Handling timeout on blocking .NET socket

18,366

The problem is if the timeout occurs the TcpClient gets disconnected. So your method won't work. Use the async read/write functions or use select.

The probably easiest way with async function call is like this:

byte[] data = new byte[4096];
IASyncResult result = stream.BeginRead(data, 0, data.Length, null, null);
result.AsyncWaitHandle.WaitOne(<timeout value in ms>);
int bytes = stream.EndRead(result);

if (!result.IsCompleted)
  <timed out>
else
  <read data>
...
Share:
18,366
Luca
Author by

Luca

SOreadytohelp

Updated on June 05, 2022

Comments

  • Luca
    Luca almost 2 years

    A TcpClient instance, created with the Accept method, is used for manage a client connection. The problem arise when I need to terminate the server thread, since it is blocked on a receive call.

    So I setup a the TcpClient ReceiveTimeout in order to loop every n milliseconds to test the exit condition. The result is that the Receive operation raise an exception (SocketException) having the error code SocketError.TimedOut. Good I was thinking...

    The problem is that the property Socket.Connected returns false, but as stated in the MSDN documentation:

    The value of the Connected property reflects the state of the connection as of the most recent operation. If you need to determine the current state of the connection, make a nonblocking, zero-byte Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035), then the socket is still connected; otherwise, the socket is no longer connected.

    So, I do what states:

    try {
         // Receive operation on socket stream
         // Send operation on socket stream
    } catch (SocketException e) {
        if (e.SocketErrorCode == SocketError.TimedOut) {
        try {
            IAsyncResult asyncResult;
            int sResult;
    
            asyncResult = mSocket.Client.BeginSend(new byte[] {}, 0, 0, SocketFlags.None, delegate(IAsyncResult result) { }, null);
            sResult = mSocket.Client.EndSend(asyncResult);
            Debug.Assert(asyncResult.IsCompleted == true);
    
            if (mSocket.Connected == false)
                throw new Exception("not more connected");  // Always thrown
        } catch (Exception e) {
                 // ...
            }
    }
    

    But, even if the aynch Send operation is executed, the property mSocket.Connected is always false, causing the outer loop to terminate (other threads calls Disconnect method to terminate the server thread).

    What am I missing?