Получение Unicode с помощью ASP.NET core websocket

Я пытаюсь создать сервер веб-сокета с использованием промежуточного программного обеспечения веб-сокета ASP.NET core 1.1, которое может обрабатывать текстовые сообщения. Моя стратегия - использовать буфер фиксированного размера для продолжения чтения и декодирования до тех пор, пока сообщение веб-сокета не закончится. Настройка промежуточного программного обеспечения выглядит следующим образом:

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);

В чем может быть причина этой ошибки?


person Community    schedule 06.01.2017    source источник
comment
Странно, это не похоже на связь, эта ошибка просто говорит о том, что клиент отключился. Что-то не так с вашим клиентом?   -  person Tratcher    schedule 06.01.2017
comment
@Tratcher Я так не думаю. Он отлично работает для текстов ASCII и Unicode с размером меньше, чем размер буфера (32 в данном случае)   -  person    schedule 07.01.2017


Ответы (1)


Я думаю, что это:

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

Помните, что объект Decoder сохраняет состояние между вызовами GetChars. Когда приложение завершает работу с потоком данных, оно должно установить для параметра flush значение true, чтобы убедиться, что информация о состоянии сброшена. С этой настройкой декодер игнорирует недопустимые байты в конце блока данных и очищает внутренний буфер.

.

person vtortola    schedule 07.01.2017