C# UWP中StreamReader通过StreamSocketListener始终接收null求助
UWP Socket 通信读取返回 Null 问题分析与修复
核心问题排查
你的代码出现接收端读取返回 Null 的根本原因是发送端数据未实际写入网络流,同时存在多处异步编程和逻辑错误:
1. StreamWriter 未刷新缓冲区
StreamWriter 默认会缓存数据,你调用 sw.WriteLine() 后没有手动刷新或开启自动刷新,导致数据一直停留在本地缓冲区,未发送到接收端。随后直接关闭 StreamSocket,缓冲区数据被丢弃,接收端自然读取不到内容,返回 Null。
2. Async Void 误用
SendInfos 和 onConnectionReceived 使用了 async void:
- 非事件场景下的
async void无法被等待,异常也无法被捕获,会导致发送操作还未完成,线程就已结束。 - 主线程的
Task.WaitAll无法等待async void方法的异步逻辑完成。
3. 输入结束判断逻辑错误
代码中判断输入结束的条件是 s == ";;;;",但提示用户输入 ";;;" 结束,导致用户输入 ;;; 时会被当作普通内容加入列表,而非触发结束流程。
4. 低效且不可靠的 Thread.Sleep 等待
用 Thread.Sleep 来同步两端操作是不可靠的,依赖固定等待时间会导致时序问题,应该用异步原语(如 TaskCompletionSource)来等待操作完成。
5. 主线程任务等待逻辑错误
Task.Factory.StartNew(async () => { ... }) 返回的是 Task<Task>,Task.WaitAll 只会等待外层任务完成,不会等待内部异步操作结束,导致主线程提前退出。
修复后的完整代码
using System; using System.IO; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Windows.Networking; using Windows.Networking.Sockets; namespace UWPConsoleApp { class UWPConsoleApp { static async Task Main(string[] args) { List<string> toSend = new List<string>(); bool end = false; do { Console.WriteLine("Please write something to send to the other task (write ';;;' to end)"); string s = Console.ReadLine(); if (s != ";;;") { toSend.Add(s); Console.WriteLine($"The list now contains {toSend.Count} lines"); } else { if (toSend.Count == 0) { Console.WriteLine("WARNING: you must insert at least one line before going on"); continue; } end = true; } } while (!end); List<string> received = null; var receiverTask = Task.Run(async () => { ThreadReceiver tr = new ThreadReceiver(); received = await tr.ReceiveInfos(); }); // 先启动接收端,再启动发送端 await Task.Delay(1000); var senderTask = Task.Run(async () => { ThreadSender ts = new ThreadSender(); ts.buffer = toSend; Console.WriteLine("(T1) starting send..."); await ts.SendInfos(); }); await Task.WhenAll(senderTask, receiverTask); Console.WriteLine("Done."); if (received != null) { Console.WriteLine("Received content:"); foreach (var line in received) { Console.WriteLine($"- {line}"); } } Console.ReadKey(); } } class ThreadSender { public List<string> buffer; private StreamSocket ss; public ThreadSender() { buffer = new List<string>(); ss = new StreamSocket(); } public async Task SendInfos() { HostName hn = new HostName("localhost"); await ss.ConnectAsync(hn, "3000"); // 开启自动刷新,确保数据实时发送 using var sw = new StreamWriter(ss.OutputStream.AsStreamForWrite()) { AutoFlush = true }; Console.WriteLine($"(T1) Sending line count: {buffer.Count}"); await sw.WriteLineAsync(buffer.Count.ToString()); foreach (string line in buffer) { Console.WriteLine("(T1) sending line: {0}", line); await sw.WriteLineAsync(line); } Console.WriteLine("(T1) closing connection"); ss.Dispose(); } } class ThreadReceiver { public List<string> buffer = new List<string>(); private StreamSocketListener ssl; private readonly TaskCompletionSource<bool> _tcs = new TaskCompletionSource<bool>(); private bool _error = false; public ThreadReceiver() { ssl = new StreamSocketListener(); ssl.ConnectionReceived += OnConnectionReceived; } public async Task<List<string>> ReceiveInfos() { await ssl.BindServiceNameAsync("3000"); Console.WriteLine("(T2) waiting for connections..."); // 用TaskCompletionSource异步等待连接处理完成 await _tcs.Task; if (_error) { Console.WriteLine("(T2) closing connection (error occurred)"); return null; } return buffer; } private async void OnConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) { Console.WriteLine("received an incoming connection"); try { using var sr = new StreamReader(args.Socket.InputStream.AsStreamForRead()); string receivedCountString = await sr.ReadLineAsync(); if (receivedCountString == null) { Console.Error.WriteLine("(T2) ERROR: received null value"); _error = true; _tcs.SetResult(true); return; } if (!int.TryParse(receivedCountString, out int nToRead)) { Console.Error.WriteLine("(T2) ERROR: invalid count format"); _error = true; _tcs.SetResult(true); return; } while (nToRead > 0) { string receivedString = await sr.ReadLineAsync(); if (receivedString == null) { Console.Error.WriteLine("(T2) ERROR: received null value"); _error = true; _tcs.SetResult(true); return; } buffer.Add(receivedString); nToRead--; } } catch (Exception ex) { Console.Error.WriteLine($"(T2) ERROR: {ex.Message}"); _error = true; } finally { _tcs.SetResult(true); ssl.Dispose(); } } } }
关键修复点说明
- StreamWriter 自动刷新:设置
AutoFlush = true,确保每次写入后立即将数据发送到网络流。 - 替换 Async Void 为 Async Task:
SendInfos改为async Task,让调用方可以等待发送操作完成。 - 修复输入判断逻辑:将结束条件改为判断
s == ";;;",与提示一致。 - 用 TaskCompletionSource 替代 Thread.Sleep 循环:接收端通过异步原语等待连接处理完成,避免低效且不可靠的睡眠等待。
- 主线程改用 Async Main:UWP 控制台支持
async Task Main,直接使用异步等待替代Task.WaitAll,避免线程阻塞问题。 - 添加异常处理:接收端增加异常捕获,避免未处理异常导致程序崩溃。
- 使用 using 语句管理资源:自动释放流资源,避免资源泄漏。
内容的提问来源于stack exchange,提问作者programmatoroseduto
相关产品推荐
相关产品推荐

