C# асинхронный прослушиватель UDP SocketException

У меня есть довольно простой асинхронный прослушиватель 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().


person chezy525    schedule 04.03.2011    source источник


Ответы (2)


Из этой ветки форума похоже, что сокет UDP также получает сообщения ICMP и генерирует исключения при их получении. Возможно, это отлично подходит для обновления статуса низкого уровня, но меня это раздражает.

Сначала определите магическое число

public const int SIO_UDP_CONNRESET = -1744830452;

Затем установите элемент управления ввода-вывода низкого уровня, чтобы игнорировать эти сообщения:

var client = new UdpClient(endpoint);
client.Client.IOControl(
    (IOControlCode)SIO_UDP_CONNRESET, 
    new byte[] { 0, 0, 0, 0 }, 
    null
);
person Kyle Lahnakoski    schedule 03.02.2012
comment
Хороший человек! У Hi была такая же проблема с получением сообщений ICMP и созданием исключений при их получении. Который решается вашим трюком с кодированием! - person Kevan; 08.03.2013
comment
@ Кайл, наконец-то я смог полностью протестировать это! Казалось бы, это было фактической основной причиной исключения. Для справки, в итоге я использовал как ваш ответ, так и ответ Джима, так что даже если есть исключение, прослушиватель перезапускается. - person chezy525; 31.07.2013
comment
Неработающей ссылке. Этот ответ следует изменить, чтобы либо обновить ссылку, либо включить информацию, на которую указывает ссылка. - person Nate Zaugg; 02.03.2014

Я видел эту ошибку с UDP, если пакет каким-то образом усекается или иным образом не доставляется полностью. По крайней мере, я думаю, так и происходит. Мне никогда не удавалось надежно воспроизвести его.

Я бы посоветовал вам поймать SocketException, зарегистрировать его (если хотите), а затем избавиться от этого сокета. Затем снова вызовите Starter:

catch (SocketException)
{
    // log error
    udpSock.Close();
    Starter();
}
person Jim Mischel    schedule 04.03.2011
comment
Это то, что я в итоге сделал, но мне все же хотелось бы знать, что на самом деле вызывает это исключение (т.е. доказать, что вы считаете правильным). - person chezy525; 30.03.2011
comment
@ chezy525 Я полагаю, что эти исключения сокетов обычно возникают из-за пункта назначения / порта ICMP / и т. д. недостижимые сообщения на вашем сокете. Как вы его получите, если просто слушаете, я не уверен. Просто мысль. - person Kongress; 30.06.2011
comment
попробуйте включить трассировку system.net и посмотреть, что там происходит - person taher chhabrawala; 03.02.2012