You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
            }
        }
    }
}

关键修复点说明

  1. StreamWriter 自动刷新:设置 AutoFlush = true,确保每次写入后立即将数据发送到网络流。
  2. 替换 Async Void 为 Async Task:SendInfos 改为 async Task,让调用方可以等待发送操作完成。
  3. 修复输入判断逻辑:将结束条件改为判断 s == ";;;",与提示一致。
  4. 用 TaskCompletionSource 替代 Thread.Sleep 循环:接收端通过异步原语等待连接处理完成,避免低效且不可靠的睡眠等待。
  5. 主线程改用 Async Main:UWP 控制台支持 async Task Main,直接使用异步等待替代 Task.WaitAll,避免线程阻塞问题。
  6. 添加异常处理:接收端增加异常捕获,避免未处理异常导致程序崩溃。
  7. 使用 using 语句管理资源:自动释放流资源,避免资源泄漏。

内容的提问来源于stack exchange,提问作者programmatoroseduto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 19:41:06