C#异步TCP Listener Socket无法接受连接问题求助
问题产生原因
- 核心逻辑漏洞:
Main方法执行完tl.BeginAcceptTcpClient(OnCompleteTCP, tl);后没有任何阻塞逻辑,控制台应用主进程会直接终止,所有异步回调没有机会被触发,自然无法接受连接。 - 单次监听缺陷:接受完第一个客户端连接后没有重新调用
BeginAcceptTcpClient,只能处理最多一次连接请求,后续客户端无法接入。 - 并发资源冲突:全局声明的
TcpClient和byte[] Mybuffer是共享变量,多客户端连接时会出现资源覆盖、数据串包的问题。 - 数据解析错误:读取到指定长度的字节后直接将整个缓冲区转成字符串,会输出大量无效空字符,应该仅对实际读取到的字节长度做转换。
修复方案
按照以下逻辑调整代码即可解决问题:
- 为
Main方法添加阻塞逻辑,避免主进程直接退出 - 在连接接收回调末尾重新发起异步监听,支持多客户端接入
- 移除全局共享的连接和缓冲区对象,每个连接使用独立资源避免并发冲突
- 修正字节转字符串的逻辑,仅处理实际收到的字节长度
- 可选优化:监听IP改为
IPAddress.Any,自动适配本机所有网卡,不需要写死固定IP
修复后完整代码如下:
using System; using System.Net; using System.Net.Sockets; using System.Text; class Program { private static void PrintUsageInfo() { } static void Main(string[] args) { TcpListener tl = new TcpListener(IPAddress.Any, 8008); tl.Start(); tl.BeginAcceptTcpClient(OnCompleteTCP, tl); // 阻塞主进程,防止程序直接退出 Console.WriteLine("服务端已启动,端口8008,按任意键退出..."); Console.ReadKey(); tl.Stop(); } static void OnCompleteReadData(IAsyncResult isa) { int countreadbytes = 0; // 每个连接使用独立的状态对象,避免共享冲突 var state = (ConnectionState)isa.AsyncState; try { countreadbytes = state.Client.GetStream().EndRead(isa); if (countreadbytes == 0) { Console.WriteLine("USER Disconnected"); state.Client.Close(); return; } // 仅转换实际收到的字节 Console.Write(Encoding.ASCII.GetString(state.Buffer, 0, countreadbytes)); // 继续监听当前连接的新数据 state.Client.GetStream().BeginRead(state.Buffer, 0, state.Buffer.Length, OnCompleteReadData, state); } catch (Exception ex) { Console.WriteLine(ex.ToString()); state.Client.Close(); } } static void OnCompleteTCP(IAsyncResult isa) { TcpListener tcpl = (TcpListener)isa.AsyncState; try { // 重新发起监听,接收下一个客户端连接 tcpl.BeginAcceptTcpClient(OnCompleteTCP, tcpl); TcpClient newClient = tcpl.EndAcceptTcpClient(isa); Console.WriteLine("新客户端接入"); // 为每个新连接创建独立的缓冲区 var state = new ConnectionState() { Client = newClient, Buffer = new byte[4096] }; newClient.GetStream().BeginRead(state.Buffer, 0, state.Buffer.Length, OnCompleteReadData, state); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } // 自定义连接状态类,存储每个连接的独立资源 class ConnectionState { public TcpClient Client { get; set; } public byte[] Buffer { get; set; } } }
内容的提问来源于stack exchange,提问作者Amir Ahmadabadiha
相关产品推荐
相关产品推荐

