在将所有websocket数据发送到客户端之前,ASP.NET关闭连接

前端之家收集整理的这篇文章主要介绍了在将所有websocket数据发送到客户端之前,ASP.NET关闭连接前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我写了一个简单的asp.net websocket处理程序作为远程数据处理服务器和客户端之间的网关.
我在我的本地机器(win8,IIS EXPRESS 8)中测试过,一切运行良好.但是在azure网站上,ASP.NET在将所有websocket数据发送到客户端之前关闭了连接.

以下是我的数据传输代码

internal class WebSocketStreamTransfer{

    public WebSocketStreamTransfer(CancellationToken disconnectionToken){
        DisconnectionToken = disconnectionToken;
    }

    private CancellationToken DisconnectionToken{
        get;
        set;
    }

    public async Task AcceptWebSocketConnection(WebSocketContext context) {
        if (context == null)
            throw new ArgumentNullException("context");
        WebSocket websocket = context.WebSocket;
        if (websocket == null)
            throw new SocksOverHttpException("Null websocket");
        using(IConnection conn = ConnectionManagerFactory.ConnectionManager.CreateConnection(Guid.NewGuid().ToString())) {
            try {
                DisconnectionToken.Register(conn.Close);
                TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(null);
                await Task.WhenAny(SendDataToRemoteServer(conn,websocket,DisconnectionToken,tcs),SendDataToClient(conn,tcs.Task));
            } catch(Exception e) {
                Logger.LogException(e);
            }
        }
    }

    internal static async Task SendDataToRemoteServer(IConnection conn,WebSocket websocket,CancellationToken cancelToken,TaskCompletionSource<bool> tcs) {
        try {
            ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[ApplicationConfiguration.GetDefaultBufferSize()]);
            while (IsConnected(conn,cancelToken,websocket)) {
                WebSocketReceiveResult result = await websocket.ReceiveAsync(buffer,cancelToken);
                if (websocket.State == WebSocketState.Open) {
                    if (result.MessageType == WebSocketMessageType.Binary) {
                        if (result.Count > 0) {
                            if (IsConnected(conn,websocket)) {
                                int numRead = await conn.SendData(buffer.Array,result.Count,cancelToken);
                                if (numRead > 0) {
                                    tcs.TrySetResult(true); // Notify SendDataToClient can continue
                                }else{
                                    Logger.LogError("Client not send enough data for remote connection built");
                                    return;
                                }
                            } else {
                                Logger.LogInformation("SendDataToRemoteServer: Cancel send data to remote server due to connection closed");
                            }
                        } else
                            Logger.LogInformation("Receive empty binary message");
                    } else if (result.MessageType == WebSocketMessageType.Text) {
                        Logger.LogError("Receive unexpected text message");
                        return;
                    } else {
                        Logger.LogInformation("Receive close message");
                        await websocket.CloseAsync(WebSocketCloseStatus.NormalClosure,"Close Connection",cancelToken);
                        return;
                    }
                } else {
                    Logger.LogInformation("SendDataToRemoteServer: WebSocket connection closed by client");
                    return;
                }
            }
        }finally{
            tcs.TrySetResult(true);
        }
    }

    internal static async Task SendDataToClient(IConnection conn,Task connectedTask) {
        await connectedTask;
        while (IsConnected(conn,websocket)) {
            byte[] data = await conn.ReceiveData(cancelToken);
            if (data.Length <= 0) {
                Logger.LogInformation("SendDataToClient: Get empty data from remote server");
                return;
            }
            if (IsConnected(conn,websocket)) {
                await websocket.SendAsync(new ArraySegment<byte>(data),WebSocketMessageType.Binary,true,cancelToken);
            } else {
                Logger.LogInformation("SendDataToClient: Cancel send data to client due to connection closed");
            }
        }
    }

    internal static bool IsConnected(IConnection conn,WebSocket websocket) {
        bool socketConnected = websocket.State == WebSocketState.Open;
        return socketConnected && conn.Connected && !cancelToken.IsCancellationRequested;
    }
}

问题场景:

> SendDataToRemoteServer等待客户端数据,客户端尚未发送数据
> SendDataToClient从远程服务器接收空数据,表示远程服务器开始关闭连接.所以完成SendDataToClient
> AcceptWebSocketConnection完成因为Task.WhenAny(SendDataToRemoteServer(conn,tcs.Task))
>期望ASP.NET在关闭tcp连接之前发送所有数据,但ASP.NET立即关闭连接(azure).

解决方法

WebSocket消息可以分成不同的帧.您没有检查消息是否已完成.从与其他WS连接发送信息的代码应如下所示:
WebSocketReceiveResult result = null;
do
{
    result = await source.ReceiveAsync(buffer,CancellationToken.None);
    var sendBuffer = new ArraySegment<Byte>(buffer.Array,buffer.Offset,result.Count);

    await target.SendAsync(sendBuffer,result.MessageType,result.EndOfMessage,CancellationToken.None);
}
while (!result.EndOfMessage);

您必须检查EndOfMessage属性,并在消息未完成时继续读取.

它适用于您的本地计算机,因为本地您不会以相同的方式受到缓冲的影响,或者因为您尝试的消息较小.

猜你在找的asp.Net相关文章