如何在UWP中使用C#完整读取网络套接字的传入数据?
UWP 中 StreamSocket 完整读取请求数据的解决方案
我太懂你的困扰了——之前在.NET里能用的套接字读取方案,到UWP里处处受限,ReadTimeout不能用、同步读取容易阻塞,连Length属性都直接抛异常,确实头疼。针对你做简易REST服务器读取POST数据的场景,我给你一套UWP专属的实现方案:
核心思路
UWP的StreamSocket输入流是纯异步设计的,完全不能依赖同步读取逻辑。我们需要通过异步循环读取覆盖两种常见HTTP请求体传输场景:
- 带
Content-Length头的常规请求 - 无
Content-Length但用Transfer-Encoding: chunked分块编码的请求(HTTP/1.1标准) - 既无长度头也不分块的旧版HTTP/1.0请求(读取到流结束)
完整实现代码
直接替换你现有的conn_received方法,用异步逻辑重构:
private async void conn_received(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) { // 用using自动释放资源,避免UWP沙箱内资源泄漏 using (var socket = args.Socket) using (var inputStream = socket.InputStream) using (var reader = new StreamReader(inputStream.AsStreamForRead())) { // 第一步:读取请求头 string requestLine = await reader.ReadLineAsync(); if (string.IsNullOrEmpty(requestLine)) return; var headers = new Dictionary<string, string>(); string headerLine; while (!string.IsNullOrEmpty(headerLine = await reader.ReadLineAsync())) { var splitPos = headerLine.IndexOf(':'); if (splitPos > 0) { var key = headerLine.Substring(0, splitPos).Trim(); var value = headerLine.Substring(splitPos + 1).Trim(); headers[key] = value; } } // 第二步:读取请求体 string requestBody = string.Empty; if (headers.TryGetValue("Transfer-Encoding", out var transferEncoding) && transferEncoding.Equals("chunked", StringComparison.OrdinalIgnoreCase)) { // 处理分块编码的请求体 requestBody = await ReadChunkedBodyAsync(reader); } else if (headers.TryGetValue("Content-Length", out var lengthStr) && int.TryParse(lengthStr, out int contentLength)) { // 处理带Content-Length的请求体 char[] buffer = new char[contentLength]; int totalRead = 0; while (totalRead < contentLength) { int readBytes = await reader.ReadAsync(buffer, totalRead, contentLength - totalRead); if (readBytes == 0) break; // 提前断开,做异常处理 totalRead += readBytes; } requestBody = new string(buffer, 0, totalRead); } else { // 读取到流结束(适用于HTTP/1.0无长度头的情况) var bodyBuilder = new StringBuilder(); char[] buffer = new char[4096]; // 用4KB缓冲区平衡性能和内存 int readBytes; while ((readBytes = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0) { bodyBuilder.Append(buffer, 0, readBytes); } requestBody = bodyBuilder.ToString(); } // 这里写你的业务逻辑,比如解析POST数据 // ... other stuff ... } } // 处理HTTP分块编码的辅助方法 private async Task<string> ReadChunkedBodyAsync(StreamReader reader) { var chunkBuilder = new StringBuilder(); while (true) { // 读取块大小(十六进制格式) string chunkSizeLine = await reader.ReadLineAsync(); if (string.IsNullOrEmpty(chunkSizeLine)) break; if (!int.TryParse(chunkSizeLine.Trim(), System.Globalization.NumberStyles.HexNumber, null, out int chunkSize)) break; if (chunkSize == 0) break; // 分块结束标记 // 读取当前块的内容 char[] chunkBuffer = new char[chunkSize]; int totalRead = 0; while (totalRead < chunkSize) { int readBytes = await reader.ReadAsync(chunkBuffer, totalRead, chunkSize - totalRead); if (readBytes == 0) break; totalRead += readBytes; } chunkBuilder.Append(chunkBuffer, 0, totalRead); // 跳过块末尾的CRLF分隔符 await reader.ReadLineAsync(); } // 跳过结束块后的CRLF await reader.ReadLineAsync(); return chunkBuilder.ToString(); }
关键注意点
- 全程异步:所有读取操作都用
Async后缀的方法,彻底避免UWP线程阻塞导致的死锁或UI卡顿问题 - 分块编码必须处理:这是HTTP/1.1中无
Content-Length时的标准传输方式,直接读流会拿到带块大小标记的无效数据 - 资源自动释放:用
using包裹套接字和流对象,UWP沙箱对资源泄漏的容忍度很低,必须严格处理 - 权限声明:别忘了在
Package.appxmanifest里开启Internet(Client & Server)或Private Networks(Client & Server)权限,否则套接字根本连不上
内容的提问来源于stack exchange,提问作者andyt_3185834
相关产品推荐
相关产品推荐

