Магазин Windows (UWP)/.NET Core/веб-сокеты DNX не могут передавать данные

В настоящее время я работаю над созданием соединения WebSocket между ASP.NET 5 (DNX), основной консолью DNX и приложением универсальной платформы Windows (Windows Store).

ASP.NET 5 служит сервером с использованием пакета «Microsoft.AspNet.WebSockets.Server»: «1.0.0-rc1-final». И консольное приложение, и приложение UWP используют «System.Net.WebSockets.Client»: «4.0.0-beta-23516» в качестве сервера веб-сокетов.

Метод настройки сервера использовал следующее для настройки очень простого сервера WebSocket:

        app.UseWebSockets();

        app.Use( async ( Context, Next ) =>
        {
            var HttpContext = ( HttpContext )Context;

            if( HttpContext.WebSockets.IsWebSocketRequest )
            {
                WebSocket Socket = await HttpContext.WebSockets.AcceptWebSocketAsync();
                await Task.Delay( 100 );

                CancellationTokenSource Cts = new CancellationTokenSource();
                CancellationToken Ct = Cts.Token;

                System.Diagnostics.Debug.WriteLine( "New client; sending data..." );
                byte[] Data = System.Text.Encoding.UTF8.GetBytes( "Hello WebSocket!" );
                await Socket.SendAsync( new ArraySegment<byte>( Data ), WebSocketMessageType.Binary, false, Ct );
                System.Diagnostics.Debug.WriteLine( "Data sent." );

                //System.Diagnostics.Debug.WriteLine( "New client; receiving data..." );
                //byte[] Data = new byte[ 16 ];
                //var Result = await Socket.ReceiveAsync( new ArraySegment<byte>( Data ), Ct );
                //System.Diagnostics.Debug.WriteLine( $"Data received: {Result.Count}" );
            }
        } );

Оба клиента (консоль и приложение UWP) используют следующий код для подключения к серверу:

            CancellationTokenSource Cts = new CancellationTokenSource();
            CancellationToken Ct = Cts.Token;

            string Address = "ws://localhost:5000";

            var Socket = new System.Net.WebSockets.ClientWebSocket();

            Console.WriteLine( $"Creating connection to: {Address}" );
            await Socket.ConnectAsync( new Uri( Address ), Ct );
            Task.Delay( 100 ).Wait();

            byte[] Data = new byte[ 1024 ];
            Console.WriteLine( "Receiving data..." );
            var Result = await Socket.ReceiveAsync( new ArraySegment<byte>( Data ), Ct );
            Console.WriteLine( $"Data received: {Result.Count}" );

            //Console.WriteLine( "Sending data..." );
            //byte[] Data = System.Text.Encoding.UTF8.GetBytes( "Hello WebSocket!" );
            //Socket.SendAsync( new ArraySegment<byte>( Data ), WebSocketMessageType.Binary, false, Ct ).Wait();
            //Console.WriteLine( "Data sent." );

(Конечно, приложение UWP не использует Console.WriteLine, а записывает в текстовый блок. При запуске сервера и консольного приложения связь работает (данные отправляются и принимаются). Однако при запуске приложения UWP соединение устанавливается но данные НЕ получены Я пробовал наоборот (таким образом, закомментированные строки), и в этом случае приложение UWP отправляет данные, но сервер НЕ получает их...

Это ошибка в одной из реализаций или я что-то не так делаю? Я уже пытался развернуть сервер на другой машине и проверил свои исключения обратной связи - с тем же результатом. При использовании MVC в серверном приложении HttpClient МОЖЕТ получать данные из приложения UWP, проблема только с WebSockets.

Примечание. Я хочу повторно использовать System.Net.WebSockets.Client, поскольку я собираюсь поместить все в общую библиотеку.

У меня есть работающее минимальное решение для воспроизведения проблемы в OneDrive: https://onedrive.live.com/redir?resid=1DDFA1793BD83CB5!270551&authkey=!AFtXc_Xae2qnpF8&ithint=file%2czip

Помощь приветствуется; заранее спасибо!


person Simon Mattes    schedule 27.11.2015    source источник


Ответы (1)


В System.Net.WebSockets.Client используются разные WebSocketHandle для разных платформ. См. исходный код в GitHub и в WebSocketHandle.WinRT.cs вы можете обнаружить, что его _webSocket определяется как WinRTWebSocket. В WinRTWebSocket, он использует MessageWebSocket для установления соединения и получения данных. MessageWebSocket — это класс WebSocket. мы обычно использовали в приложениях UWP. MessageWebSocket использует событие MessageReceived для обработки полученного сообщения. Это событие уведомляет пользователей о любом входящем сообщении. Но это событие вызывается, когда все сообщение получено конечной точкой (не для частичных фрагментов).

Поэтому, когда вы отправляете данные с параметром endOfMessage в методе WebSocket.SendAsync в false, событие MessageReceived не будет вызываться, поскольку сообщение не завершено. Вы можете создать проект UWP, используя MessageWebSocket для его тестирования (вы можете обратиться к пример WebSocket в GitHub). И это заставляет метод Socket.ReceiveAsync всегда ждать, и вы чувствуете, что никакие данные не получены.

Чтобы решить эту проблему, вам нужно установить параметр endOfMessage в методе WebSocket.SendAsync на true, когда сообщение закончится. Например, на вашем сервере используйте следующий код:

await Socket.SendAsync(new ArraySegment<byte>(Data), WebSocketMessageType.Binary, false, Ct);
await Task.Delay(1000);
await Socket.SendAsync(new ArraySegment<byte>(Data), WebSocketMessageType.Binary, true, Ct);

Тогда в вашем клиенте вы получите Hello WebSocket!Hello WebSocket!.

person Jay Zuo    schedule 02.12.2015