远程主机强制关闭了一个已存在的连接。

20

我需要从异步套接字服务器获取UDP数据报,但我的应用程序出现了异常:

问题出现在这里:

Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);

完整的源代码:

class Program
    {
        static void Main(string[] args)
        {
            const int PORT = 30485;
            IPAddress IP;
            IPAddress.TryParse("92.56.23.87", out IP);
            // This constructor arbitrarily assigns the local port number.
            UdpClient udpClient = new UdpClient(PORT);
            Socket receiveSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            try
            {
                udpClient.Connect("92.56.23.87", PORT);

                if (udpClient.Client.Connected)
                    Console.WriteLine("Connected.");

                // Sends a message to the host to which you have connected.
                Byte[] sendBytes = Encoding.ASCII.GetBytes("CONNECT");

                udpClient.Send(sendBytes, sendBytes.Length);

                //IPEndPoint object will allow us to read datagrams sent from any source.
                IPEndPoint RemoteIpEndPoint = new IPEndPoint(IP, PORT);

                // Blocks until a message returns on this socket from a remote host.
                Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
                string returnData = Encoding.ASCII.GetString(receiveBytes);
                // Uses the IPEndPoint object to determine which of these two hosts responded.
                Console.WriteLine("This is the message you received " + returnData.ToString());
                Console.WriteLine("This message was sent from " + RemoteIpEndPoint.Address.ToString() + " on their port number " + RemoteIpEndPoint.Port.ToString());

                udpClient.Close();

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());

            }
        }
    }

例外:

Connected.
System.Net.Sockets.SocketException (0x80004005): An existing connection
was forcibly closed by the remote host at System.Net.Sockets.Socket.ReceiveFrom(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, EndPoint& remoteEP) at ystem.Net.Sockets.UdpClient.Receive(IPEndPoint& remoteEP) at ConsoleApplication7.Program.Main(String[] args) in c:\users\user\documents\visual studio 2010\Projects\ConsoleApplication7\ConsoleApplication7\Program.cs

有什么问题可能出现?


为了提供更多信息,我在这个网页购买了私人socks连接: http://rapidsocks.com/。该服务给我提供了一个IP和端口列表,实际上并不是代理,只是从服务器池中返回一个proxyIP:proxyPort的连接...

如何从服务器获取带有代理IP和端口的答案?


好问题 - 也许如果您告诉我们更多信息 - 异常抛出在哪里?您是否在控制台上看到任何“调试消息”?您能展示一下测试运行吗? - Random Dev
请在 catch 块中打印 stackTrace,并查看异常抛出的行。 - Zenwalker
另一端是否正常工作?你能检查一下吗? - Random Dev
这里抛出了异常: Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint); 异常信息如下: 远程主机强制关闭了一个现有的连接。 - Johnny
ckoening - 你是指在服务器端吗? - Johnny
如果是的话,我认为它可以正常工作。我买了一双袜子,试图连接服务器以获取UDP数据包(我需要IP和端口)。从逻辑上讲,我需要一些形式: 第一次连接92.56.23.87:30485 > 76.43.126.6:1080 第二次连接92.56.23.87:30485 > 78.67.54.210:5847 - Johnny
2个回答

54
在UDP领域中,发生这种情况的一种方式是当您向主机发送UDP数据包时,远程主机在该端口上没有侦听器,并反弹一个ICMP无法到达主机的消息作为响应。
简单来说,这个异常告诉你far-end那个端口上没有进程在监听。
更新:您可以使用以下代码避免这种行为:
  var udpClient = new UdpClient();
  uint IOC_IN = 0x80000000;
  uint IOC_VENDOR = 0x18000000;
  uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
  udpClient.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);

根据 Microsoft 文章 263823 的描述(截至2019年),Windows 2000中的用户数据报协议(UDP)程序可能无法工作,并可能生成WSAECONNRESET响应。

症状 在 Windows 2000 中,使用 User Datagram Protocol (UDP) 发送数据报可能导致无法工作并生成 WSAECONNRESET 响应。

原因 如果使用 sendto 函数发送数据报结果返回 "ICMP 端口不可达" 响应,并且 select 函数已设置为 readfds,则该程序将返回1,并且后续调用 recvfrom 函数将无法使用 WSAECONNRESET(10054)错误响应。在 Microsoft Windows NT 4.0 中,此情况会导致 select 函数被阻塞或超时。

解决方法 在 Windows 2000 中引入了一种名为“SIO_UDP_CONNRESET”的新 sockets IOCTL。当使用此 IOCTL 时,必须专门针对 Windows 2000 重写程序以获取原始的 Windows NT 4.0 行为。Windows NT 4.0、Microsoft Windows 95 和 Microsoft Windows 98 不支持此新的 IOCTL。除了重写您的应用程序外,您还需要参考本文下面提到的热修复程序。


对我而言,这解决了在向无监听器的套接字发送数据报后,Receive() 引发异常的问题。我可以在没有监听器的情况下多次 Send() 数据报而不出现错误,但随后 Receive() 将不再起作用。非常模糊的错误行为。这个解决方案同样也很模糊,但它非常有帮助!+1 - Roland
在现场设备突然更改IP地址而UDP数据包仍未完成时,会出现此错误。这个修复了它。 - SteveGSD
@uingtea,所示的 IOCTL 不应直接导致高 CPU,它应该被调用并立即返回。如果您看到 CPU 问题,您可能需要检查代码中是否存在高频发送循环。 - Cameron
没事了,是我代码里的另一个错误。 - uingtea

4

这个错误信息太泛泛了,可能意味着任何事情。现在需要使用低级网络流量嗅探器来过滤出实际发生了什么。在服务器上添加额外的错误处理try catch块和良好的日志记录始终是一个不错的起点。


这是一个带有代理服务的服务器,它是私有的,并且如何在内部获取IP:Port的信息写在RFC1928中。 - Johnny
连接在对 CONNECT 的回复中,BND.PORT 包含服务器分配给连接到目标主机的端口号,而 BND.ADDR 包含关联的 IP 地址。提供的 BND.ADDR 通常与客户端用于到达 SOCKS 服务器的 IP 地址不同,因为此类服务器经常具有多个接口。预期 SOCKS 服务器将使用 DST.ADDR 和 DST.PORT,以及客户端侧源地址和端口来评估 CONNECT 请求。 - Johnny
服务器或代理是否有任何异常? - CodingBarfield
我不知道,对我来说这是黑盒服务器。 服务器支持给了我一个PHP代码示例: <?php $ch=curl_init(""); @curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 返回传输的字符串而不是直接输出它 @curl_setopt($ch, CURLOPT_VERBOSE, 0); @curl_setopt($ch, CURLOPT_HEADER, 0); // 禁用头信息 @curl_setopt($ch, CURLOPT_PROXY, "10.0.0.10:35000"); // 我们SOCKS5的IP和端口 @curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); // 启用SOCKS5 $x=@curl_exec($ch); curl_close($ch); echo $x; ?> - Johnny
1
为什么这被标记为答案?下面有另一个回答详细解释了这个特定的问题。 - leviathanbadger
如果在 .Net 中,服务器端出现未处理的异常但未设置将异常发送回客户端,则这是预期行为。然而,尽管深入了解 UDP 的工作方式很好,但可能并不实用。 - CodingBarfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接