0

我正在尝试使用可以处理文本消息的 ASP.NET core 1.1 websocket 中间件构建一个 websocket 服务器。我的策略是使用固定大小的缓冲区来继续读取和解码,直到 websocket 消息结束。中间件设置如下:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        var logger = loggerFactory.CreateLogger("websocket");

        app.UseWebSockets();

        app.Use(async (http, next) =>
        {
            if (!http.WebSockets.IsWebSocketRequest)
            {
                await next();
                return;
            }

            var websocket = await http.WebSockets.AcceptWebSocketAsync();

            while (websocket.State == WebSocketState.Open)
            {
                var buffer = new ArraySegment<byte>(new byte[32]);
                var charbuffer = new char[32];
                try
                {
                    var sb = new StringBuilder();
                    var decoder = Encoding.UTF8.GetDecoder();

                    //aha, we got a message
                    var detectResult = await websocket.ReceiveAsync(buffer, CancellationToken.None);
                    var receiveResult = detectResult;

                    while (!receiveResult.EndOfMessage)
                    {
                        var charLen = decoder.GetChars(buffer.Array, 0, receiveResult.Count, charbuffer, 0);
                        logger.LogInformation($"Decoded {charLen} byte(s) from wire");
                        sb.Append(charbuffer, 0, charLen);
                        receiveResult = await websocket.ReceiveAsync(buffer, CancellationToken.None);
                    }
                    var charLenFinal = decoder.GetChars(buffer.Array, 0, receiveResult.Count, charbuffer, 0);
                    logger.LogInformation($"Decoded {charLenFinal} byte(s) from wire");
                    sb.Append(charbuffer, 0, charLenFinal);

                    var message = sb.ToString();
                    logger.LogInformation($"decoded message: {message}");
                    await websocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes("got it")), WebSocketMessageType.Text, true, CancellationToken.None);
                }
                catch (Exception ex)
                {
                    logger.LogError(ex.Message);
                    logger.LogError(ex.InnerException?.Message ?? string.Empty);
                }
            }
        });
    }

现在该代码适用于仅包含 ASCII 字符的文本。但是当我尝试发送长度大于缓冲区大小的 Unicode 文本消息(越南语)时,出现异常

fail: websocket[0]
  The remote party closed the WebSocket connection without completing the close handshake.
fail: websocket[0]
     at System.Net.WebSockets.ManagedWebSocket.<ReceiveAsyncPrivate>d__60.MoveNext()
  --- End of stack trace from previous location where exception was thrown ---
     at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
     at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
     at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
     at MvcApp.Startup.<>c__DisplayClass5_0.<<Configure>b__0>d.MoveNext()

异常发生在该行

var detectResult = await websocket.ReceiveAsync(buffer, CancellationToken.None);

此错误的原因可能是什么?

4

1 回答 1

0

我认为这:

var charLenFinal = decoder.GetChars(buffer.Array, 0, receiveResult.Count, charbuffer, 0);

应该:

var charLenFinal = decoder.GetChars(buffer.Array, 0, receiveResult.Count, charbuffer, 0, true);

自从:

https://msdn.microsoft.com/en-us/library/125z2etb(v=vs.110).aspx

请记住,解码器对象在调用 GetChars 之间保存状态。当应用程序处理完数据流后,应将 flush 参数设置为 true 以确保刷新状态信息。使用此设置,解码器会忽略数据块末尾的无效字节并清除内部缓冲区

.

于 2017-01-07T15:56:37.640 回答