Windows应用商店(UWP)/ .NET Core / DNX WebSockets无法传输数据

时间:2015-11-27 17:43:18

标签: c# asp.net websocket uwp dnx

我目前正致力于在ASP.NET 5(DNX),DNX Core Console和通用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 CAN会从UWP应用程序中接收数据,只是WebSockets似乎有问题。

注意:我想重新使用System.Net.WebSockets.Client,因为我要将所有内容都放在共享库中。

我有一个可行的最小解决方案,可以在我的OneDrive上重现这个问题:https://onedrive.live.com/redir?resid=1DDFA1793BD83CB5!270551&authkey=!AFtXc_Xae2qnpF8&ithint=file%2czip

非常感谢帮助;提前谢谢!

1 个答案:

答案 0 :(得分:1)

System.Net.WebSockets.Client中,它为不同的平台使用不同的WebSocketHandle。查看GitHubWebSocketHandle.WinRT.cs中的源代码,您可以发现其_webSocket定义为WinRTWebSocket。在WinRTWebSocket中,它使用MessageWebSocket建立连接并接收数据。 MessageWebSocket是我们通常在UWP应用程序中使用的WebSocket类。 MessageWebSocket使用MessageReceived事件来处理收到的消息。此事件通知用户任何传入的消息。但是,当端点收到整个消息时,将调用此事件(而不是部分片段)。

因此,当您使用endOfMessage方法将WebSocket.SendAsync参数发送到false时,MessageReceived事件将被调用,因为消息未完成。您可以使用MessageWebSocket构建一个UWP项目来测试它(您可以参考WebSocket sample in 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!