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
    [源码下载]

  • 相关阅读:
    程序自动网站留言,自动登录,自动投票等做法 httpclient 拂晓风起
    CruiseControl 安装 配置 教程 实例 搭建服务器 (CruiseControl + git/svn) 拂晓风起
    编码和字符集的关系 拂晓风起
    PuttyGen生成SSH(key) 带图 TortoiseGit和Github的SSH生成 拂晓风起
    计算时间差,将yyyyMMddHHmmss字符格式转为时间
    C# 操作非标准的xml文件
    SqlServer2000中调度包到作业中,自动执行失败的解决方法
    ReSharper 命名规则
    Js中setInterval、setTimeout不能传递参数问题 及各自的关闭方法
    获取存储过程返回值
  • 原文地址:https://www.cnblogs.com/webabcd/p/3360490.html
Copyright © 2011-2022 走看看