TcpListener/TcpClient异步代码循环后后续逻辑无法执行求助
问题原因及解决方案
核心问题
- TCP流阻塞死锁:TCP协议中,
ReadAsync返回0仅当对方主动关闭连接的输出流。当前客户端发送完数据后未关闭输出流,服务器会一直等待更多输入,卡在while循环;服务器同理未关闭输出流,客户端也会卡在读取循环,双方都无法执行循环后的代码。 - async void Main导致主线程提前退出:控制台程序使用
async void Main时,主线程不会等待异步操作完成就直接终止,这也是程序提前结束的原因之一。
修复步骤
- 将
Main函数改为async Task:C# 7.1及以上版本支持async Task Main,能让主线程等待异步操作完成。 - 客户端发送完数据后关闭输出流:告知服务器数据已发送完毕,触发服务器的
ReadAsync返回0,退出循环。 - 服务器处理完数据后关闭输出流:告知客户端响应已发送完毕,触发客户端的
ReadAsync返回0,退出循环。
修改后的代码
客户端代码
public static async Task Main() { using TcpClient client = new TcpClient("localhost", 50000); using NetworkStream stream = client.GetStream(); byte[] data = RandomNumberGenerator.GetBytes(100000); await stream.WriteAsync(data, 0, data.Length); // 关闭输出流,通知服务器数据已发送完成 client.Client.Shutdown(SocketShutdown.Send); byte[] bytes = new byte[8096]; int i; while((i = await stream.ReadAsync(bytes, 0, bytes.Length)) > 0) { Console.WriteLine(i); } Console.WriteLine("this doesnt get printed"); return; }
服务器代码
public static async Task Main() { try { TcpListener server = new TcpListener(IPAddress.Any, 50000); server.Start(); using TcpClient client = await server.AcceptTcpClientAsync(); using NetworkStream stream = client.GetStream(); byte[] bytes = new byte[8096]; byte[] return_bytes = new byte[8096]; int i; while((i = await stream.ReadAsync(bytes, 0, bytes.Length)) > 0) { await stream.WriteAsync(return_bytes, 0, return_bytes.Length); } // 关闭输出流,通知客户端响应已发送完成 client.Client.Shutdown(SocketShutdown.Send); Console.WriteLine("this doesn't get printed"); server.Stop(); } catch(Exception ex) { Console.WriteLine("port already in use"); } }
额外说明
using块会自动释放TcpClient和NetworkStream资源,无需手动调用Close()。SocketShutdown.Send仅关闭输出方向的流,输入方向仍可读取数据,确保双方能完成最后的响应读取。
内容的提问来源于stack exchange,提问作者Toby Green
相关产品推荐
相关产品推荐

