29、WebSocket

       本篇讲述通过 MessageWebSocket 通信,服务器端是 aspx 的网站。MessageWebSocket 和 Socket 大同小异。

附上位于  Windows.Networking.Sockets 命名空间下的 MessageWebSocket 类的定义 :

View Code
    // 摘要:
    //     支持允许使用 WebSocket 的读取和写入整个消息的网络通信。
   [Activatable(100794368)]
    [DualApiPartition(version = 100794368)]
    [MarshalingBehavior(MarshalingType.Agile)]
    [Threading(ThreadingModel.Both)]
    [Version(100794368)]
    public sealed class MessageWebSocket : IWebSocket, IDisposable
    {
        // 摘要:
        //     创建新的 MessageWebSocket 对象。
        public MessageWebSocket();

        // 摘要:
        //     获取 MessageWebSocket 对象上的套接字控件数据。
        //
        // 返回结果:
        //     某一 MessageWebSocket 对象上的套接字控件数据。
        public MessageWebSocketControl Control { get; }
        //
        // 摘要:
        //     获取 MessageWebSocket 对象上的套接字信息。
        //
        // 返回结果:
        //     该 MessageWebSocket 对象的套接字信息。
        public MessageWebSocketInformation Information { get; }
        //
        // 摘要:
        //     获取 MessageWebSocket 对象上写入远程网络目标的输出流。
        //
        // 返回结果:
        //     要作为单一消息写入远程目标的有序字节流。
        public IOutputStream OutputStream { get; }

        // 摘要:
        //     当 MessageWebSocket 对象作为关闭握手的一部分收到结束帧时发生。
        public event TypedEventHandler<IWebSocket, WebSocketClosedEventArgs> Closed;
        //
        // 摘要:
        //     指示在 MessageWebSocket 对象上收到消息的事件。
        public event TypedEventHandler<MessageWebSocket, MessageWebSocketMessageReceivedEventArgs> MessageReceived;

        // 摘要:
        //     关闭 MessageWebSocket 对象并指示关闭的原因。
        //
        // 参数:
        //   code:
        //     指示关闭原因的状态代码。
        //
        //   reason:
        //     包含有关关闭的其他信息的可选 UTF-8 编码数据。
        [Overload("CloseWithStatus")]
        public void Close(ushort code, string reason);
        public IAsyncAction ConnectAsync(Uri uri);
        public void Dispose();
        //
        // 摘要:
        //     向由 MessageWebSocket 对象握手的 WebSocket 协议中使用的 HTTP 请求消息添加 HTTP 请求标头。
        //
        // 参数:
        //   headerName:
        //     请求标头的名称。
        //
        //   headerValue:
        //     请求标头的值。
        public void SetRequestHeader(string headerName, string headerValue);
    }

位于 namespace Windows.Networking.Sockets 命名空间下的 StreamWebSocket 类的定义:

View Code
    // 摘要:
    //     支持允许使用 WebSocket 的读取和写入流的网络通信。
    [Activatable(100794368)]
    [DualApiPartition(version = 100794368)]
    [MarshalingBehavior(MarshalingType.Agile)]
    [Threading(ThreadingModel.Both)]
    [Version(100794368)]
    public sealed class StreamWebSocket : IWebSocket, IDisposable
    {
        // 摘要:
        //     创建新的 StreamWebSocket 对象。
        public StreamWebSocket();

        // 摘要:
        //     获取 StreamWebSocket 对象上的套接字控件数据。
        //
        // 返回结果:
        //     某一 StreamWebSocket 对象上的套接字控件数据。
        public StreamWebSocketControl Control { get; }
        //
        // 摘要:
        //     获取 StreamWebSocket 对象上的套接字信息。
        //
        // 返回结果:
        //     该 StreamWebSocket 对象的套接字信息。
        public StreamWebSocketInformation Information { get; }
        //
        // 摘要:
        //     获取要从 StreamWebSocket 对象上的远程目标读取的输入流。
        //
        // 返回结果:
        //     要从远程目标读取的有序字节流。
        public IInputStream InputStream { get; }
        //
        // 摘要:
        //     获取 StreamWebSocket 对象上写入远程网络目标的输出流。
        //
        // 返回结果:
        //     要写入远程目标的有序字节流。
        public IOutputStream OutputStream { get; }

        // 摘要:
        //     当 StreamWebSocket 对象作为关闭握手的一部分收到结束帧时发生。
        public event TypedEventHandler<IWebSocket, WebSocketClosedEventArgs> Closed;

        // 摘要:
        //     关闭 StreamWebSocket 对象并指示关闭的原因。
        //
        // 参数:
        //   code:
        //     指示关闭原因的状态代码。
        //
        //   reason:
        //     包含有关关闭的其他信息的可选 UTF-8 编码数据。
        [Overload("CloseWithStatus")]
        public void Close(ushort code, string reason);
        public IAsyncAction ConnectAsync(Uri uri);
        public void Dispose();
        //
        // 摘要:
        //     向由 StreamWebSocket 对象握手的 WebSocket 协议中使用的 HTTP 请求消息添加 HTTP 请求标头。
        //
        // 参数:
        //   headerName:
        //     请求标头的名称。
        //
        //   headerValue:
        //     请求标头的值。
        public void SetRequestHeader(string headerName, string headerValue);
    }

位于 System.Net.WebSockets 命名空间下的 WebSocket 类 :

View Code
 // 摘要:
    //     The WebSocket class allows applications to send and receive data after the
    //     WebSocket upgrade has completed.
    public abstract class WebSocket : IDisposable
    {
        // 摘要:
        //     创建 System.Net.WebSockets.WebSocket 类的实例。
        protected WebSocket();

        // 摘要:
        //     Indicates the reason why the remote endpoint initiated the close handshake.
        //
        // 返回结果:
        //     返回 System.Net.WebSockets.WebSocketCloseStatus。
        public abstract WebSocketCloseStatus? CloseStatus { get; }
        //
        // 摘要:
        //     Allows the remote endpoint to describe the reason why the connection was
        //     closed.
        //
        // 返回结果:
        //     返回 System.String。
        public abstract string CloseStatusDescription { get; }
        public static TimeSpan DefaultKeepAliveInterval { get; }
        //
        // 摘要:
        //     Returns the current state of the WebSocket connection.
        //
        // 返回结果:
        //     返回 System.Net.WebSockets.WebSocketState。
        public abstract WebSocketState State { get; }
        //
        // 摘要:
        //     The subprotocol that was negotiated during the opening handshake.
        //
        // 返回结果:
        //     返回 System.String。
        public abstract string SubProtocol { get; }

        // 摘要:
        //     Aborts the WebSocket connection and cancels any pending IO operations.
        public abstract void Abort();
        //
        // 摘要:
        //     Closes the WebSocket connection using the close handshake defined in the
        //     WebSocket protocol specification section 7.
        //
        // 参数:
        //   closeStatus:
        //     Indicates the reason for closing the WebSocket connection.
        //
        //   statusDescription:
        //     Specifies a human readable explanation as to why the connection is closed.
        //
        //   cancellationToken:
        //     The token that can be used to propagate notification that operations should
        //     be canceled.
        //
        // 返回结果:
        //     返回 System.Threading.Tasks.Task。
        public abstract Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken);
        //
        // 摘要:
        //     Initiates or completes the close handshake defined in the WebSocket protocol
        //     specification section 7.
        //
        // 参数:
        //   closeStatus:
        //     Indicates the reason for closing the WebSocket connection.
        //
        //   statusDescription:
        //     Allows applications to specify a human readable explanation as to why the
        //     connection is closed.
        //
        //   cancellationToken:
        //     The token that can be used to propagate notification that operations should
        //     be canceled.
        //
        // 返回结果:
        //     返回 System.Threading.Tasks.Task。
        public abstract Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken);
        public static ArraySegment<byte> CreateClientBuffer(int receiveBufferSize, int sendBufferSize);
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static WebSocket CreateClientWebSocket(Stream innerStream, string subProtocol
                                    , int receiveBufferSize, int sendBufferSize, TimeSpan keepAliveInterval
                                    , bool useZeroMaskingKey, ArraySegment<byte> internalBuffer);

        public static ArraySegment<byte> CreateServerBuffer(int receiveBufferSize);
        //
        // 摘要:
        //     Used to clean up unmanaged resources for ASP.NET and self-hosted implementations.
        public abstract void Dispose();
        //
        // 摘要:
        //     Returns true if the state of the WebSocket instance is Closed or Aborted.
        //
        // 参数:
        //   state:
        //     The current state of the WebSocket.
        //
        // 返回结果:
        //     返回 System.Boolean。
        protected static bool IsStateTerminal(WebSocketState state);
        //
        // 摘要:
        //     Receives data from the WebSocket connection asynchronously.
        //
        // 参数:
        //   buffer:
        //     References the application buffer that is the storage location for the received
        //     data.
        //
        //   cancellationToken:
        //     Propagate the notification that operations should be canceled.
        //
        // 返回结果:
        //     返回 System.Threading.Tasks.Task<TResult>。
        public abstract Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken cancellationToken);
        //
        // 摘要:
        //     此 API 支持 .NET Framework 基础结构,但不应在代码中直接使用。Allows callers to register prefixes
        //     for WebSocket requests (ws and wss).
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static void RegisterPrefixes();
        //
        // 摘要:
        //     Sends data over the WebSocket connection asynchronously.
        //
        // 参数:
        //   buffer:
        //     The buffer to be sent over the connection.
        //
        //   messageType:
        //     Indicates whether the application is sending a binary or text message.
        //
        //   endOfMessage:
        //     Indicates whether the data in “buffer†is the last part of a message.
        //
        //   cancellationToken:
        //     The token that propagates the notification that operations should be canceled.
        //
        // 返回结果:
        //     返回 System.Threading.Tasks.Task。
        public abstract Task SendAsync(ArraySegment<byte> buffer, WebSocketMessageType messageType, bool endOfMessage
                                     , CancellationToken cancellationToken);
        //
        // 摘要:
        //     Verifies that the connection is in an expected state.
        //
        // 参数:
        //   state:
        //     The current state of the WebSocket to be tested against the list of valid
        //     states.
        //
        //   validStates:
        //     List of valid connection states.
        protected static void ThrowOnInvalidState(WebSocketState state, params WebSocketState[] validStates);
    }

    在下面的 1、和 2、 中的响应客户端的请求的 EchoWebSocket.ashx 文件 :

using System;
using System.Web;
using System.Net.WebSockets;
using System.Web.WebSockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

public class EchoWebSocket : IHttpHandler {
    private const int MaxBufferSize = 64 * 1024;

    public void ProcessRequest (HttpContext context)
    {
        try
        {

         //AcceptWebSocketRequest(Func<AspNetWebSocketContext, System.Threading.Tasks.Task> userFunc); 方法
         //用一个指定的方法,接收一个 System.Web.WebSockets.AspNetWebSocket 请求。这个
         //请求不是一个 System.Web.WebSockets.AspNetWebSocket 请求。
            context.AcceptWebSocketRequest(async wsContext =>
            {
                try
                {
                    byte[] receiveBuffer = new byte[MaxBufferSize];

                 // 初始化 System.ArraySegment<T> 结构的新实例,该结构用于分隔指定数组中的所有元素。
                    ArraySegment<byte> buffer = new ArraySegment<byte>(receiveBuffer);

                //返回 : 当前的 System.Web.WebSockets.AspNetWebSocket 实例。
                    WebSocket socket = wsContext.WebSocket;
                    string userString;

                    if (socket.State == WebSocketState.Open)
                    {
                     // 链接建立起来后通知一下
                         var announceString = "EchoWebSocket Connected at: " + DateTime.Now.ToString();

                     //ArrarSegment<T> : 分隔一维数组的一部分。
                        ArraySegment<byte> outputBuffer2 = new ArraySegment<byte>(Encoding.UTF8.GetBytes(announceString));

                    //通过 WebSocket 连接异步发送数据。
                        await socket.SendAsync(outputBuffer2, WebSocketMessageType.Text, true, CancellationToken.None);
                    }

                    // 当 WebSocket处于打开状态时, 轮询客户端发送来的数据
                    while (socket.State == WebSocketState.Open)
                    {

                       //从 WebSocket 链接中异步接收数据
                            WebSocketReceiveResult receiveResult = await socket.ReceiveAsync(buffer, CancellationToken.None);

                        if (receiveResult.MessageType == WebSocketMessageType.Close)
                        {
                            // public abstract Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken
// cancellationToken) : 关闭 WebSocket 连接,使用关闭握手中定义的 WebSocket协议
await socket.CloseAsync( receiveResult.CloseStatus.GetValueOrDefault(), receiveResult.CloseStatusDescription, CancellationToken.None); return; } //显示 WebSocket 收到的字节数。 int offset = receiveResult.Count; while (receiveResult.EndOfMessage == false) { //在异步 WebSocket 连接中接收的数据。 receiveResult = await socket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer,
offset, MaxBufferSize - offset), CancellationToken.None); offset += receiveResult.Count; } //判断当前收到的消息是一个 utf - 8 消息 还是一个 二进制的消息。 if (receiveResult.MessageType == WebSocketMessageType.Text) { string cmdString = Encoding.UTF8.GetString(receiveBuffer, 0, offset); //将指定字节数组中的一个字节序列解码为一个字符串。 userString = cmdString; userString = "You said: \"" + userString + "\""; ArraySegment<byte> outputBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userString)); //通过 WebSocket 对象 异步发送数据 await socket.SendAsync(outputBuffer, WebSocketMessageType.Text, true, CancellationToken.None); } else if (receiveResult.MessageType == WebSocketMessageType.Binary) { userString = String.Format("binary message received, size={0} bytes", receiveResult.Count); ArraySegment<byte> outputBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userString)); await socket.SendAsync(outputBuffer, WebSocketMessageType.Text, true, CancellationToken.None); } } } catch (Exception ex) { //System.Diagnostics.Trace.WriteLine(ex); } }); } catch (Exception ex) { //System.Diagnostics.Trace.WriteLine(ex); context.Response.StatusCode = 500; context.Response.StatusDescription = ex.Message; context.Response.End(); } } public bool IsReusable { get { return false; } } }

页面中会用到的工具方法 , 判断并创建合法的 Uri:

       public bool TryGetUri(string uriString, out Uri uri)
        {
            uri = null;

            Uri webSocketUri;
            if (!Uri.TryCreate(uriString.Trim(), UriKind.Absolute, out webSocketUri))
            {
               //  Error: Invalid URI
                return false;
            }
            
            // Fragments are not allowed in WebSocket URIs.
            if (!String.IsNullOrEmpty(webSocketUri.Fragment))
            {
                // Error: URI fragments not supported in WebSocket URIs
                return false;
            }

            // Uri.SchemeName returns the canonicalized scheme name so we can use case-sensitive, ordinal string
            // comparison. 
//获取此 URI 的方案名称。
if ((webSocketUri.Scheme != "ws") && (webSocketUri.Scheme != "wss")) { // Error: WebSockets only support ws:// and wss:// schemes return false; } uri = webSocketUri; return true; }

1、UTF-8 text messages :

    操作截图 :

   在第一个 TextBox 中写上固定的本地服务地址和端口号, 指向服务器端的响应一般处理程序 (EchoWebSocket.ashx),在服务器端使用 WebSocket

类的对象进行响应客户端的请求。

点击 'Start' 按钮, 和服务器端建立连接 (服务器端已经运行),并且发送第二个 TextBox 中的文本, 服务器端响应 :

页面的 xaml :

//服务器的地址
 <TextBox  Name="ServerAddressField" IsEnabled="False" Text="ws://localhost:10000/EchoWebSocket.ashx" />

//向服务器端发送的文本字符串
 <TextBox Name="InputField" Text="Hello Windows 8~"  />
//响应服务器返回信息 
<TextBox Name="OutputField"  IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Auto" 
                                          ScrollViewer.VerticalScrollMode="Auto" />

相应的 C# :

首先声明两个变量 :

//用来与服务端通信
private MessageWebSocket messageWebSocket;

//执行向 MessageWebSocket 对象的输出流写入操作
private DataWriter messageWriter;

在 'Start' 按钮的单击事件中:

 private async void Start_Click(object sender, RoutedEventArgs e)
        {
            
            bool connecting = true;
            try
            {
                // 如果 messageWebSocket 为空时,创建
                 if (messageWebSocket == null)
                {
                    // 需要在工程文件清单中选择功能选项卡,勾选 Internet(客户端) 或者
                    // Internet(客户端和服务器)选项。    
                    //尝试创建合法的 Uri 对象                   
                    Uri server;
                    if (!TryGetUri(ServerAddressField.Text, out server))
                    {
                        return;
                    }
                   
                 // 支持允许使用 WebSocket 的读取和写入整个消息的网络通信。
                    messageWebSocket = new MessageWebSocket();
               
//
将在 MessageWebSocket 对象上配置的 WebSocket 消息类型。 messageWebSocket.Control.MessageType = SocketMessageType.Utf8;
//
指示在 MessageWebSocket 对象上收到消息的事件。 messageWebSocket.MessageReceived += MessageReceived; //在 UI 线程调度关闭事件。这让我们可以避免同步访问 messageWebSocket 。 //当 MessageWebSocket 对象作为关闭握手的一部分收到结束帧时发生。 messageWebSocket.Closed += async (senderSocket, args) => { //异步运行事件调度程序并返回调度事件的结果。 await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => Closed(senderSocket, args)); }; await messageWebSocket.ConnectAsync(server); //创建并初始化指向 messageWebSocket 对象输出流的数据编写器的新实例。 messageWriter = new DataWriter(messageWebSocket.OutputStream); // Connected } else { // Already connected } connecting = false; string message = InputField.Text; OutputField.Text += "Sending Message:\r\n" + message + "\r\n"; //缓冲任何我们想要发送的数据。 将字符串值写入输出流。 messageWriter.WriteString(message); // 异步存储数据操作。作为一个完整的消息将数据发送出去。 await messageWriter.StoreAsync(); // Send Complete } catch (Exception ex) { // 在连接操作是发生的错误 if (connecting && messageWebSocket != null) { messageWebSocket.Dispose(); messageWebSocket = null; } // 基于 WebSocket 操作遇到的错误,获取 WebErrorStatus 值。 WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult); switch (status) { case WebErrorStatus.CannotConnect: case WebErrorStatus.NotFound: case WebErrorStatus.RequestTimeout: // Cannot connect to the server. Please make sure to run the server setup script before running the sample break; case WebErrorStatus.Unknown: throw; default: // Error break; } OutputField.Text += ex.Message + "\r\n"; } }

 当收到服务器端的消息时触发 :

       private void MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
        {
            try
            {
                MarshalText(OutputField, "Message Received; Type: " + args.MessageType + "\r\n");

             // 获取 DataReader 对象,以读取MessageWebSocket 上的远程网络目标接收到的传入数据。
                using (DataReader reader = args.GetDataReader())
                {
                    //获取或设置用于输入流的 Unicode 字符编码。
                      reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;

                    string read = reader.ReadString(reader.UnconsumedBufferLength);
                    MarshalText(OutputField, read + "\r\n");
                }
            }
            catch (Exception ex) // For debugging
            {
                 //基于 WebSocket 操作遇到的错误,获取 WebErrorStatus 值。
                  WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult);

                if (status == WebErrorStatus.Unknown)
                {
                    throw;
                }

                MarshalText(OutputField, "Error: " + status + "\r\n");

                MarshalText(OutputField, ex.Message + "\r\n");
            }
        }
// 可能由服务器端触发,也可能本地的 Close/Dispose() 方法触发
private void Closed(IWebSocket sender, WebSocketClosedEventArgs args) { MarshalText(OutputField, "Closed; Code: " + args.Code + ", Reason: " + args.Reason + "\r\n"); if (messageWebSocket != null) { messageWebSocket.Dispose(); messageWebSocket = null; } } private void MarshalText(TextBox output, string value) { MarshalText(output, value, true); } // 后台操作对 UI 线程中的元素进行更改时,需要返回到 UI 线程执行 private void MarshalText(TextBox output, string value, bool append) { //异步运行事件调度程序并返回调度事件的结果。 var ignore = output.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { if (append) { output.Text += value; } else { output.Text = value; } }); }


单击 'Close' 按钮时 :

       private void Close_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (messageWebSocket != null)
                {
                   //public void Close(ushort code, string reason)  : 关闭 MessageWebSocket 
                   //对象并指示关闭的原因。 (code:  指示关闭原因的状态代码。)
                    messageWebSocket.Close(1000, "Closed due to user request.");
                    messageWebSocket = null;
                }
                else
                {
                   // No active WebSocket, send something first
                }
            }
            catch (Exception ex)
            {
                WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult);

                if (status == WebErrorStatus.Unknown)
                {
                    throw;
                }

                OutputField.Text += ex.Message + "\r\n";
            }
        }

2、Binary data stream :

     本例介绍如何使用  StreamWebSocket 发送二进制数据。

   

     操作截图 :

点击 'Start'  按钮 :

页面的 xaml :

//服务器端地址
 <TextBox  Name="ServerAddressField" IsEnabled="False" Text="ws://localhost:10000/EchoWebSocket.ashx" />

<Button Content="Start"  Click="Start_Click"/>

<Button Content="Stop" Click="Stop_Click"/>
<TextBlock Text="Data Sent:"/>

<TextBox Name="DataSentField" IsReadOnly="True" />

<TextBlock Text="Data Received:" />

<TextBox Name="DataReceivedField" />

相应的 C# 方法  :

 
 private StreamWebSocket streamWebSocket;
 private byte[] readBuffer;
 private async void Start_Click(object sender, RoutedEventArgs e)
        {
          
          if (streamWebSocket != null)
            {
                // Already connected
                return;
            }

            Uri server;
            if (!TryGetUri(ServerAddressField.Text, out server))
            {
                return;
            }

            try
            {
               //Connecting to  server 
              // 支持允许使用 WebSocket 的读取和写入流的网络通信。
                streamWebSocket = new StreamWebSocket();

                streamWebSocket.Closed += async (senderSocket, args) =>
                {
                    await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => Closed(senderSocket, args));
                };

              //连接服务器
                await streamWebSocket.ConnectAsync(server);

                readBuffer = new byte[1000];

                //启动一个后台任务持续阅读传入的数据
                Task receiving = Task.Factory.StartNew(Scenario2ReceiveData,
                    streamWebSocket.InputStream.AsStreamForRead(), TaskCreationOptions.LongRunning);

                // 启动一个后台任务,不断写输出数据
                Task sending = Task.Factory.StartNew(Scenario2SendData,
                    streamWebSocket.OutputStream, TaskCreationOptions.LongRunning);

                //Connected
            }
            catch (Exception ex) 
            {
                if (streamWebSocket != null)
                {
                    streamWebSocket.Dispose();
                    streamWebSocket = null;
                }

                WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult);

                switch (status)
                {
                    case WebErrorStatus.CannotConnect:
                    case WebErrorStatus.NotFound:
                    case WebErrorStatus.RequestTimeout:
                       // Cannot connect to the server. Please make sure  to run the server setup script before running the sample
                        break;

                    case WebErrorStatus.Unknown:
                        throw;

                    default:
                             Error:  status
                        break;
                }

                OutputField.Text += ex.Message + "\r\n";
            }
        }
//不断写输出数据。写入数据,我们将展示如何使用 data.AsBuffer() 来获得一个 IBuffer 来使用

//webSocket.OutputStream.WriteAsync() 。 或者你可以调用
//webSocket.OutputStream.AsStreamForWrite() 来使用 .NET streams

 private async void Scenario2SendData(object state)
        {
            int dataSent = 0;
            byte[] data = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 };

            MarshalText(OutputField, "Background sending data in " + data.Length
                + " byte chunks each second.\r\n");

            try
            {
                IOutputStream writeStream = (IOutputStream)state;

                // 发送直到套接字 关闭/停止
                while (true)
                {
                    // using System.Runtime.InteropServices.WindowsRuntime;
                   // 在有序流中以异步方式写入数据。
                    await writeStream.WriteAsync(data.AsBuffer());

                    dataSent += data.Length;
                    MarshalText(DataSentField, dataSent.ToString(), false);

                    // 延迟 1 秒 ,这样用户可以看发生了什么。
                    await Task.Delay(TimeSpan.FromSeconds(1));
                }
            }
            catch (ObjectDisposedException)
            {
                MarshalText(OutputField, "Background write stopped.\r\n");
            }
            catch (Exception ex)
            {
                WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult);

                switch (status)
                {
                    case WebErrorStatus.OperationCanceled:
                        MarshalText(OutputField, "Background write canceled.\r\n");
                        break;

                    case WebErrorStatus.Unknown:
                        throw;

                    default:
                        MarshalText(OutputField, "Error: " + status + "\r\n");
                        MarshalText(OutputField, ex.Message + "\r\n");
                        break;
                }
            }
        }
  
//持续阅读传入的数据。阅读数据, 我们将展示如何使用 webSocket.InputStream.AsStream()
//得到一个 .NET stream。 或者你可以调用 readBuffer.AsBuffer()  
//webSocket.InputStream.ReadAsync 来使用IBuffer。
 private async void Scenario2ReceiveData(object state)
        {
            int bytesReceived = 0;
            try
            {
                Stream readStream = (Stream)state;
                MarshalText(OutputField, "Background read starting.\r\n");

                while (true) // Until closed and ReadAsync fails.
                {
//异步读取一个字节序列,并且在流中通过读取的字节数提前 position int read = await readStream.ReadAsync(readBuffer, 0, readBuffer.Length); bytesReceived += read; MarshalText(DataReceivedField, bytesReceived.ToString(), false); // 处理获得的数据. } } catch (ObjectDisposedException) { MarshalText(OutputField, "Background read stopped.\r\n"); } catch (Exception ex) { WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult); switch (status) { case WebErrorStatus.OperationCanceled: MarshalText(OutputField, "Background write canceled.\r\n"); break; case WebErrorStatus.Unknown: throw; default: MarshalText(OutputField, "Error: " + status + "\r\n"); MarshalText(OutputField, ex.Message + "\r\n"); break; } } }
 //  可能由服务器端触发,也可能本地的 Close/Dispose() 方法触发

private void Closed(IWebSocket sender, WebSocketClosedEventArgs args) { MarshalText(OutputField, "Closed; Code: " + args.Code + ", Reason: " + args.Reason + "\r\n"); if (streamWebSocket != null) { streamWebSocket.Dispose(); streamWebSocket = null; } } private void MarshalText(TextBox output, string value) { MarshalText(output, value, true); } private void MarshalText(TextBox output, string value, bool append) { var ignore = output.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { if (append) { output.Text += value; } else { output.Text = value; } }); }

点击 'Close' 按钮时触发 :

  private void Stop_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (streamWebSocket != null)
                {
                    //Stopping
                    streamWebSocket.Close(1000, "Closed due to user request.");
                    streamWebSocket = null;
                }
                else
                {
                    //There is no active socket to stop
                }
            }
            catch (Exception ex)
            {
                WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult);

                if (status == WebErrorStatus.Unknown)
                {
                    throw;
                }

                //Error
                OutputField.Text += ex.Message + "\r\n";
            }
        }
原文地址:https://www.cnblogs.com/hebeiDGL/p/2707027.html