.netsocketsasyncsocket

Socket send vs sendasync. When does send actually block?


  Reading the MSDN page, it is clear that Send will block if there are no internal buffers in the socket transport layer.  This is actually a good thing, because I'd rather not have a NoBufferSpaceAvailable error.  My understanding is that the transport buffer space is quite large, but if Send throttles things to prevent these errors I'm happy.

However, is NOT clear what else will cause Send to block.  My guess is that it DOES NOT block waiting for the ack of the send, and that Send will just queue the data to the transport buffers and return. 

What would be a VERY BAD thing is that if a Send really does block until a specific socket actually has completely blocked until transmission completion.  If that were the case then one slow connection out of 1000 could slow down the entire sending process.  In that case SendAsync would really be mandatory.

Anyone have any more details on this?


Solution

  • As EJP says, the send buffers take care of any un-ACKed data, which is to say that any data you send will stay in the buffers until it is ACKed by the receiver. This is to allow for data to be resent later, in the case that an ACK never arrives for a packet.

    Also, as EJP says, whenever an ACK is received, the data that was just ACKed is then removed from the send buffer and the space freed up so you can use it for further sends.

    However, in the case of sending large amounts of data, and ACKs being slow to come back (due to high latency, a noisy connection or simply a disconnection along the way), then the send buffers will get filled up and will eventually result in a send blocking due to a lack of send buffer space.

    So un-ACKed data will not itself directly cause a send to block, but if you send large amounts of data and there are network issues that mean that ACKs are not get back to you, then yes ... un-ACKed data will eventually cause sends to block. And this is correct behaviour.

    You would not want to keep sending data for ever, without receiving an ACK. If you did want that, then you would probably be using UDP instead of TCP :)

    EDIT: Also, it's not uncommon to use one thread per connection, to avoid the specific case you mention where one bad connection can affect a thousand. And if you are worried about scaling, you probably should be using asynchronous calls anyway.