What calls is the SocketAsyncEventArgs Completed thread called and where to process messages

I have a standard implementation for receiving UDP packets asynchronously using SocketAsyncEventArgs

. What I don't understand from the docs and some lookups is if I have to do the real work of handling messages inside the callback itself, for example this comment indicates in the full implementation I'm talking about, or I have to offload processing to other threads. for example via ConcurrentQueue or BlockingCollection.

My problems are as follows:

  • If processing directly in the callback could result in poor receive performance or random delays due to temporary starvation of the thread pool or some other implementation detail?
  • Due to small processing delays (rather than just uploading to a collection), can more packets drop due to a full buffer?
  • More packets can be reordered in the sense that the callback is called in a different order than the packets actually come from the network.

So what's the best practice or intended way to handle messages using SocketAsyncEventArgs to ensure minimal missed datagrams, without additional reordering of callbacks, and no additional delays?

And a related question - does ReceiveAsync

any order at all, or at least try to call the callback in the same order as the packets received from the network, or should I use blocking for this? The target use case is to subscribe to 6-8 UDP channels, in each of which the order is very important. Executing a series of blocking threads looks more complicated than just handling callbacks, but not that hard as long as the solution guarantees the order of the messages.

+3


source to share


1 answer


What is the best practice or intended way of handling messages using SocketAsyncEventArgs to ensure the least missed datagrams.

To be honest, this is really a matter of opinion to some extent, and also highly dependent on your exact scenario. Typically, however, your I / O completion routine should be fast. If your processing is fast then it is okay to complete this procedure. If not, you should do as little work as possible, i.e. Simply move the data to a queue where it can be processed elsewhere and then return from the completion routine.

Keep in mind that "fast" is relative here. You just need to be faster than the network, which despite the ever-increasing network speed is not very difficult to do on a modern processor. The network layer will depend on your name, so if your workload bandwidth exceeds your network bandwidth, you are probably doing a great job in the completion routine.

But it really just depends. There is no way to say which is better. Each specific scenario is different.

Does ReceiveAsync receive any order at all, or is it at least trying to call the callback in the same order the packets are received from the network, or should I use blocking to do this?

Blocking the reception won't help.

Asynchronous methods have the same characteristics: you can release more than once and they will be completed in the same order in which they were released. But you still need to keep track of which order you issued read operations. The buffers will be filled in the order you gave them at the network layer, but the completion routines may not be executed in order because they are executed per thread, and the thread scheduler does not guarantee the order of execution of the thread. Just because one thread was started before another does not mean that it will actually receive its next timelist before the other.



But this is actually worse than this:

The target use case is to subscribe to 6-8 UDP channels, in each of which the order is very important.

If order is important in your scenario, you need to include sequence numbers in your datagrams and make sure you use them to place the data in the correct order if those datagrams are received.

UDP does not guarantee ordering. Datagrams can be received in any order, regardless of the order in which they are sent. UDP also does not guarantee delivery at all. Datagrams can be deleted at any time. UDP also does not guarantee uniqueness. This datagram can be delivered multiple times.

If reliability and orderliness are important in your scenario, you should probably use TCP over UDP.

If you only need to order, then UDP may still work for you. And in this case, since you need ordinal numbers in the datagrams anyway, this makes the "multiple concurrent read" scenario easier, since the data itself contains the ordinal, so you don't need to track it down separately (for example, in a state object linked with each read operation).

+3


source







All Articles