Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get remote endpoint info when using Receive[...]Async methods - FYI

Here's a Windows .net annoyance that took me 2 days to resolve. I find the solution important enough to babble for myself at SO, ie. give others a clear statement re. HowTo.

Problem: I get no sender IP address for my connectionless (UDP) socket with ReceiveAsync().

.net provides nice high-performance Receive[...]Async methods that have an advantage over the traditional async method chain of BeginGetResponce -> (callback) -> BeginReceive -> (callback) -> EndReceive, in that the Receive[...]Async methods re-use SocketAsyncEventArgs. You can maintain a pool of SocketAsyncEventArgs and pass any of them to Receive[...]Async. As Receive[...]Async raises the Completed callback, SocketAsyncEventArgs (and it's Buffer property) gives you the payload. The re-use affects the .net garbage bag.

However: The SocketAsyncEventArgs.RemoteEndPoint produce exception. As does the SocketAsyncEventArgs.ReceiveMessageFromPacketInfo stuff. Pre-filling RemoteEndPoint with (IPAddress.Any 0) just causes RemoteEndPoint to say 0.0.0.0:0 - useless! Doing a SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, True) has no effect. Seems to be no damned way to get the remote IP address.

The net is full of questions re. this but there are no specific answers. SO does host answer(s) to the problem (mainly 1 good 1, now that i know what to look for), but also a lot of irrelevant fuzz around the thingy.

Answer below.

like image 748
Stormwind Avatar asked Aug 05 '16 22:08

Stormwind


1 Answers

ReceiveAsync - no go
ReceiveFromAsync - no go
ReceiveMessageFromAsync - go

The design & look of these methods are almost identical. Ofc one tries ReceiveAsync first. A ReceiveAsyncWithHeaderInfo had gained my attention...

A. Do socket creation along this:

so = Socket.New(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)

B. In addition (pseudoish), do a:

so.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, True)

before Binding the socket to a local endpoint. This is not critical, as the first Completed callback will set it to True anyway. But you lose the 1st packet if not set in advance.

C. When constructing the SocketAsyncEventArgs for ReceiveMessageFromAsync, set it's RemoteEndPoint property to

SocketAsyncEventArgs.RemoteEndPoint = IPEndPoint.New(IPAddress.Any, 0)

ReceiveMessageFromAsync will crash if this is not set, so this is critical. The IPAddress.Any and port 0 are not important, .net will update those when data comes in, so setting RemoteEndPoint only provides Microsoft space to write into. Halleluja.

(D. And naturally create the buffer and callbacks in SocketAsyncEventArgs, as shown in various examples)

_ _

MS could have added this comment to the documentation of the no-go methods:

"If you need the senders IP address (which you probably do), don't use ReceiveAsync or ReceiveFromAsync, use ReceiveMessageFromAsync".

Now you have a RemoteEndPoint.Address and Port :-).

like image 89
Stormwind Avatar answered Nov 10 '22 01:11

Stormwind