• 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";
                }
            }
  • 相关阅读:
    Thymeleaf
    快速创建springBoot
    多环境的配置
    第一个SpringBoot
    shiro第三天整合jdbc
    shrio 第二天
    Python 算法集合
    张凤强-《工会固定资产管理系统的设计与实现》随笔
    李翔-《营口港资产管理系统设计与实现》随笔
    刘晶-《高校固定资产管理系统的设计与实现》随笔
  • 原文地址:https://www.cnblogs.com/hebeiDGL/p/2707027.html
Copyright © 2020-2023  润新知