ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

UWP WebSocket 客户端实战:基于 Windows-universal-samples 的 MessageWebSocket 与 StreamWebSocket 完整指南

UWP WebSocket 客户端实战:基于 Windows-universal-samples 的 MessageWebSocket 与 StreamWebSocket 完整指南 示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载导读本文以 Windows-universal-samples 仓库中的 WebSocket 示例archived/WebSocket/README.md及其活跃版本 Samples/WebSocket/README.md为核心系统讲解如何在通用 Windows 平台UWP应用中使用Windows.Networking.Sockets命名空间下的 WebSocket 类进行实时双向通信。你将掌握 MessageWebSocket 与 StreamWebSocket 的选型与调用、安全的 URI 校验、wss:// 下的服务器证书自定义验证、客户端证书安装与认证以及配套 IIS 服务器的部署与运行方法。WebSocket 示例概览两个核心客户端类Windows 10 为 UWP 应用提供了完整的 WebSocket 客户端支持定义于Windows.Networking.Sockets命名空间包含两种用途不同的 WebSocket 对象类适用场景消息类型MessageWebSocket典型的消息交换场景消息体不大发送/接收以完整消息为粒度支持 UTF-8 文本与二进制消息StreamWebSocket传输照片、视频等大文件允许每次读操作只读取消息的一段而无需一次性读完整条消息仅支持二进制消息仓库中的示例同时演示了这两类连接并覆盖了四个典型场景以 JavaScript 版 archived/WebSocket/js/js/sample-configuration.js 中的场景清单为准C#/C 版本结构一致使用 MessageWebSocket 发送 UTF-8 文本消息服务器将消息回显使用 StreamWebSocket 发送二进制数据服务器回显二进制数据使用StreamWebSocketControl.ClientCertificate属性在连接安全服务器时提供客户端认证信息使用MessageWebSocketControl.ReceiveMode PartialMessage处理部分Partial与完整Complete消息。注意该示例默认通过回环接口loopback访问网络。场景一用 MessageWebSocket 收发 UTF-8 文本这是最基础的场景建立连接、发送文本、接收服务器回显、关闭连接。完整实现见 archived/WebSocket/js/js/scenario1-utf8.jsC# 版本见 Samples/WebSocket/cs/Scenario1_UTF8.xaml.cs。建立连接创建MessageWebSocket实例设置消息类型并挂接事件回调然后调用connectAsyncvar messageWebSocket new MessageWebSocket(); messageWebSocket.control.messageType SocketMessageType.utf8; messageWebSocket.addEventListener(messagereceived, onMessageReceived); messageWebSocket.addEventListener(closed, onClosed); return messageWebSocket.connectAsync(server).then(function () { // The default DataWriter encoding is utf8. messageWriter new Windows.Storage.Streams.DataWriter(messageWebSocket.outputStream); }, function (error) { messageWebSocket.close(); messageWebSocket null; appendOutputLine(SdkSample.buildWebSocketError(error)); });C# 中的等价写法Samples/WebSocket/cs/Scenario1_UTF8.xaml.cs为messageWebSocket new MessageWebSocket(); messageWebSocket.Control.MessageType SocketMessageType.Utf8; messageWebSocket.MessageReceived MessageReceived; messageWebSocket.Closed OnClosed; await messageWebSocket.ConnectAsync(server); messageWriter new DataWriter(messageWebSocket.OutputStream);关键点connectAsync的参数不是字符串而是经过校验的Windows.Foundation.Uri对象校验细节见下文URI 校验小节。发送消息发送时先把数据写入DataWriter缓冲再通过storeAsync()一次性作为完整消息发出messageWriter.writeString(message); return messageWriter.storeAsync().then(function () { WinJS.log WinJS.log(Send Complete, sample, status); });接收消息MessageReceived事件触发时整条消息已经缓冲完毕直接用args.getDataReader()读取function onMessageReceived(args) { var reader args.getDataReader(); reader.unicodeEncoding UnicodeEncoding.utf8; appendOutputLine(reader.readString(reader.unconsumedBufferLength)); }关闭连接关闭时有两个容易被忽略的细节archived/WebSocket/js/js/scenario1-utf8.js若未来要复用同一个 socket 的 outputStream 挂接新的 DataWriter必须先detachStream()再关闭 DataWriter否则 DataWriter 析构时会自动关闭输出流后续 I/O 将失败C# 中表现为ObjectDisposedException主动关闭使用close(1000, Closed due to user request.)其中 1000 为 WebSocket 标准关闭码Normal Closure并附带关闭原因字符串。场景二用 StreamWebSocket 传输二进制数据流当需要传输大文件照片、视频等时StreamWebSocket 允许按段读取避免一次性缓冲整条消息。完整实现见 archived/WebSocket/js/js/scenario2-binary.js。连接建立后示例同时启动两个后台循环一个持续写数据一个持续读数据。持续写入function sendData(activeSocket) { var dataWriter new Windows.Storage.Streams.DataWriter(activeSocket.outputStream); var bytesSent 0; var data Hello World; function loopAsync() { if (streamWebSocket ! activeSocket) { return; // 连接已失效停止发送 } var size dataWriter.measureString(data); dataWriter.writeString(data); return dataWriter.storeAsync().then(function () { bytesSent size; dataSent.innerText bytesSent; return WinJS.Promise.timeout(1000); // 每秒发送一次便于观察 }).then(loopAsync); } loopAsync()... }持续读取部分读取function receiveData(activeSocket) { var dataReader new Windows.Storage.Streams.DataReader(activeSocket.inputStream); // 关键partial 模式让数据一到就返回不必等整条消息 dataReader.inputStreamOptions Windows.Storage.Streams.InputStreamOptions.partial; function loopAsync() { if (streamWebSocket ! activeSocket) { return; } return dataReader.loadAsync(100).then(function (sizeBytesRead) { bytesReceived sizeBytesRead; var incomingBytes new Array(sizeBytesRead); dataReader.readBytes(incomingBytes); return loopAsync(); }); } loopAsync()... }核心要点InputStreamOptions.partial配合loadAsync(100)每次只缓冲 100 字节并立即处理这正是按段读取大消息的实现方式也可以用 DataReader 逐个读出布尔值、整数、字符串等类型。场景四MessageWebSocket 的部分消息Partial/Complete读写默认情况下MessageWebSocket 只在收到完整消息时触发MessageReceived。若希望在数据到达时立即处理部分内容需要设置接收模式见 archived/WebSocket/js/js/scenario4-partialReadWrite.jsmessageWebSocket.control.receiveMode MessageWebSocketReceiveMode.partialMessage;发送侧通过两个 API 区分消息帧的终结属性if (endOfMessageCheckBox.checked true) { // 发送完整消息终结帧 asyncTask messageWebSocket.sendFinalFrameAsync(buffer); } else { // 发送部分消息非终结帧 asyncTask messageWebSocket.sendNonfinalFrameAsync(buffer); }接收侧用args.isMessageComplete判断当前事件是部分还是完整消息var partialOrCompleted args.isMessageComplete ? Complete : Partial; appendOutputLine(partialOrCompleted message received; Type: ...);需要注意部分 UTF-8 消息可能在多字节字符中间被拆断。示例中刻意只使用 ASCII 字符规避该问题若应用要发送多字节字符必须自行处理被截断的字符边界。核心安全实践URI 校验与错误诊断URI 校验由于服务器地址来自用户输入不可信来源示例在连接前统一通过SdkSample.validateAndCreateUri()校验archived/WebSocket/js/js/sample-configuration.js无法解析的字符串直接拒绝返回 null含 fragment#...的 URI 被拒绝WebSocket URI 不支持片段scheme 必须是ws或wssUri.schemeName返回规范化后的名称可做区分大小写的序数比较校验通过后返回Windows.Foundation.Uri供connectAsync使用。C# 版本中对应的MainPage.TryGetUri()逻辑与此一致Samples/WebSocket/cs/Scenario1_UTF8.xaml.cs。错误诊断SdkSample.buildWebSocketError()将 HRESULT 转换为WebErrorStatus并对最常见的失败给出可操作提示archived/WebSocket/js/js/sample-configuration.jscannotConnect/notFound/requestTimeout→ 无法连接服务器请确认已先运行服务器安装脚本unknown→ 输出原始 COM 错误码其他 → 输出枚举名。场景三wss:// 下的证书验证与客户端证书服务器证书的自定义验证当连接 wss:// 端点时操作系统默认基于受信任 CA 链验证服务器证书示例展示了如何在此之上追加自定义验证逻辑。先声明哪些证书错误可以忽略再订阅servercustomvalidationrequested事件messageWebSocket.control.ignorableServerCertificateErrors.push( ChainValidationResult.untrusted, ChainValidationResult.invalidName); messageWebSocket.addEventListener(servercustomvalidationrequested, onServerCustomValidationRequested);事件处理函数中必须先用getDeferral()取得延迟deferral在异步验证完成后调用deferral.complete()否则异步 API 无法在处理器内安全使用function onServerCustomValidationRequested(args) { var deferral args.getDeferral(); SdkSample.areCertificateAndCertChainValidAsync( args.serverCertificate, args.serverIntermediateCertificates).then(function (isValid) { if (isValid) { appendOutputLine(Custom validation of server certificate passed.); } else { args.reject(); // 验证失败时拒绝连接 } deferral.complete(); }); }验证函数对证书链中的每一张证书含服务器证书本身逐一调用isCertificateValidAsync全部通过才算有效archived/WebSocket/js/js/sample-configuration.js。示例中的校验逻辑检查签发者是否为www.fabrikam.com仅为演示占位不构成证书校验最佳实践推荐。安全警告代码注释中原样强调只有测试应用才应忽略 SSL 错误。真实应用中忽略证书错误会招致中间人MITM攻击——连接虽然是加密的但服务器身份未被认证。且并非所有证书验证错误都可被忽略。示例忽略这些错误仅因为 localhost 使用的自签名证书主题名是fabrikam.com。客户端证书的获取、安装与绑定场景三演示了如何为安全连接提供客户端证书archived/WebSocket/js/js/scenario3-clientCertificate.js。流程分三步从应用商店查找证书用CertificateQuery按签发者www.contoso.com和友好名称WebSocketSampleClientCert查询CertificateStores.findAllAsync若已安装则直接复用安装随包携带的 PFX从ms-appx:///data/clientCert.pfx读取证书文件base64 编码后调用CertificateEnrollmentManager.importPfxDataAsync安装到应用专属证书库应用卸载即删除。示例中 PFX 密码为1234绑定到连接通过StreamWebSocketControl.ClientCertificate属性挂接streamWebSocket.control.clientCertificate cert;关于证书库的选择代码注释给出了重要说明若要安装到与用户共享的CurrentUser\MY库应用卸载后证书仍然保留必须改用CertificateEnrollmentManager.UserCertificateEnrollmentManager.importPfxDataAsync()且应用需要在 Package.appxmanifest 中声明sharedUserCertificates能力示例清单中该能力处于注释状态见 archived/WebSocket/js/Package.appxmanifest。合规提醒将 PFX 文件打进应用包违反 Windows 应用商店认证要求。本示例仅为演示客户端证书用法要发布到商店的应用需通过其他途径获取客户端证书。网络能力Network Capabilities配置示例默认经回环接口运行但应用仍必须在Package.appxmanifest中声明网络能力才能在运行时访问网络README 原文明确说明。能力可在 Visual Studio 的清单编辑器或直接编辑 XML 设置Private Networks (Client Server)允许在家庭或工作网络本地内网上进行入站/出站访问。清单中对应Capability NameprivateNetworkClientServer /若修改示例去连接 Internet 上另一台设备的服务器组件更典型的产品形态客户端必须声明Internet (Client)对应Capability NameinternetClient /。JavaScript 版示例清单archived/WebSocket/js/Package.appxmanifest同时声明了internetClientServer与privateNetworkClientServer两项Capabilities Capability NameinternetClientServer / Capability NameprivateNetworkClientServer / !-- Uncomment this capability if you need to install a certificate to the CurrentUser\MY store -- !--uap:Capability NamesharedUserCertificates -- /Capabilities服务器端准备IIS 回显服务器与 PowerShell 脚本应用要成功建立 WebSocket 连接必须有一个支持 WebSockets、且暴露WebSocketSample路径的 Web 服务器且需在启动应用之前启动服务器。仓库在 Samples/WebSocket/server 下提供了完整方案setupserver.ps1在本地安装并启用 IIS、创建WebSocketSample应用目录、拷贝网页文件、启用 WebSocket 支持、生成自签名服务器证书DNS 名为www.fabrikam.com、配置 443 端口的 SSL 绑定并添加 80/443 入站防火墙规则removeserver.ps1卸载以上设置网站文件位于 Samples/WebSocket/server/website核心是回显处理器 echowebsocket.ashx收到文本消息回显You said: ...收到二进制消息回显字节数统计收到 Close 帧则回显关闭码与原因。安装并启动服务器IIS进入示例的Server文件夹任选其一# 方式一管理员 PowerShell .\SetupServer.ps1 # 注意可能还需要调整脚本执行策略 # 方式二管理员命令提示符 PowerShell.exe -ExecutionPolicy Unrestricted -File SetupServer.ps1不再需要服务器时.\RemoveServer.ps1 # 或 PowerShell.exe -ExecutionPolicy Unrestricted -File RemoveServer.ps1前置条件setup 脚本要求先运行 Samples/WebSocket/shared/clientCertGenerator.ps1 生成证书否则脚本会退出并提示。使用其他 Web 服务器示例不依赖 IIS任何支持 WebSocket 的服务器均可。通用配置步骤将Server\webSite\EchoWebSocket.ashx复制到 Web 服务器的WebSocketSample目录再次复制并重命名为EchoWebSocketWithClientAuthentication.ashx配置服务器接受 WebSocket 连接并对EchoWebSocketWithClientAuthentication.ashx页面要求 SSL 连接与客户端证书。连接非 localhost 服务器若服务器在其他设备上在应用清单中追加所需能力例如服务器位于 Internet 时添加Internet (Client Server)更新服务器主机名编辑 HTML/XAML 中的ServerAddressField元素把localhost替换为服务器主机名或 IP或在应用运行时在Server Address输入框中直接填写主机名/IP。注意IIS 不适用于 ARM 构建和 Windows Phone。在这些设备上应把 Web 服务器架设在独立的 32/64 位机器上并按非 localhost 服务器步骤运行。Windows Phone 版同理。构建与运行示例若下载的是示例 ZIP务必解压整个压缩包而非仅目标子目录以保证共享依赖可用使用 Visual Studio 2017 打开File Open Project/Solution定位到解压目录下的 Samples 子文件夹 → 本示例文件夹 → 首选语言子文件夹C、C# 或 JavaScript双击解决方案.sln文件按CtrlShiftB或Build Build Solution构建。运行方式取决于需求仅部署Build Deploy Solution部署并运行 Windows 版按F5调试运行或CtrlF5免调试运行。JavaScript 版工程文件见 archived/WebSocket/js/WebSocket.sln 与 archived/WebSocket/js/WebSocket.jsprojJS 场景页面位于 archived/WebSocket/js/html 下的四个 scenario 页面默认服务器地址为ws://localhost/WebSocketSample/EchoWebSocket.ashx见 scenario1-utf8.html。已知问题场景三演示的客户端证书 API 目前在XBOX上无法工作README 明确标注。延伸阅读与仓库路径活跃版本完整代码Samples/WebSocket含 cpp / cppwinrt / cs 三种语言实现、shared 共享 XAML、server 服务器端脚本归档 JavaScript 版本archived/WebSocket服务器回显处理器echowebsocket.ashx服务器安装脚本setupserver.ps1证书生成脚本clientCertGenerator.ps1。参考 APIMessageWebSocket、StreamWebSocket及Windows.Networking.Sockets命名空间系统要求为 Windows 10客户端、Windows Server 2016服务器端、Windows 10Phone。赞分享示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载相关推荐Windows Universal Platform WebSocket 示例实战MessageWebSocket 与 StreamWebSocket 完整指南Windows Universal Platform WebSocket 示例实战MessageWebSocket 与 StreamWebSocket 完整指示例工程Windows-universal-samples 之 CameraStarterKit基于 Windows.Media.Capture 的端到端 UWP 相机应用实战指南Windows universal samples 之 CameraStarterKit基于 Windows.Media.Capture 的端到端 UWP 相示例工程UWP 中 Windows Runtime XML API 实战指南基于 Windows-universal-samples 的 XmlDocument 样例UWP 中 Windows Runtime XML API 实战指南基于 Windows universal samples 的 XmlDocument 样例示例工程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表