程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Windows 8 Store Apps學習(63) 通信: WebSocket

Windows 8 Store Apps學習(63) 通信: WebSocket

編輯:關於.NET

介紹

重新想象 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

源碼下載:http://files.cnblogs.com/webabcd/Windows8.rar

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved