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

C#中UdpClient.Receive报‘远程主机强制关闭连接’异常求助

解决UDP查询游戏服务器时的“远程主机强制关闭现有连接”异常

首先咱们得先搞清楚这个异常的根源:UDP本身是无连接协议,但你调用了udpClient.Connect(IP, Port),这会让你的UDP客户端绑定到指定的远程端点,相当于在客户端层面做了一个“虚拟连接”。当目标服务器下线或者拒绝响应时,系统就会返回这个强制关闭连接的错误——毕竟这个虚拟连接已经失效了。

下面给你几个具体的解决思路和代码示例:

1. 移除Connect()调用,改用无连接的UDP通信

既然UDP不需要提前建立连接,直接发送和接收数据包就好,这样能避免因虚拟连接失效触发的异常。修改后的QueryServer方法可以这样写:

private void QueryServer(IPAddress IP, int Port)
{
    // 每次查询创建新的UdpClient实例,避免复用带来的状态问题
    using (UdpClient udpClient = new UdpClient())
    {
        try
        {
            // 设置接收超时,避免长时间阻塞
            udpClient.Client.ReceiveTimeout = 3000; // 3秒超时
            IPEndPoint remoteEndPoint = new IPEndPoint(IP, Port);
            
            // 直接发送数据包,不需要提前Connect
            Byte[] sendBytes = Encoding.ASCII.GetBytes("你的查询指令");
            udpClient.Send(sendBytes, sendBytes.Length, remoteEndPoint);
            
            // 接收响应
            Byte[] receiveBytes = udpClient.Receive(ref remoteEndPoint);
            string response = Encoding.ASCII.GetString(receiveBytes);
            
            // 处理响应,更新ListView(注意跨线程操作UI)
            UpdateListView(IP, Port, "在线", response);
        }
        catch (SocketException ex)
        {
            // 捕获超时或连接相关异常,标记服务器为下线
            if (ex.SocketErrorCode == SocketError.TimedOut || 
                ex.SocketErrorCode == SocketError.ConnectionReset)
            {
                UpdateListView(IP, Port, "离线", "无响应");
            }
            else
            {
                // 处理其他异常
                Console.WriteLine($"查询服务器{IP}:{Port}时出错:{ex.Message}");
            }
        }
    }
}

2. 针对异常做针对性处理(如果必须保留Connect())

如果你因为某些原因必须使用Connect(),那一定要在代码中捕获这个特定的SocketException,并将其视为服务器离线的信号:

private void QueryServer(IPAddress IP, int Port)
{
    using (UdpClient udpClient = new UdpClient())
    {
        try
        {
            udpClient.Connect(IP, Port);
            udpClient.Client.ReceiveTimeout = 3000;
            
            Byte[] sendBytes = Encoding.ASCII.GetBytes("你的查询指令");
            udpClient.Send(sendBytes, sendBytes.Length);
            
            Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
            // 处理在线逻辑
        }
        catch (SocketException ex)
        {
            // 匹配远程主机强制关闭连接的错误码
            if (ex.SocketErrorCode == SocketError.ConnectionReset)
            {
                // 标记服务器为离线,更新ListView
                UpdateServerStatus(IP, Port, false);
            }
            else
            {
                // 处理其他错误
                throw;
            }
        }
    }
}

3. 额外的最佳实践

  • 避免复用UdpClient实例:每个查询用新的实例,避免之前的连接状态干扰后续操作。
  • 跨线程更新UI:如果QueryServer是在后台线程执行的,更新ListView时一定要用Invoke或BeginInvoke,避免UI线程异常。
  • 批量查询时加延迟:如果一次性查询多个服务器,不要同时发送所有请求,适当加小延迟,避免被目标网络限制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:23:40