Tengo una clase de servidor UDP asíncrono con un socket vinculado a IPAddress.Any, y me gustaría saber a qué IPAddress se envió el paquete recibido (... o recibido). Parece que no puedo usar la propiedad Socket.LocalEndPoint, ya que siempre devuelve 0.0.0.0 (lo cual tiene sentido ya que está vinculado a eso ...).Socket C# UDP: Obtener la dirección del receptor
Estas son las partes interesantes del código que estoy usando actualmente:
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){
//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} to {3}:{4}",
msgLen,
((IPEndPoint)clientEP).Address,
((IPEndPoint)clientEP).Port,
((IPEndPoint)recvSock.LocalEndPoint).Address,
((IPEndPoint)recvSock.LocalEndPoint).Port);
//Do other, more interesting, things with the received message.
}
Como se mencionó anteriormente esta siempre imprime una línea como:
recibido 32 bytes desde 127.0.0.1:1678 en 0.0.0.0: 12345
Y me gustaría que fuera algo así como:
recibido 32 bytes desde 127.0.0.1:1678 a 127.0.0.1:12345
Gracias, de antemano, por alguna idea sobre esto! --Adam
ACTUALIZACIÓN
Bueno, he encontrado una solución, aunque no me gusta ... Básicamente, en lugar de abrir un socket UDP con destino a IPAddress.Any, se crea una toma única para cada dirección IP disponible. Así, la nueva función de arranque se parece a:
public void Starter(){
buffer = new byte[1024];
//create a new socket and start listening on the loopback address.
Socket lSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
lSock.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345);
EndPoint ncEP = new IPEndPoint(IPAddress.Any, 0);
lSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref ncEP, DoReceiveFrom, lSock);
//create a new socket and start listening on each IPAddress in the Dns host.
foreach(IPAddress addr in Dns.GetHostEntry(Dns.GetHostName()).AddressList){
if(addr.AddressFamily != AddressFamily.InterNetwork) continue; //Skip all but IPv4 addresses.
Socket s = new Socket(addr.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
s.Bind(new IPEndPoint(addr, 12345));
EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);
s.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, s);
}
}
Esto es sólo para ilustrar el concepto, el mayor problema con este código como está, es que cada socket está intentando utilizar el mismo tampón ... que es generalmente una mala idea ...
Tiene que haber una mejor solución para esto; Quiero decir, la fuente y el destino son parte del encabezado del paquete UDP. Bueno, supongo que seguiré con esto hasta que haya algo mejor.
Ha sido probado ahora mate y funciona. Esta es la mejor respuesta a las diversas preguntas sobre este tema. Me gustaría ver la versión de ReceiveMessageFromAsync pero probablemente pueda resolverlo por mí mismo si no respondes. –
@StephenKennedy: para ser sincero, ya no creo tener ese código. : P No es terriblemente complicado, sin embargo, IIRC; simplemente configure un 'SocketAsyncEventArgs', adjunte un controlador a su evento' Completed', luego pase el objeto a 'ReceiveMessageFromAsync'. – cHao
Sin preocupaciones. Tengo SendToAsync() en funcionamiento, así que puedo jugar con ReceiveMessageFromAsync() tmw :) Gracias. –