views:

54

answers:

4

i am trying to disconnect a client from a server but the server still sees it as being connected. I cant find a solution to this and Shutdown, Disconnect and Close all dont work.

Some code for my disconnect from the client and checking on the server:

Client:

  private void btnDisconnect_Click(object sender, EventArgs e)
    {
        connTemp.Client.Shutdown(SocketShutdown.Both);
        connTemp.Client.Disconnect(false);
        connTemp.GetStream().Close();
        connTemp.Close();
    }

Server:

    while (client != null && client.Connected)
            {
                NetworkStream stream = client.GetStream();
                data = null;

                try
                {
                    if (stream.DataAvailable)
                    {
                        data = ReadStringFromClient(client, stream);
                        WriteToConsole("Received Command: " + data);
                    }
                } // So on and so on...

There are more writes and reads further down in the code.

Hope you all can help.

UPDATE: I even tried passing the TCP client by ref, assuming there was a scope issue and client.Connected remains true even after a read. What is going wrong?

Second Update!!:

Here is the solution. Do a peek and based on that, determine if you are connected or not.

  if (client.Client.Poll(0, SelectMode.SelectRead))
                    {
                        byte[] checkConn = new byte[1];
                        if (client.Client.Receive(checkConn, SocketFlags.Peek) == 0)
                        {
                            throw new IOException();
                        }
                    }
+1  A: 

From the MSDN Documentation:

The Connected property gets the connection state of the Client socket as of the last I/O operation.

When it returns false, the Client socket was either never connected, or is no longer connected. Because the Connected property only reflects the state of the connection as of the most recent operation, you should attempt to send or receive a message to determine the current state. After the message send fails, this property no longer returns true. Note that this behavior is by design. You cannot reliably test the state of the connection because, in the time between the test and a send/receive, the connection could have been lost. Your code should assume the socket is connected, and gracefully handle failed transmissions.

Coding Gorilla
This doesnt work. At the bottom of that while loop i did another client.connected and its still returning true even though I have disconnected from the server. What now?
Sean P
A: 

It's a general TCP problem, see:

The workaround for this tend to rely on sending the amount of data to expect as part of the protocol. That's what HTTP 1.1 does using the Content-Length header (for a entire entity) or with chunked transfer encoding (with various chunk sizes).

Another way is to send "NOOP" or similar commands (essentially messages that do nothing but make sure the communication is still open) as part of your protocol regularly.

(You can also add to your protocol a command that the client can send to the server to close the connection cleanly, but not getting it won't mean the client hasn't disconnected.)

Bruno
+1  A: 

I am not sure about the NetworkStream class but I would think that it would behave similar to the Socket class as it is primarily a wrapper class. In general the server would be unaware that the client disconnected from the socket unless it performs an I/O operation on the socket (a read or a write). However, when you call BeginRead on the socket the callback is not called until there is data to be read from the socket, so calling EndRead and getting a bytes read return result of 0 (zero) means the socket was disconnected. If you use Read and get a zero bytes read result I suspect that you can check the Connected property on the underlying Socket class and it will be false if the client disconnected since an I/O operation was performed on the socket.

Steve Ellinger
This got me on the right track...thanks... see above.
Sean P
A: 

Here is the solution!!

  if (client.Client.Poll(0, SelectMode.SelectRead))
                {
                    byte[] checkConn = new byte[1];
                    if (client.Client.Receive(checkConn, SocketFlags.Peek) == 0)
                    {
                        throw new IOException();
                    }
                }
Sean P