Search code examples
c#.netsockets.net-micro-framework

How long should we wait to check for available data after accepting a connection?


Situation

We're using the following code to accept incoming HTTP requests.

var localEndPoint = new IPEndPoint(IPAddress.Any, Port);

var serverSocket = new Socket(
    AddressFamily.InterNetwork,
    SocketType.Stream,
    ProtocolType.Tcp);

serverSocket.Bind(localEndPoint);
serverSocket.Listen(backlog: 25);

while (true)
{
    using (var clientSocket = serverSocket.Accept())
    {
        if (clientSocket.Available > 0)
        {
            var builder = new StringBuilder();

            while (clientSocket.Available > 0)
            {
                var currentBytes = new byte[clientSocket.Available];
                var bytesReceived = clientSocket.Receive(currentBytes);

                var currentBytesString = 
                    new string(Encoding.UTF8.GetChars(currentBytes));

                builder.Append(currentBytesString);
            }
        }
    }
}

Problem

Sometimes clientSocket.Available is zero even though the connection has data. The solution we implemented is to wait after accepting the connection before we check whether data is available. We do it like this:

var start = DateTime.Now;
var duration = new TimeSpan(0);
while (clientSocket.Available <= 0 || duration.Milliseconds < 1000)
{
    duration = DateTime.Now - start;
    Thread.Sleep(100);
}

Question

After accepting a connection, how long we we need to wait before the connection's data will be available in the socket?

Working Solution

Thank you to szym for the inspiration for this approach. It is working for now.

while (true)
{
    using (var clientSocket = serverSocket.Accept())
    {
        var builder = new StringBuilder();

        do
        {
            var currentBytes = new byte[50];
            var bytesReceived = clientSocket.Receive(currentBytes);

            var currentBytesString = 
                new string(Encoding.UTF8.GetChars(currentBytes));

            builder.Append(currentBytesString);
        }
        while (clientSocket.Available > 0);
    }
}

Solution

  • Generally, you might need to wait a while (think crappy networks with huge round-trip times), the default timeout on some platforms is 20 seconds!

    However, the approach of checking Available in a sleepy-loop is polling and is a waste of CPU. You should either block on Receive which will just wait for data to arrive (perhaps spawn a thread if you need to handle multiple connections), or use a non-blocking approach.

    To quote the documentation (emphasis mine):

    If you are using a non-blocking Socket, Available is a good way to determine whether data is queued for reading, before calling Receive. The available data is the total amount of data queued in the network buffer for reading. If no data is queued in the network buffer, Available returns 0.