重新想象 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 = * ;
- 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, , 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(, "用户在客户端关闭了 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());
- }
- }
- 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[];
- int bytesReceived = ;
- try
- {
- Stream readStream = (Stream)state;
- while (true)
- {
- // 接收数据
- int read = await readStream.ReadAsync(readBuffer, , readBuffer.Length);
- bytesReceived += read;
- await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
- {
- lblMsg.Text += "received: " + System.Text.Encoding.UTF8.GetString(readBuffer, , 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(, "用户在客户端关闭了 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
[源码下载]
重新想象 Windows 8 Store Apps (63) - 通信: WebSocket的更多相关文章
- 重新想象 Windows 8 Store Apps (60) - 通信: 获取网络信息, 序列化和反序列化
[源码下载] 重新想象 Windows 8 Store Apps (60) - 通信: 获取网络信息, 序列化和反序列化 作者:webabcd 介绍重新想象 Windows 8 Store Apps ...
- 重新想象 Windows 8 Store Apps (61) - 通信: http, oauth
[源码下载] 重新想象 Windows 8 Store Apps (61) - 通信: http, oauth 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 通信 ...
- 重新想象 Windows 8 Store Apps (62) - 通信: Socket TCP, Socket UDP
[源码下载] 重新想象 Windows 8 Store Apps (62) - 通信: Socket TCP, Socket UDP 作者:webabcd 介绍重新想象 Windows 8 Store ...
- 重新想象 Windows 8 Store Apps 系列文章索引
[源码下载][重新想象 Windows 8.1 Store Apps 系列文章] 重新想象 Windows 8 Store Apps 系列文章索引 作者:webabcd 1.重新想象 Windows ...
- 重新想象 Windows 8 Store Apps (66) - 后台任务: 下载和上传
[源码下载] 重新想象 Windows 8 Store Apps (66) - 后台任务: 下载和上传 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 后台任务 后台 ...
- 重新想象 Windows 8 Store Apps (68) - 后台任务: 控制通道(ControlChannel)
[源码下载] 重新想象 Windows 8 Store Apps (68) - 后台任务: 控制通道(ControlChannel) 作者:webabcd 介绍重新想象 Windows 8 Store ...
- 重新想象 Windows 8 Store Apps (34) - 通知: Toast Demo, Tile Demo, Badge Demo
[源码下载] 重新想象 Windows 8 Store Apps (34) - 通知: Toast Demo, Tile Demo, Badge Demo 作者:webabcd 介绍重新想象 Wind ...
- 重新想象 Windows 8 Store Apps (35) - 通知: Toast 详解
[源码下载] 重新想象 Windows 8 Store Apps (35) - 通知: Toast 详解 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 通知 Toa ...
- 重新想象 Windows 8 Store Apps (36) - 通知: Tile 详解
[源码下载] 重新想象 Windows 8 Store Apps (36) - 通知: Tile 详解 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 通知 Tile ...
随机推荐
- Android 模拟器检测
参考链接:https://github.com/MindMac/HideAndroidEmulator 从多个方面识别模拟器1.用户习惯:联系人数量.短信数量.相册里面照片数量.安装的应用2.从IME ...
- 《objective-c基础教程》学习笔记(十一)—— 类别
在编写面向对象程序的时候,我们经常想为现有的类添加一些新的行为.有些时候,我们可以创建这个类的子类.但是,如果我们用到工具集或者类库的时候,无法处理新建的子类.这时,Objective-C就给我们提供 ...
- mac安装 配置 ant
转自:http://blog.sina.com.cn/s/blog_877e9c3c0101qs87.html 1.下载ant 官网下载 http://ant.apache.org/bindownlo ...
- android 开发环境
http://blog.csdn.net/shulianghan/article/details/38023959
- 控制反转(Ioc)和依赖注入(DI)
控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基 ...
- 一个基于POP3协议进行邮箱账号验证的类
最近老陈要针对企业邮箱做一些开发,以对接企业OA神马的,但企业邮箱唯独没有开放账号密码验证功能,很恼火!不得已,翻出早些年的Asp代码改编成了C#类,实现了一个C#下的通过POP3协议进行邮箱账号验证 ...
- coreseek 提示 client version is higher than daemon version 解决办法
安装好coreseek,开启了服务之后,通过 sphinx php扩展去请求数据,提示:client version is higher than daemon version (client is ...
- 【cs229-Lecture17】离散与维数灾难
主要内容: 解决MDP问题的算法: 离散化: 模型MDP的同化型: (model/similator) 拟合值迭代算法: Q函数: 近似政策迭代: 笔记转自:http://blog.csdn.net/ ...
- win7激活
应亲戚要求,装了次win7系统,重新删除分区,格盘,重新划分好分区.完毕.发现系统分区全自动变成动态磁盘.使用win7激活工具时,注意选择使用 小马通用版激活工具. 动态磁盘 稍后解释 小马工具
- android小技巧和注意事项
在listView 或者 gridView 的使用中,通常不仅仅为了展现数据,更多的是操作数据.于是当控件重合在一起时,我们需要添加事件.就会出现一个问题,当点击一个控件和长按这个控件时,常常出现长按 ...