views:

60

answers:

3

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?

A: 

You should look at the C# example on the Socket.Connected MSDN page you linked to. It has a significantly different implementation of a method to determine whether the socket is still connected.

// .Connect throws an exception if unsuccessful
client.Connect(anEndPoint);

// This is how you can determine whether a socket is still connected.
bool blockingState = client.Blocking;
try
{
    byte [] tmp = new byte[1];

    client.Blocking = false;
    client.Send(tmp, 0, 0);
    Console.WriteLine("Connected!");
}
catch (SocketException e) 
{
    // 10035 == WSAEWOULDBLOCK
    if (e.NativeErrorCode.Equals(10035))
        Console.WriteLine("Still Connected, but the Send would block");
    else
    {
        Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
    }
}
finally
{
    client.Blocking = blockingState;
}

Console.WriteLine("Connected: {0}", client.Connected);
Chris Shouts
I have the same behavior. Send routine doesn't throw the exception, and the Connected property remains set to false. Later routine calls (send/receive) behave as galbarm answer describe.
Luca
+1  A: 

Check out this link:

A non-blocking socket operation could not be completed

galbarm
Seems interesting, but the proposed solution doesn't work on .NET 2.0.
Luca
+1  A: 

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>
...
pitt7
Compliments for your first answer! But it is exactly what I try to avoid. For using non blocking socket I would refactor the server logic and make every network operation asynch, without spawning additional threads."The problem is if the timeout occurs the TcpClient gets disconnected": where it is written? In stdc non-blocking socket, after a timeout (implementated using a select), are not disconnected.
Luca
The code I posted uses the async BeginRead/EndRead function. But it blocks using WaitOne. So you don't have to change your server logic.BeginRead doesn't block. WaitOne blocks until there is data or the specified timeout occurs. Using !result.IsCompleted to check if it timed out or there is data available.
pitt7
I don't know where "if the timeout occurs the TcpClient gets disconnected" is written. But I had exactly the same problem. And if Read returns by timeout Connected is False. I didn't do much research on this but just accepted that it's not intended in C# to set a timeout value and run into this timeout regulary.
pitt7
I agree. However, a simpler approach is to avoid continuous looping on the server thread while handling network communication, loosing the need of a timeout feature.
Luca