[源码下载]

重新想象 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的更多相关文章

  1. 重新想象 Windows 8 Store Apps (60) - 通信: 获取网络信息, 序列化和反序列化

    [源码下载] 重新想象 Windows 8 Store Apps (60) - 通信: 获取网络信息, 序列化和反序列化 作者:webabcd 介绍重新想象 Windows 8 Store Apps ...

  2. 重新想象 Windows 8 Store Apps (61) - 通信: http, oauth

    [源码下载] 重新想象 Windows 8 Store Apps (61) - 通信: http, oauth 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 通信 ...

  3. 重新想象 Windows 8 Store Apps (62) - 通信: Socket TCP, Socket UDP

    [源码下载] 重新想象 Windows 8 Store Apps (62) - 通信: Socket TCP, Socket UDP 作者:webabcd 介绍重新想象 Windows 8 Store ...

  4. 重新想象 Windows 8 Store Apps 系列文章索引

    [源码下载][重新想象 Windows 8.1 Store Apps 系列文章] 重新想象 Windows 8 Store Apps 系列文章索引 作者:webabcd 1.重新想象 Windows ...

  5. 重新想象 Windows 8 Store Apps (66) - 后台任务: 下载和上传

    [源码下载] 重新想象 Windows 8 Store Apps (66) - 后台任务: 下载和上传 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 后台任务 后台 ...

  6. 重新想象 Windows 8 Store Apps (68) - 后台任务: 控制通道(ControlChannel)

    [源码下载] 重新想象 Windows 8 Store Apps (68) - 后台任务: 控制通道(ControlChannel) 作者:webabcd 介绍重新想象 Windows 8 Store ...

  7. 重新想象 Windows 8 Store Apps (34) - 通知: Toast Demo, Tile Demo, Badge Demo

    [源码下载] 重新想象 Windows 8 Store Apps (34) - 通知: Toast Demo, Tile Demo, Badge Demo 作者:webabcd 介绍重新想象 Wind ...

  8. 重新想象 Windows 8 Store Apps (35) - 通知: Toast 详解

    [源码下载] 重新想象 Windows 8 Store Apps (35) - 通知: Toast 详解 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 通知 Toa ...

  9. 重新想象 Windows 8 Store Apps (36) - 通知: Tile 详解

    [源码下载] 重新想象 Windows 8 Store Apps (36) - 通知: Tile 详解 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 通知 Tile ...

随机推荐

  1. openwrt 编译newifi 应用程序

    首先找交叉编译工具( toolchain ) Development Snapshots http://downloads.openwrt.org/snapshots/trunk/ 我需要的版本是 m ...

  2. 11款样式新颖的 jQuery/CSS3 网页菜单

    今天为大家准备了11款样式风格挺不错的jQuery/CSS3网页菜单,主要包括面包屑菜单.下拉菜单.Tab菜单等,喜欢的朋友赶紧收藏,一起来看看这些菜单. 1.jQuery / CSS3多功能下拉菜单 ...

  3. swift 闭包

    闭包可以捕获和存储其所在上下文中任意常量和变量的引用. 这就是所谓的闭合并包裹着 这些常量和变量,俗称闭包. Swift标准库中提供了sort排序函数,sort函数的第二个参数是个闭包.和OC中的bl ...

  4. 十、EnterpriseFrameWork框架的分层架构及意义(控制器、业务对象、实体、Dao之间关系)

    本章内容主要包括两个方面,一.是框架分层(控制器.业务对象.实体.Dao)的详细说明,二.是对比常用三层结构的区别和优势: 本文要点: 1.框架中的各个分层详细说明 2.对比常用三层结构的区别和优势 ...

  5. Python使用libsvm的“ImportError: No module named svmutil”问题

    from:http://blog.csdn.net/xmu_jupiter/article/details/46830327 这几天快被Python的一些细节问题整死了,浪费了不少时间.现在把这些记录 ...

  6. MyBatis知多少(2)

    MyBatis从目前最流行的关系数据库访问方法中吸收了大量的优秀特征和思想,并找出其中的协同增效作用.下图展示了MyBatis框架是如何吸收我们在多年使用不同方式进行数据库集成的 开发过程中所学到的知 ...

  7. 403 Forbidden client denied by server configuration[apache2, linux]

    在LAMP的配置过程中, 由于APACHE的版本问题, 即使是APACHE2和APACHE2.2也有很大的不同. 一般都有同一个环境配置多个虚拟网站的情况, 如果你在配置过程中遇到APACHE的不同版 ...

  8. Unity3D内置着色器

    Unity内部提供了一些可以直接使用的着色器,这些内置着色器包括以下6个方面: (1)Performance of Unity shaders 着色器的性能和两个方面有关:shader本身和rende ...

  9. VirtualBox Bridged 无线网卡

    启动虚拟机后选择右键单击右下角的网络链接图标,  弹出的窗口中选择Bridged Adapter,  wlan0 然后选择OK 查看virtual Box主页面中setting中网络的配置是否和刚才一 ...

  10. Web程序员开发App系列 - 调试Android和IOS手机代码(补图)

    Web程序员开发App系列 Web程序员开发App系列 - 认识HBuilder Web程序员开发App系列 - 申请苹果开发者账号 Web程序员开发App系列 - 调试Android和iOS手机代码 ...