重新想象 Windows 8 Store Apps 之 通信: Socket - 与 WebSocket 服务端做 Text 通信, Socket - 与 WebSocket 服务端做 Stream(Binary) 通信


​[源码下载]​



重新想象 Windows 8 Store Apps (63) - 通信: WebSocket


作者:​​webabcd​



介绍

重新想象 Windows 8 Store Apps 之 通信


  • Socket - 与 WebSocket 服务端做 Text 通信
  • Socket - 与 WebSocket 服务端做 Stream(Binary) 通信


示例

WebSocket 的服务端

WebServer/WebSocketServer.ashx.cs


/*  * WebSocket 协议的服务端  *   * 需要在 iis 启用 WebSocket 协议:控制面板 -> 程序和功能 -> 启用或关闭 Windows 功能 -> 开启 iis 的 WebSocket 协议  */  using System; using System.IO; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Web;  namespace WebServer {     public class WebSocketServer : IHttpHandler     {         // 接收数据的缓冲区的最大大小         private int _maxBufferSize = 64 * 1024;          public void ProcessRequest(HttpContext context)         {             try             {                 // HttpContext.AcceptWebSocketRequest() - 接受一个 WebSocket 请求                 context.AcceptWebSocketRequest(async wsContext => // AspNetWebSocketContext                 {                     try                     {                         byte[] receiveBuffer = new byte[_maxBufferSize];                         ArraySegment<byte> buffer = new ArraySegment<byte>(receiveBuffer);                          // AspNetWebSocketContext.WebSocket - 获取当前上下文的 WebSocket 对象                         WebSocket socket = wsContext.WebSocket;                          // HTTP 握手完成                         if (socket.State == WebSocketState.Open)                         {                             var outputString = "WebSocket Connected: " + DateTime.Now.ToString("mm:ss");                             ArraySegment<byte> outputBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(outputString));                              // WebSocket.SendAsync() - 发送数据                             //     WebSocketMessageType.Text - 发送的是文本数据                             //     WebSocketMessageType.Binary - 发送的是二进制数据                             await socket.SendAsync(outputBuffer, WebSocketMessageType.Text, true, CancellationToken.None);                         }                          // HTTP 握手完成                         while (socket.State == WebSocketState.Open)                         {                             // WebSocket.ReceiveAsync() - 接收数据,返回 WebSocketReceiveResult 对象                             WebSocketReceiveResult receiveResult = await socket.ReceiveAsync(buffer, CancellationToken.None);                              // WebSocketReceiveResult.MessageType - 接收到的数据的类型(WebSocketMessageType 枚举)                             //     WebSocketMessageType.Text - 收到的是文本数据                             //     WebSocketMessageType.Binary - 收到的是二进制数据                             //     WebSocketMessageType.Close - 收到的是来自客户端的 WebSocket 关闭的消息                             if (receiveResult.MessageType == WebSocketMessageType.Close)                             {                                 // WebSocket.CloseAsync() - 关闭 WebSocket                                 await socket.CloseAsync(                                     receiveResult.CloseStatus.GetValueOrDefault(),                                     receiveResult.CloseStatusDescription,                                     CancellationToken.None);                                  return;                             }                               int offset = receiveResult.Count;                              // WebSocketReceiveResult.EndOfMessage - 消息是否被完全接收                             while (receiveResult.EndOfMessage == false)                             {                                 // WebSocket.ReceiveAsync() - 接收数据,返回 WebSocketReceiveResult 对象                                 receiveResult = await socket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer, offset, _maxBufferSize - offset), CancellationToken.None);                                 offset += receiveResult.Count;                             }                              // 收到文本数据                             if (receiveResult.MessageType == WebSocketMessageType.Text)                             {                                 string receivedText = Encoding.UTF8.GetString(receiveBuffer, 0, offset);                                 string sendText = "server to client: \"" + receivedText + "\"";                                  // 发送文本数据到客户端                                 ArraySegment<byte> outputBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(sendText));                                 await socket.SendAsync(outputBuffer, WebSocketMessageType.Text, true, CancellationToken.None);                             }                             // 收到二进制数据                             else if (receiveResult.MessageType == WebSocketMessageType.Binary)                             {                                 string sendText = "server to client: binary message received, size: " + receiveResult.Count + " bytes";                                  // 发送文本数据到客户端                                 ArraySegment<byte> outputBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(sendText));                                 await socket.SendAsync(outputBuffer, WebSocketMessageType.Text, true, CancellationToken.None);                             }                         }                     }                     catch (Exception ex)                     {                                              }                 });             }             catch (Exception ex)             {                              }         }          public bool IsReusable         {             get             {                 return false;             }         }     } }


1、演示如何通过 MessageWebSocket 与 WebSocket 服务端做 Text 通信

Communication/Socket/MessageWebSocketDemo.xaml


<Page     x:Class="XamlDemo.Communication.Socket.MessageWebSocketDemo"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:local="using:XamlDemo.Communication.Socket"     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     mc:Ignorable="d">      <Grid Background="Transparent">         <StackPanel Margin="120 0 0 0" Orientation="Horizontal">              <StackPanel>                 <Button Name="btnTextDemo" Content="与 WebSocket 服务端做 Text 通信" Click="btnTextDemo_Click" />                 <Button Name="btnClose" Content="Close" Click="btnClose_Click" Margin="0 10 0 0" />             </StackPanel>              <TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap" Margin="20 0 0 0" />          </StackPanel>     </Grid> </Page>


Communication/Socket/MessageWebSocketDemo.xaml.cs


/*  * 演示如何通过 MessageWebSocket 与 WebSocket 服务端做 Text 通信  *   * 注:需要在 Package.appxmanifest 中增加配置 <Capability Name="privateNetworkClientServer" /> 和 <Capability Name="internetClient" />  */  using System; using Windows.Networking.Sockets; using Windows.Storage.Streams; using Windows.UI.Core; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.Web;  namespace XamlDemo.Communication.Socket {     public sealed partial class MessageWebSocketDemo : Page     {         // WebSocket 协议的服务端地址(服务端代码参见:WebServer/WebSocketServer.cs)         private Uri _serverUri = new Uri("ws://localhost:86/WebSocketServer.ashx");          // MessageWebSocket - 用于与 WebSocket 服务端做 Message 通信(可以是 utf8 或 binary)         private MessageWebSocket _socket;          // 用于发送数据         DataWriter _dataWriter;          public MessageWebSocketDemo()         {             this.InitializeComponent();         }          private async void btnTextDemo_Click(object sender, RoutedEventArgs e)         {             try             {                 if (_socket == null)                 {                     lblMsg.Text += "connecting to: " + _serverUri.ToString();                     lblMsg.Text += Environment.NewLine;                      _socket = new MessageWebSocket();                     // 发送的消息的类型 Utf8 或 Binary                     _socket.Control.MessageType = SocketMessageType.Utf8;                     // 接收到消息时所触发的事件                     _socket.MessageReceived += _socket_MessageReceived;                      // WebSocket 关闭时所触发的事件                     _socket.Closed += async (senderSocket, args) =>                     {                         await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>                         {                             // WebSocketClosedEventArgs.Code - 关闭原因的状态吗                             // WebSocketClosedEventArgs.Reason - 关闭原因的详细信息                             lblMsg.Text += "socket closed - code: " + args.Code + ", reason: " + args.Reason;                             lblMsg.Text += Environment.NewLine;                              if (_socket != null)                             {                                 _socket.Dispose();                                 _socket = null;                             }                         });                     };                      // 连接指定的 WebSocket 服务                     await _socket.ConnectAsync(_serverUri);                     // 根据 MessageWebSocket 的 OutputStream,实例化一个 DataWriter,以便发数据到服务端                     _dataWriter = new DataWriter(_socket.OutputStream);                      lblMsg.Text += "connected";                     lblMsg.Text += Environment.NewLine;                 }                  string message = "hello " + DateTime.Now.ToString("hh:mm:ss");                 lblMsg.Text += "send: " + message;                 lblMsg.Text += Environment.NewLine;                  // 发送数据到服务端                 _dataWriter.WriteString(message);                 await _dataWriter.StoreAsync();                  lblMsg.Text += "sent";                 lblMsg.Text += Environment.NewLine;             }             catch (Exception ex)              {                 if (_socket != null)                 {                     _socket.Dispose();                     _socket = null;                 }                  WebErrorStatus errStatus = WebSocketError.GetStatus(ex.GetBaseException().HResult);                  lblMsg.Text += "errStatus: " + errStatus.ToString();                 lblMsg.Text += Environment.NewLine;                 lblMsg.Text += ex.ToString();                 lblMsg.Text += Environment.NewLine;             }         }          void _socket_MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)         {             try             {                 // MessageWebSocketMessageReceivedEventArgs.MessageType - 收到的数据的类型 Utf8 或 Binary                 // MessageWebSocketMessageReceivedEventArgs.GetDataReader() - 获取收到的数据的 DataReader 对象,用于读取接收到的数据                 using (DataReader reader = args.GetDataReader())                 {                     reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;                     string read = reader.ReadString(reader.UnconsumedBufferLength);                      var ignore = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>                     {                         lblMsg.Text += "received: " + read;                         lblMsg.Text += Environment.NewLine;                     });                 }             }             catch (Exception ex)             {                 WebErrorStatus errStatus = WebSocketError.GetStatus(ex.GetBaseException().HResult);                  lblMsg.Text += "errStatus: " + errStatus.ToString();                 lblMsg.Text += Environment.NewLine;                 lblMsg.Text += ex.ToString();                 lblMsg.Text += Environment.NewLine;             }         }          private void btnClose_Click(object sender, RoutedEventArgs e)         {             try             {                 if (_socket != null)                 {                     lblMsg.Text += "socket closing";                     lblMsg.Text += Environment.NewLine;                      // 关闭 WebSocket,可以指定 code 和 reason(此处指定的 code 和 reason 可以在 MessageWebSocket.Closed 事件中获取)                     _socket.Close(8888, "用户在客户端关闭了 WebSocket");                     _socket = null;                 }             }             catch (Exception ex)             {                 WebErrorStatus errStatus = WebSocketError.GetStatus(ex.GetBaseException().HResult);                  lblMsg.Text += "errStatus: " + errStatus.ToString();                 lblMsg.Text += Environment.NewLine;                 lblMsg.Text += ex.ToString();                 lblMsg.Text += Environment.NewLine;             }         }     } }


2、演示如何通过 StreamWebSocket 与 WebSocket 服务端做 Stream(Binary) 通信

Communication/Socket/StreamWebSocketDemo.xaml


<Page     x:Class="XamlDemo.Communication.Socket.StreamWebSocketDemo"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:local="using:XamlDemo.Communication.Socket"     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     mc:Ignorable="d">      <Grid Background="Transparent">         <StackPanel Margin="120 0 0 0" Orientation="Horizontal">              <StackPanel>                 <Button Name="btnBinaryDemo" Content="与 WebSocket 服务端做 Binary 通信" Click="btnBinaryDemo_Click" />                 <Button Name="btnClose" Content="Close" Click="btnClose_Click" Margin="0 10 0 0" />             </StackPanel>              <TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap" Margin="20 0 0 0" />          </StackPanel>     </Grid> </Page>


Communication/Socket/StreamWebSocketDemo.xaml.cs


/*  * 演示如何通过 StreamWebSocket 与 WebSocket 服务端做 Stream(Binary) 通信  *   * 注:需要在 Package.appxmanifest 中增加配置 <Capability Name="privateNetworkClientServer" /> 和 <Capability Name="internetClient" />  */  using System; using Windows.Networking.Sockets; using Windows.Storage.Streams; using Windows.UI.Core; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.Web; using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; using System.IO;  namespace XamlDemo.Communication.Socket {     public sealed partial class StreamWebSocketDemo : Page     {         // WebSocket 协议的服务端地址(服务端代码参见:WebServer/WebSocketServer.cs)         private Uri _serverUri = new Uri("ws://localhost:86/WebSocketServer.ashx");          // StreamWebSocket - 用于与 WebSocket 服务端做 Stream 通信(只能是 binary)         private StreamWebSocket _socket;          public StreamWebSocketDemo()         {             this.InitializeComponent();         }          private async void btnBinaryDemo_Click(object sender, RoutedEventArgs e)         {             try             {                 if (_socket == null)                 {                     lblMsg.Text += "connecting to: " + _serverUri.ToString();                     lblMsg.Text += Environment.NewLine;                      _socket = new StreamWebSocket();                      // WebSocket 关闭时所触发的事件                     _socket.Closed += async (senderSocket, args) =>                     {                         await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>                         {                             // WebSocketClosedEventArgs.Code - 关闭原因的状态吗                             // WebSocketClosedEventArgs.Reason - 关闭原因的详细信息                             lblMsg.Text += "socket closed - code: " + args.Code + ", reason: " + args.Reason;                             lblMsg.Text += Environment.NewLine;                              if (_socket != null)                             {                                 _socket.Dispose();                                 _socket = null;                             }                         });                     };                      // 连接指定的 WebSocket 服务                     await _socket.ConnectAsync(_serverUri);                      // 新开线程,用于接收数据                     Task receiving = Task.Factory.StartNew(ReceiveData, _socket.InputStream.AsStreamForRead(), TaskCreationOptions.LongRunning);                      // 新开线程,用于发送数据                     Task sending = Task.Factory.StartNew(SendData, _socket.OutputStream, TaskCreationOptions.LongRunning);                      lblMsg.Text += "connected";                     lblMsg.Text += Environment.NewLine;                 }             }             catch (Exception ex)             {                 if (_socket != null)                 {                     _socket.Dispose();                     _socket = null;                 }                  WebErrorStatus errStatus = WebSocketError.GetStatus(ex.GetBaseException().HResult);                  lblMsg.Text += "errStatus: " + errStatus.ToString();                 lblMsg.Text += Environment.NewLine;                 lblMsg.Text += ex.ToString();                 lblMsg.Text += Environment.NewLine;             }         }          // 发送数据         private async void SendData(object state)         {             // 自定义需要发送的二进制数据             byte[] data = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 };              try             {                 IOutputStream writeStream = (IOutputStream)state;                  while (true)                 {                     var ignore = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>                     {                         lblMsg.Text += "send: " + data.Length.ToString() + " 字节的数据";                         lblMsg.Text += Environment.NewLine;                     });                      // 发送 stream 数据                     await writeStream.WriteAsync(data.AsBuffer());                      var ignore2 = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>                     {                         lblMsg.Text += "sent";                         lblMsg.Text += Environment.NewLine;                     });                      await Task.Delay(TimeSpan.FromSeconds(3));                 }             }             catch (ObjectDisposedException)             {                 var ignore = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>                 {                     lblMsg.Text += "用于发送数据的后台线程已经停止";                     lblMsg.Text += Environment.NewLine;                 });             }             catch (Exception ex)             {                 WebErrorStatus errStatus = WebSocketError.GetStatus(ex.GetBaseException().HResult);                  var ignore = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>                 {                     lblMsg.Text += "errStatus: " + errStatus.ToString();                     lblMsg.Text += Environment.NewLine;                     lblMsg.Text += ex.ToString();                     lblMsg.Text += Environment.NewLine;                 });             }         }          // 接收数据         private async void ReceiveData(object state)         {             // 用于接收数据的缓冲区             byte[] readBuffer = new byte[1024];              int bytesReceived = 0;             try             {                 Stream readStream = (Stream)state;                  while (true)                 {                     // 接收数据                     int read = await readStream.ReadAsync(readBuffer, 0, readBuffer.Length);                     bytesReceived += read;                      await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>                     {                         lblMsg.Text += "received: " + System.Text.Encoding.UTF8.GetString(readBuffer, 0, read);                         lblMsg.Text += Environment.NewLine;                         lblMsg.Text += "累计已收到 " + bytesReceived.ToString() + " 字节的数据";                         lblMsg.Text += Environment.NewLine;                     });                 }             }             catch (ObjectDisposedException)             {                 var ignore = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>                 {                     lblMsg.Text += "用于接收数据的后台线程已经停止";                     lblMsg.Text += Environment.NewLine;                 });             }             catch (Exception ex)             {                 WebErrorStatus errStatus = WebSocketError.GetStatus(ex.GetBaseException().HResult);                  var ignore = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>                 {                     lblMsg.Text += "errStatus: " + errStatus.ToString();                     lblMsg.Text += Environment.NewLine;                     lblMsg.Text += ex.ToString();                     lblMsg.Text += Environment.NewLine;                 });             }         }          private void btnClose_Click(object sender, RoutedEventArgs e)         {             try             {                 if (_socket != null)                 {                     lblMsg.Text += "socket closing";                     lblMsg.Text += Environment.NewLine;                      // 关闭 WebSocket,可以指定 code 和 reason(此处指定的 code 和 reason 可以在 MessageWebSocket.Closed 事件中获取)                     _socket.Close(8888, "用户在客户端关闭了 WebSocket");                     _socket = null;                 }             }             catch (Exception ex)             {                 WebErrorStatus errStatus = WebSocketError.GetStatus(ex.GetBaseException().HResult);                  lblMsg.Text += "errStatus: " + errStatus.ToString();                 lblMsg.Text += Environment.NewLine;                 lblMsg.Text += ex.ToString();                 lblMsg.Text += Environment.NewLine;             }         }     } }



OK

​[源码下载]​