C#异步UDP监听器SocketException

10

我有一个非常简单的异步UDP监听器,设置为服务,并且它一直运作得很好,但最近它因为一个SocketException而崩溃了:An existing connection was forcibly closed by the remote host。 我有三个问题:

  1. 这是什么原因?(我认为UDP套接字没有连接)
  2. 如何复制它以进行测试目的?
  3. 如何干净地处理异常,使一切都可以继续工作?

我的代码大概长这样:

private Socket udpSock;
private byte[] buffer;
public void Starter(){
    //Setup the socket and message buffer
    udpSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    udpSock.Bind(new IPEndPoint(IPAddress.Any, 12345));
    buffer = new byte[1024];

    //Start listening for a new message.
    EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);
    udpSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, udpSock);
}

private void DoReceiveFrom(IAsyncResult iar){
    try{
        //Get the received message.
        Socket recvSock = (Socket)iar.AsyncState;
        EndPoint clientEP = new IPEndPoint(IPAddress.Any, 0);
        int msgLen = recvSock.EndReceiveFrom(iar, ref clientEP);
        byte[] localMsg = new byte[msgLen];
        Array.Copy(buffer, localMsg, msgLen);

        //Start listening for a new message.
        EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);
        udpSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, udpSock);

        //Handle the received message
        Console.WriteLine("Recieved {0} bytes from {1}:{2}",
                          msgLen,
                          ((IPEndPoint)clientEP).Address,
                          ((IPEndPoint)clientEP).Port);
        //Do other, more interesting, things with the received message.
    } catch (ObjectDisposedException){
        //expected termination exception on a closed socket.
        // ...I'm open to suggestions on a better way of doing this.
    }
}

异常是在recvSock.EndReceiveFrom()行抛出的。

2个回答

19

根据这个论坛贴子,UDP套接字似乎也会收到ICMP消息,并在接收到它们时抛出异常。也许这对于低级别的状态更新很有用,但我发现它很烦人。

首先,定义魔数。

public const int SIO_UDP_CONNRESET = -1744830452;
然后将低级IO控件设置为忽略这些消息:
var client = new UdpClient(endpoint);
client.Client.IOControl(
    (IOControlCode)SIO_UDP_CONNRESET, 
    new byte[] { 0, 0, 0, 0 }, 
    null
);

太棒了!我曾经遇到过接收 ICMP 消息并在接收时抛出异常的问题。但是你的编码技巧解决了这个问题! - Kevan
@Kyle,我终于有时间全面测试了!看起来这才是异常的真正根本原因。为了参考,我最终采用了你和Jim的答案,这样即使出现异常,监听器也会重新启动。 - chezy525
损坏的链接。这个答案应该被更改,要么更新链接,要么包含链接指向的信息。 - Nate Zaugg

2

如果数据包被截断或未完全传递,我曾经在UDP中看到过这种错误。至少我认为是这样的。我从来没有能够可靠地复制它。

我建议你捕获SocketException,记录它(如果需要),然后处理该套接字。然后再次调用Starter

catch (SocketException)
{
    // log error
    udpSock.Close();
    Starter();
}

这就是我最终做的事情,但我仍然想知道是什么导致了这个异常(即证明你认为正确的东西)。 - chezy525
@chezy525 我相信这些套接字异常通常是由于收到你的套接字上的 ICMP“目标/端口等不可达”消息引起的。如果您只是在监听,那么如何获得这种异常我不太确定。这只是一个想法。 - Kongress
尝试启用系统网络跟踪并查看底层情况。 - taher chhabrawala

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