2012-04-26 10 views
6

Estoy trabajando en una aplicación de servidor (C#, .NET 4.0) que necesitará manejar miles de paquetes UDP por segundo. Así que decidí SocketAsyncEventArg para implementar el servidor.Restablecimiento de la conexión al recibir el paquete en el servidor UDP

El problema al que me enfrento es que mi implementación recibe solo un paquete y luego aparece el error "ConnectionReset" (nunca imaginé que podría obtener este error porque UDP no tiene conexión). Aquí está mi implementación de prueba:

using System; 
using System.Net; 
using System.Net.Sockets; 

static class Program 
{ 
    static void Main(string[] args) 
    { 
     UdpEchoServer.Start(); 

     while (true) 
     { 
      Console.ReadLine(); 
      SendPacket(); 
     } 
    } 

    static void SendPacket() 
    { 
     Console.WriteLine("SendPacket"); 
     var c = new UdpClient(); 
     c.Send(new byte[5], 5, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 445)); 
     c.Close(); 
    } 
} 

static class UdpEchoServer 
{ 
    static Socket mSocket; 
    static byte[] mBuffer; 
    static SocketAsyncEventArgs mRxArgs, mTxArgs; 
    static IPEndPoint mAnyEndPoint, mLocalEndPoint; 

    public static void Start() 
    { 
     mAnyEndPoint = new IPEndPoint(IPAddress.Any, 0); 
     mLocalEndPoint = new IPEndPoint(IPAddress.Any, 445); 

     mBuffer = new byte[1024]; 

     mRxArgs = new SocketAsyncEventArgs(); 
     mTxArgs = new SocketAsyncEventArgs(); 

     mRxArgs.Completed += ReceiveComplete; 
     mTxArgs.Completed += SendComplete; 

     mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 
     mSocket.Bind(mLocalEndPoint); 
     ReceiveNext(); 
    } 

    static void ReceiveNext() 
    { 
     Console.WriteLine("ReceiveNext"); 

     mRxArgs.RemoteEndPoint = mAnyEndPoint; 
     mRxArgs.SetBuffer(mBuffer, 0, mBuffer.Length); 

     if (!mSocket.ReceiveFromAsync(mRxArgs)) 
      Console.WriteLine("Error in ReceiveNext: " + mRxArgs.SocketError); 
    } 

    static void ReceiveComplete(object sender, SocketAsyncEventArgs e) 
    { 
     Console.WriteLine("Receive Complete: " + mRxArgs.SocketError); 

     if (mRxArgs.SocketError != SocketError.Success) 
      return; 

     mTxArgs.SetBuffer(mBuffer, 0, mRxArgs.BytesTransferred); 
     mTxArgs.RemoteEndPoint = mRxArgs.RemoteEndPoint; 

     Console.WriteLine("Sending reply packet"); 

     if (!mSocket.SendToAsync(mTxArgs)) 
      Console.WriteLine("Error in ReceiveComplete: " + mRxArgs.SocketError); 
    } 

    static void SendComplete(object sender, SocketAsyncEventArgs e) 
    { 
     Console.WriteLine("Send Complete: " + mTxArgs.SocketError); 

     if (mTxArgs.SocketError != SocketError.Success) 
      return; 

     ReceiveNext(); 
    } 
} 

Lo sentimos, pero es muy simple. Espero un paquete, respondo al punto final remoto y luego espero el próximo. Aquí está la salida:

ReceiveNext 

SendPacket 
Receive Complete: Success 
Sending reply packet 
Send Complete: Success 
ReceiveNext 
Error in ReceiveNext: ConnectionReset 

¿Puede sugerir qué está mal en el fragmento de código anterior?

Respuesta

10

Esto ocurre con sockets UDP. Todo lo que necesita hacer es cambiar socket operating mode antes de vincularlo. Use este código en su método Start.

mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 

const int SIO_UDP_CONNRESET = -1744830452; 
byte[] inValue = new byte[] {0}; 
byte[] outValue = new byte[] {0}; 
mSocket.IOControl(SIO_UDP_CONNRESET, inValue, outValue); 

mSocket.Bind(mLocalEndPoint); 
+0

Gracias por la respuesta, ¿podría darnos una explicación, por favor? – markmnl

+0

Tal como está, algunos desarrolladores lo diseñaron así y tenemos que seguir :-) –

1

Si elimina o comenta la llamada al Close en el UdpClient, entonces el programa funciona como se esperaba. ¿Por qué está sucediendo esto? No estoy seguro, pero podría ser con la red de bucle invertido de Windows.

+0

Sí. Tienes razón. Lo que es más interesante es que si mantenemos el 'Cerrar' pero ejecutamos el cliente y el servidor en diferentes computadoras, entonces también se resuelve el problema. Como dijiste, debe haber algo con el mecanismo de loopback de Windows. – Hemant

+0

Sí, no estoy sorprendido por eso. Si cerrar un socket UDP en un host provocara el cierre de un socket UDP en otro host ¡comenzaría a preocuparme! – Nick

Cuestiones relacionadas