UDP Sockets - Get Remote Host on data RX

J

Jason

I am working on an asynchronous UDP socket server platform, and I am
running into what appears to be a common problem but I have not found
a good answer yet.

If this was TCP, when the routine EndReceiveData() is called back
(after making a connection and receiving data) you can access the IP
of the remote host by

EndPoint ep = sock.RemoteEndPoint;
Where this would be useful is UDP, where you don't have a connection
established and you actually need to know the IP address where to send
data.

So, in a UDP synchronous setup, you can write code like this
Receive()
{

IpEndPoint ipep = new IpEndPoint(IPAddress.Any,10000);
EndPoint ep = (EndPoint)ipep;

//When this returns, ipep, will now contain the value of the
RemoteEndPoint.
sock.ReceiveFrom(buffer, ref ep);

//Now you can send data back to that computer
sock.SendTo(buffer, ep);
}

So far so good. You can detect who sent the packet and you can reply
back to them. Easy enough.


But once you move to asynchronous, this doesn't work anymore

BeginReceive()
{

IpEndPoint ipep = new IpEndPoint(IPAddress.Any,10000);
EndPoint ep = (EndPoint)ipep;

//When this returns, ipep, will now contain the value of the
RemoteEndPoint, right?
sock.BeginReceiveFrom(buffer, 0, 1024, SocketFlags.None, ref ep, new
AsyncCallback(OnDataReceived), sock);

}
OnDataReceived(IAsyncResult asyn)
{
Socket sock = (Socket)asyn.AsyncState;
int iRx = sock.EndReceive(asyn);

.... ... ...
}

In this case, you can look at sock.RemoteEndPoint but it will throw an
exception. The argument I hear for this is that this is
connectionless and you don't ever get this, but in the syncronous
example above you DO get this with UDP.
If you pass in an object that contains both the Socket and the
EndPoint that was passed by reference into BeginReceiveFrom, and pull
them both out once you make it to OnDataReceived, you do get a
response, but it is always IPAddress.Any (aka 0.0.0.0.) What is even
the point of passing in the EndPoint by reference into
BeginReceiveFrom if it's always going to come out the same?

More over, there is no way that BeginReceiveFrom will ever alter the
value in "ref EndPoint" because it returns instantly, before any data
has come in. That is the whole point.

So, one solution is to have the client sends it's IP address in every
single packet. But this seems silly - there has to be a way to detect
the IP address that data came in on. No?

Any help would be appreciated. Excuse my code snipits, I typed them
all here, so there may be typos.

Jason
 
B

Bela Istok

See this example: (using UdpClient)

UdpClient client = new UdpClient(12345, AddressFamily.InterNetwork);
client.EnableBroadcast = true;

client.BeginReceive(AsyncCallbackF, client);

static void AsyncCallbackF(IAsyncResult a)
{
System.Net.IPEndPoint end = new System.Net.IPEndPoint(0, 0);
UdpClient uc = ((UdpClient)a.AsyncState);
byte[] ret = uc.EndReceive(a, ref end);
Console.WriteLine(BitConverter.ToString(ret));
Console.WriteLine(end);
uc.BeginReceive(AsyncCallbackF, uc);
}

Regards,

Bela Istok
Peter Duniho said:
[...]
More over, there is no way that BeginReceiveFrom will ever alter the
value in "ref EndPoint" because it returns instantly, before any data
has come in. That is the whole point.

To some extent, the parameter exists because async methods are supposed to
have the same signature as synchronous methods. That said, while I
haven't tried it, I suspect that the "remoteEP" argument would in fact
receive the remote endpoint address if it was known when
BeginReceiveFrom() is called (i.e. it's used for a TCP socket, or for a
UDP socket that's been "connected").

More to the point though: if you call BeginReceiveFrom(), why would you
not call EndReceiveFrom() as well? If you do that, then you can get the
endpoint value from the call to EndReceiveFrom(), just as you'd want and
expect.

Pete
 
J

Jason

What a silly mistake. I think that was it. When you call
EndReceiveFrom, you get the IAsyncResult but also the ref EndPoint.

Very cool! Thank you for that nugget of info!

Jason
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top