C# TcpListener第二次调用时出现连接报错问题求助
问题分析与解决方案
核心问题点
- 旧连接资源未彻底释放:重置设备后,原后台线程仍在尝试从已断开的
NetworkStream读取数据,且未关闭旧的TcpClient和NetworkStream,导致资源泄漏与冲突。 - 多线程冲突:每次重连都新建
BackgroundWorker,但旧线程未终止,多个线程同时操作网络资源,引发异常。 - 异常处理不完整:仅捕获
SocketException,未处理连接关闭时的IOException,且捕获异常后未终止当前读取循环,继续执行无效操作。 - TcpListener停止后未清理:直接调用
server.Stop()后,未等待旧线程退出就重连,残留线程会继续占用端口或尝试读取无效流。
修复后的代码示例
1. 添加全局控制变量
在窗体类中添加取消标志,用于通知后台线程终止:
private bool _isStopping = false; private BackgroundWorker bwConnector; private TcpListener server; private TcpClient client; private NetworkStream stream; private int anarg = 0;
2. 重写初始化方法conn_init
确保旧线程终止后再创建新线程,避免多线程冲突:
private void conn_init() { // 终止旧线程(如果存在) if (bwConnector != null && bwConnector.IsBusy) { _isStopping = true; bwConnector.CancelAsync(); // 等待旧线程完全退出 while (bwConnector.IsBusy) { Thread.Sleep(50); } _isStopping = false; } bwConnector = new BackgroundWorker(); bwConnector.WorkerSupportsCancellation = true; // 开启取消支持 bwConnector.DoWork += (sender, args) => { if (!args.Cancel) { conn_function(anarg); } }; bwConnector.RunWorkerAsync(); }
3. 重写连接处理方法conn_function
完善资源释放、异常处理与终止逻辑:
void conn_function(int a_param) { try { Int32 port = 7050; // 开启端口复用,避免TIME_WAIT状态导致无法重绑定 var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); server = new TcpListener(socket); server.LocalEndpoint = new IPEndPoint(IPAddress.Any, port); server.Start(); Byte[] bytes = new Byte[256]; while (!_isStopping) { if (_isStopping) break; // 等待客户端连接,同时检查终止标志 client = server.AcceptTcpClient(); stream = client.GetStream(); int i = 1; while (i != 0 && !_isStopping) { try { i = stream.Read(bytes, 0, bytes.Length); stream.Flush(); } catch (SocketException e) { richTextBox1.Invoke(new EventHandler(delegate { richTextBox1.Text = $"Socket异常: {e.Message}"; })); // 异常后终止当前连接循环 i = 0; break; } catch (IOException e) { richTextBox1.Invoke(new EventHandler(delegate { richTextBox1.Text = $"IO异常: {e.Message}"; })); i = 0; break; } if (i > 0) { string data = System.Text.Encoding.UTF8.GetString(bytes, 0, i); // 处理读取到的数据 } } // 清理当前连接资源 client?.Close(); stream?.Close(); } } finally { // 最终全局资源清理 server?.Stop(); client?.Close(); stream?.Close(); } }
4. 修改断开后的重连逻辑
确保先终止旧线程、清理资源,再触发重连:
_isStopping = true; server?.Stop(); client?.Close(); stream?.Close(); // 等待资源释放 Thread.Sleep(100); _isStopping = false; conn_init();
关键修复说明
- 端口复用:通过
SocketOptionName.ReuseAddress设置,避免TcpListener停止后端口处于TIME_WAIT状态,无法立即重绑定。 - 线程终止控制:通过
_isStopping标志和BackgroundWorker.CancelAsync(),确保旧线程能及时退出,避免残留操作。 - 资源强制清理:在异常、循环结束、线程终止时,都显式关闭
TcpClient和NetworkStream,彻底释放网络资源。 - 完善异常捕获:新增
IOException捕获,覆盖连接被强制关闭的场景,避免未处理异常导致程序崩溃。
内容的提问来源于stack exchange,提问作者Ahmet
相关产品推荐
相关产品推荐

