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

C# UDP转TCP程序报错10054:远程主机强制关闭现有连接

问题背景

我编写了一款简易数据转发程序,核心逻辑为监听指定UDP端口接收数据,过滤掉首字节为0x02的数据包后,将其余数据转发至目标TCP地址。在CMD中启动程序并传入监听端口、目标TCP地址两个参数时,程序运行抛出未处理异常。
异常信息:

Unhandled exception. System.Net.Sockets.SocketException (10054): An existing connection was forcibly closed by the remote host.
(中文释义:未处理异常。System.Net.Sockets.SocketException (10054):远程主机强迫关闭了一个现有的连接)
异常堆栈指向程序Program.Main(String[] args)方法,原实现代码如下:

static void Main(string[] args)
{
    IPEndPoint listening = new IPEndPoint(IPAddress.Any, int.Parse(args[0]));
    UdpClient udp = new UdpClient(listening);
    System.Console.WriteLine($"Listening on {listening}");

    var parts = args[1].Split(':');

    IPEndPoint newrelic = new IPEndPoint(IPAddress.Parse(parts[0]), int.Parse(parts[1]));
    TcpClient tcp = new TcpClient();

    bool stop=false;
    Console.CancelKeyPress+=(object? sender, ConsoleCancelEventArgs e) =>
    {
        stop = true;
        tcp.Dispose();
        udp.Close();
        udp.Dispose();
    };
    tcp.Connect(newrelic);
    System.Console.WriteLine($"Connected to {newrelic}");
    var dummy = new IPEndPoint(IPAddress.Any,0);
    while (!stop)
    {
       
            var bytes = udp.Receive(ref dummy);
            if (bytes.Length > 0)
            {
                if (bytes[0] != 0x02)
                {
                    System.Console.WriteLine($"Received {bytes.Length} bytes");
                    var sent = tcp.Client.Send(bytes);
                }
            }
        }
}
异常产生原因
  • 核心原因是TCP连接可靠性处理缺失:程序仅在启动时建立一次TCP连接,后续全程复用该连接转发数据。一旦出现目标TCP服务重启、网络闪断、服务端空闲超时主动断开连接、中间链路丢包导致连接失效等情况,程序不会主动感知到连接已断开,调用Send方法发送数据时就会触发10054错误,且代码没有任何异常捕获逻辑,错误直接抛出导致程序崩溃。
  • 隐藏触发点:Windows平台下UDP套接字默认会将收到的ICMP端口不可达报文转换为SocketException抛出,UDP本身是无连接协议,这类错误和业务逻辑无关,但原代码没有做屏蔽处理,也可能在UDP接收环节触发同类10054异常。
  • 退出逻辑存在竞态:触发Ctrl+C退出时,事件处理中直接释放TCP、UDP对象,但此时收发循环可能刚好执行到发送/接收逻辑,调用已释放的套接字对象也会触发同类异常。
修复方案

针对上述问题做以下调整即可解决:

  1. 关闭UDP套接字的ICMP错误抛出,屏蔽UDP层面的无关10054错误
  2. 增加TCP连接状态检测逻辑,连接断开时自动重试建立连接,不需要人工重启程序
  3. 为收发逻辑增加异常捕获,遇到非退出类错误时记录日志后继续运行,不直接崩溃
  4. 调整退出逻辑,触发退出信号后先终止循环,再统一释放资源,避免竞态问题

修复后的完整代码:

static void Main(string[] args)
{
    int listenPort = int.Parse(args[0]);
    IPEndPoint listening = new IPEndPoint(IPAddress.Any, listenPort);
    UdpClient udp = new UdpClient(listening);
    // 屏蔽UDP层面的ICMP端口不可达错误
    const int SIO_UDP_CONNRESET = -1744830452;
    udp.Client.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
    Console.WriteLine($"Listening on {listening}");

    var parts = args[1].Split(':');
    IPEndPoint targetEndpoint = new IPEndPoint(IPAddress.Parse(parts[0]), int.Parse(parts[1]));
    TcpClient tcp = new TcpClient();
    bool stop = false;

    Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) =>
    {
        e.Cancel = true;
        stop = true;
    };

    // 封装TCP自动重连逻辑
    void EnsureTcpConnected()
    {
        if (tcp.Connected) return;
        tcp.Dispose();
        tcp = new TcpClient();
        while (!stop && !tcp.Connected)
        {
            try
            {
                tcp.Connect(targetEndpoint);
                Console.WriteLine($"Connected to target {targetEndpoint}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Connect to target failed, retry in 3s: {ex.Message}");
                Thread.Sleep(3000);
            }
        }
    }

    try
    {
        EnsureTcpConnected();
        var remoteUdpEp = new IPEndPoint(IPAddress.Any, 0);
        while (!stop)
        {
            try
            {
                var bytes = udp.Receive(ref remoteUdpEp);
                if (bytes.Length == 0 || bytes[0] == 0x02) continue;
                
                EnsureTcpConnected();
                if (!tcp.Connected) continue;

                Console.WriteLine($"Received {bytes.Length} bytes, forwarding to target");
                tcp.Client.Send(bytes);
            }
            catch (SocketException ex) when (ex.SocketErrorCode == SocketError.ConnectionReset || ex.SocketErrorCode == SocketError.Disconnecting)
            {
                Console.WriteLine($"TCP connection lost, will reconnect: {ex.Message}");
                tcp.Close();
            }
            catch (Exception ex)
            {
                if (!stop) Console.WriteLine($"Forward error: {ex.Message}");
            }
        }
    }
    finally
    {
        // 循环退出后统一释放资源
        udp.Dispose();
        tcp.Dispose();
        Console.WriteLine("Program exited.");
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 00:32:23