Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async Socket Writes - Potential for send operations to get mixed up? (.NET Sockets)

Tags:

c#

.net

sockets

Sorry if this has been asked before, but I find it a hard thing to search for:

If I use BeginSend() on a .NET socket, what kind of behaviour should I expect in code similar to this (pseudo) code:

Main Program Code:

Network.OutBound.SendData(messageOne);

Network.OutBound.SendData(messageTwo);

Network.OutBound class

public void SendData(byte[] buffer)
{
     connectedSocket.BeginSend(buffer,0,buffer.Length,SocketFlags.None,SendCompleteMethod);
}

private void SendComplete(arResult)
{
     int bytesSent;
     bytesSent = arResult.EndSend();

     if(bytesSent < arResult.state.buffer.Length)
     {
         //Not all data sent yet, recall BeginSend
         connectedSocket.BeginSend(buffer,bytesSent,buffer.Length - bytesSent,SocketFlags.None,SendCompleteMethod);
     }
     else
     {
         //All data sent successfully
     }
}

As im using BeginSend(), when the first SendData(messageOne) is called, it will immediately return and the second SendData(messageTwo) will be called. However, consider a case where a large amount of data is being sent for both message one and message two, and the send completes with a partial amount of data and so BeginSend() is recalled to send the remaining data.

Would this cause the two messages' bytes in the outgoing socket to be mixed up? They would both be running in seperate threadpool threads and would both be sending on the same socket. I understand TCP sockets ensure data arrives in order, but how does the runtime/socket layer know if my BeginSend() is a subsequent attempt to finish sending messageOne, or the start of messageTwo? As far as it is concerned, wouldnt the data be sent and received on the remote end be in the same order as it was written to the socket in (even though this is where the potential for mix up seems to be)

If thats the case, the what is the point of Begin/End Send if I have to serialize access to it?

Should I have some sort of flag that gets raised when messageOne has been fully sent (even if it took several BeginSend() attempts to send all the data) so the Main Program code can wait for it to complete before attempting to sending a different message?

Should I write some sort of outgoing queue wrapper? Or am I missing something?

like image 300
Dermot Avatar asked Oct 09 '22 16:10

Dermot


1 Answers

Looking in with Reflector, you will see that BeginSend finally exits from the .NET wrappers into the Win32 API and makes a call to WSASend which doesn't appear to provide any form of ASync option, so as far as I can see it will only generate Blocking calls that are managed inside .NET framework to be Async using the threadpool.

In the applications I've written with networking I've never really considered this situation, because I have a sender method that blocks if you attempt to call it again, before the previous send has complete, or I have that always block using .Send Only because they are usually a response to a received message on a dedicated thread.

EDIT:

Did a little extra testing.

If you start 2 beginsends with a small buffer each then it probably won't really make a difference but if your buffer is significant my tests I used a 400k buffer, then you are definately in for a world of hurt, you'll hopefully just exception, but it's gonna break.

like image 77
Paul Farry Avatar answered Oct 13 '22 01:10

Paul Farry