zoukankan      html  css  js  c++  java
  • 重新想象 Windows 8 Store Apps (63)

    [源码下载]


    重新想象 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
    [源码下载]

  • 相关阅读:
    git常用指令 github版本回退 reset
    三门问题 概率论
    如何高效的学习高等数学
    数据库6 关系代数(relational algebra) 函数依赖(functional dependency)
    数据库5 索引 动态哈希(Dynamic Hashing)
    数据库4 3层结构(Three Level Architecture) DBA DML DDL DCL DQL
    梦想开始的地方
    java String字符串转对象实体类
    java 生成图片验证码
    java 对象之间相同属性进行赋值
  • 原文地址:https://www.cnblogs.com/webabcd/p/3360490.html
Copyright © 2011-2022 走看看