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

C# TcpListener第二次调用时出现连接报错问题求助

问题分析与解决方案

核心问题点

  1. 旧连接资源未彻底释放:重置设备后,原后台线程仍在尝试从已断开的NetworkStream读取数据,且未关闭旧的TcpClient和NetworkStream,导致资源泄漏与冲突。
  2. 多线程冲突:每次重连都新建BackgroundWorker,但旧线程未终止,多个线程同时操作网络资源,引发异常。
  3. 异常处理不完整:仅捕获SocketException,未处理连接关闭时的IOException,且捕获异常后未终止当前读取循环,继续执行无效操作。
  4. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:00:48