2011-03-04 9 views
6

Tengo un oyente UDP Asincrónico bastante simple, configurado como un servicio, y ha estado funcionando bastante bien por un tiempo, pero recientemente se colgó en una SocketException An existing connection was forcibly closed by the remote host. Tengo tres preguntas:C# escucha UDP Async SocketException

  1. ¿Qué está causando esto? (No creo que los sockets UDP tengan una conexión)
  2. ¿Cómo puedo duplicarlo, para realizar pruebas?
  3. ¿Cómo puedo manejar limpiamente la excepción, para que todo continúe funcionando?

Mi código es algo como lo siguiente:

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. 
    } 
} 

La excepción está siendo lanzado en la línea de recvSock.EndReceiveFrom().

Respuesta

13

De this forum thread, parece que el socket UDP también está recibiendo mensajes ICMP y lanzar excepciones cuando se reciben. Tal vez esto es genial para las actualizaciones de estado de bajo nivel, pero me pareció molesto.

En primer lugar, definir el número mágico

public const int SIO_UDP_CONNRESET = -1744830452; 

establece entonces el control io bajo nivel de ignorar estos mensajes:

var client = new UdpClient(endpoint); 
client.Client.IOControl(
    (IOControlCode)SIO_UDP_CONNRESET, 
    new byte[] { 0, 0, 0, 0 }, 
    null 
); 
+0

¡Gran hombre! Hola, tuve el mismo problema de recibir mensajes ICMP y arrojar excepciones cuando se reciben. ¡Lo cual se resuelve con tu truco de codificación! – Kevan

+0

@Kyle, ¡finalmente llegué a probar esto por completo! Parecería que esta era la causa real de la excepción. Como referencia, terminé usando tanto tu respuesta como la de Jim, de modo que incluso si hay una excepción, el oyente se reinicia. – chezy525

+0

Enlace roto. Esta respuesta se debe cambiar para actualizar el enlace o incluir la información a la que apunta el enlace. –

2

He visto ese error con UDP si un paquete se trunca de alguna manera o de lo contrario no se entrega por completo. Al menos, creo que es lo que sucede. Nunca he sido capaz de duplicarlo de manera confiable.

Le sugiero que tome el SocketException, lo logre (si lo desea) y luego deseche ese socket. A continuación, llame de nuevo Starter:

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

Esto es lo que terminé haciendo, pero todavía me gustaría saber qué está causando realmente esta excepción (es decir, comprueba lo que crees que es correcto). – chezy525

+0

@ chezy525 Creo que estas excepciones de socket generalmente surgen de los mensajes ICMP "Destino/Puerto/etc inalcanzable" en su socket. Cómo podrías obtener uno si solo estás escuchando, no estoy seguro. Solo un pensamiento. – Kongress

+0

intente habilitar el rastreo de system.net y vea lo que está pasando debajo –