3

As in the simplified code below, is checking that SendAsync() has finished transmitting all intended bytes in the buffer the correct thing to do? Or is that redundant? This is for a TCP connection socket. I am particularly concerned with having to issue a second sub-call to SendAsync() inside ProcessSend().

For example, if I had multiple threads transmitting data to a client using a new (pooled) SocketAsyncEventArg for each message, isn't it possible that a simultaneous send might interject itself in-between a partially transmitted message? Or is this a good reason for controlled access to the client by only allowing one SocketAsyncEventArg to be used in data sending?

private void ProcessSend(SocketAsyncEventArgs e)
{
    // Check that data was sent
    if ((e.SocketError == SocketError.Success) && (e.BytesTransferred > 0))
    {
        AsyncSendUserToken token = (AsyncSendUserToken)e.UserToken;

        // Check that all the data was sent
        int offset = e.Offset + e.BytesTransferred;
        if (offset < e.Count)
        {
            // Call send again to finish the send
            e.SetBuffer(offset, e.Count - offset);
            bool _willRaiseEvent = token.Socket.SendAsync(e);
            if (!_willRaiseEvent)
                ProcessSend(e);
        }
    }
}
Nicholas
  • 1,392
  • 16
  • 38
  • I have also seen this happen and I also saw cases where the number of bytes transferred was greater than e.Count - e.Offset. I was reusing the one SocketAsyncEventArgs for the send, and calling a method that fills the buffer and calls SendAsync from ProcessSend. I added code to dispose the current SocketAsynEventArgs in ProcessSend and create a new one and this has stopped this error happening. – Tim Carter Feb 25 '11 at 03:59

2 Answers2

2

I suspect you are reading the example at http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx and see that they are checking the byte length on ProcessReceive.

This is done to in order to get all received bytes, as you have no control on how many bytes are sent from the other party each time.

When you perform a send, this is redundant as the framework handles sending all your data for you.

Mikael Svenson
  • 39,181
  • 7
  • 73
  • 79
  • I know this question is old, but is this answer still true with all the different .NET versions like .NET Core, Mono etc or is this answer only valid for the "normal"/Windows .NET versions? – R1PFake Apr 21 '19 at 07:57
  • See https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.sendasync?view=netframework-4.8#applies-to for supported versions of .NET – Mikael Svenson Apr 21 '19 at 12:29
  • These other .NET versions also support the method, but my question was if the statement "When you perform a send, this is redundant as the framework handles sending all your data for you." is true for all of these versions, since it's not in the official documentation for any of these versions. We "know" that it is true for .NET on Windows. but it might be different on other plattforms for example .NET Core and Mono can run on Linux, but im not sure about that, because I have no idea about Linux networking. But I assume that all of them should implement the same logic? – R1PFake Apr 21 '19 at 14:46
  • As long as the buffer is within the underlying socket buffer as per the docs yes. If you need to send more data you should look into something along the lines of https://stackoverflow.com/questions/9170126/how-to-use-socket-sendasync-to-send-large-data – Mikael Svenson Apr 21 '19 at 20:22
1

I think there's something wrong in your code:

// Check that all the data was sent
int offset = e.Offset + e.BytesTransferred;
if (offset < e.Count)
{

e.Count is the number of bytes to transfer, it's not an offset into the byte array.

So, in order to compare apples with apples, you'd say:

if (e.BytesTransfered < e.Count) { }

Victor M.
  • 1,004
  • 8
  • 10