0

Under rare conditions, the WaitOne in the code below returns false even though the socket has more than the requested data in the Available property. I don't understand why the WaitOne would return false when the data is ready. The network device I'm communicating with is connected to a switch that my computer is connected to. This smells like a software issue, but I suppose it could be other network traffic. Does anyone see anything wrong with how the BeginReceive/WaitOne is being used here?

// The tmpBuffer is code below is defined as:
Byte[] tmpBuffer = new byte[16];

// The following code is in a loop that runs until the entire packet is received
while (packet not received)
// :

// Attempt to get the next block (16-bytes) of data.  Since we don't always know how much
// data is coming in, this code always gets 16-bytes at a time.  First it tries to
// read 16 bytes.  If it only gets 14, for example, then it will read 2 bytes.  This
// makes the encyrption easy as it needs to be on a 16-byte block.
IAsyncResult ar = _server.BeginReceive(tmpBuffer, count, tmpBuffer.Length - count, SocketFlags.None, null, null);

// Wait for receive to complete OR timeout in case connection is lost
if (ar.AsyncWaitHandle.WaitOne(_receiveTimeoutMs))  // timeout is 300ms
{
    int temp = _server.EndReceive(ar);

    if (temp == 0)
    {
        _server.Close();
        throw new ApplicationException("Lost connection!");
    }
    count += temp;
    //Debug.WriteLine("Got data");
}
else
{
    sscLogger.LogWarning("Receive timed out...closing socket: rxStartTime=" + rxStartTime.ToString("h:mm:ss.ffff"));

    sscLogger.LogWarning("_server.Available=" + _server.Available.ToString() + ", requested=" + (tmpBuffer.Length - count).ToString());
    Thread.Sleep(100);
    sscLogger.LogWarning("_server.Available=" + _server.Available.ToString() + ", requested=" + (tmpBuffer.Length - count).ToString());

    _server.Close();
    throw new ApplicationException("Receive timed out");
}

The output of my logging code above is:

[W] 2/26/2015 11:49:17.6082 AM: Receive timed out...closing socket: rxStartTime=11:49:17.3082
[W] 2/26/2015 11:49:17.6102 AM: _server.Available=32, requested=16
[W] 2/26/2015 11:49:17.7123 AM: _server.Available=32, requested=16
ejwipp
  • 361
  • 1
  • 7
  • 16
  • 2
    Can I ask you why you use an asynchronous call and then block to wait for the result? Why not using directly the synchronous call Receive instead? You could validate if you have the same result too. Please note that you can set the ReceiveTimeout property of the socket to have the same behavior. – Absolom Feb 26 '15 at 20:37
  • I needed the code to timeout, so I think that is why I used the asynchronous wait. I wrote the code three-years ago so my memory is a little fuzzy. Looking at the socket class again I see that I could have used a synchronous receive and set the ReceiveTimeout parameter accordingly. I guess I missed that the first go round. – ejwipp Feb 26 '15 at 20:45
  • Any chance it is related to the `exitContext` parameter? You are calling WaitOne(TimeSpan), and that overload specifies `exitContext=false`. Take a look at https://msdn.microsoft.com/en-us/library/85bbbxt9(v=vs.110).aspx -- I don't know if this is related, but just a thought. – Ryan Feb 26 '15 at 20:54
  • Could it be a racing condition? Can you try to increase the timeout to 2 seconds and see if you still get the error? If not, then my guess is that by the time the WaitOne has timeouted and you display your logs, the socket receives the data. – Absolom Feb 26 '15 at 21:44
  • @ejwipp, `ReceiveTimeout` doesn't work for async APIs, just a bad design from Microsoft. The best thing you could do is to use your own time-out mechanism and ignore the completion of `BeginReceive`, or close the socket, in which case `EndReceive` will be called with an error. For a discussion of the same problem with `Task`-based socket APIs, check this out: http://stackoverflow.com/q/21468137/1768303 – noseratio Feb 27 '15 at 00:22

0 Answers0