Why does Socket.BeginSend
go asynchronous so quickly and so unpredictably? I know it's supposed to be asynchronous, but it can also complete immediately, in which case IAsyncResult.CompletedSynchronously
is set. I would expect CompletedSynchronously
to be true until the 8KB send buffer is filled up. The test case below (cleanup code stripped for brevity) demonstrates that BeginSend
goes asynchronous on (typically) 3rd iteration after buffering only 6 bytes of data:
TcpListener listener = new TcpListener(IPAddress.Any, 35001);
listener.Start();
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp))
client.Connect(new IPEndPoint(IPAddress.Loopback, 35001));
Socket server = listener.AcceptSocket())
for (int i = 1; i <= 10; ++i)
{
bool sent = false;
IAsyncResult result = client.BeginSend(new byte[] { 1, 2, 3 }, 0, 3,
SocketFlags.None, r => sent = true, null);
Assert.IsTrue(result.CompletedSynchronously, // fails typ. on 3rd iteration
String.Format("Asynchronous on iteration {0}", i));
Assert.IsTrue(sent);
client.EndSend(result);
}
The exact iteration when it goes asynchronous is somewhat random. When process starts, it's 3. Afterwards it's 1 for all new sockets. I've seen other numbers sporadically. I know the 8KB socket send buffer is there, because Socket.Send
(with Socket.Blocking = false
) stops at about 8KB.
Method Socket.SendAsync
behaves similarly except it always completes asynchronously (i.e. no attempt at direct buffer write). See my related question about Socket.SendAsync.
I need BeginSend
to be mostly synchronous for performance reasons (asynchronous callbacks are slower). Not to mention the unpredictability ruins unit tests and benchmarks for my low-level communication code.