Windows Store (UWP) / .NET Core / DNX WebSockets 无法传输数据

Windows Store (UWP) / .NET Core / DNX WebSockets unable to transfer data

我目前正在研究一种在 ASP.NET 5 (DNX)、DNX 核心控制台和通用 Windows 平台(Windows 商店)应用程序之间创建 WebSocket 连接的方法.

ASP.NET 5 作为服务器使用包 "Microsoft.AspNet.WebSockets.Server": "1.0.0-rc1-final"。 控制台应用程序和 UWP 应用程序都使用 "System.Net.WebSockets.Client": "4.0.0-beta-23516" 作为 websocket 服务器。

服务器配置方法使用以下方法设置了一个非常简单的 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

非常感谢您的帮助;提前致谢!

System.Net.WebSockets.Client中,针对不同的平台使用不同的WebSocketHandle。查看源码GitHub and in WebSocketHandle.WinRT.cs, you can find its _webSocket is defined as WinRTWebSocket. In WinRTWebSocket, it uses MessageWebSocket to establish connection and receive data. MessageWebSocket就是我们在UWP应用中常用的WebSocketclass。 MessageWebSocket 使用 MessageReceived 事件来处理收到的消息。此事件通知用户任何传入消息。但是当端点接收到整个消息时调用此事件(不是部分片段)。

因此,当您在 WebSocket.SendAsync 方法中使用 endOfMessage 参数向 false 发送数据时,MessageReceived 事件不会被调用,因为消息不完整。您可以使用 MessageWebSocket 构建一个 UWP 项目来测试它(您可以参考 WebSocket sample in GitHub)。这使得 Socket.ReceiveAsync 方法总是等待,你感觉没有收到数据。

要解决此问题,需要在消息结束时将WebSocket.SendAsync方法中的endOfMessage参数设置为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!.