tags:

views:

316

answers:

5

On the client side I need to know when/if my socket connection has been broken. However the Socket.Connected property always returns true, even after the server side has been disconnected and I've tried sending data through it. Can anyone help me figure out what's going on here. I need to know when a socket has been disconnected.

        Socket serverSocket = null;
        TcpListener listener = new TcpListener(1530);
        listener.Start();
        listener.BeginAcceptSocket(new AsyncCallback(delegate(IAsyncResult result)
        {
            Debug.WriteLine("ACCEPTING SOCKET CONNECTION");
            TcpListener currentListener = (TcpListener)result.AsyncState;
            serverSocket = currentListener.EndAcceptSocket(result);
        }), listener);


        Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be FALSE, and it is
        clientSocket.Connect("localhost", 1530);
        Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be TRUE, and it is

        Thread.Sleep(1000);
        serverSocket.Close();//closing the server socket here
        Thread.Sleep(1000);

        clientSocket.Send(new byte[0]);//sending data should cause the socket to update its Connected property.
        Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be FALSE, but its always TRUE
A: 

does the clientSocket.Send() method wait for the packet to either be ack/nack'd?

If not your code is flying onto the next line while socket is still trying to figure out what is going on.

Seth M.
You can put a Thread.Sleep after the send. No matter how long you wait clientSocket.Connected stays true.
BowserKingKoopa
+1  A: 

After doing some testing, it appears that the documentation for Socket.Connected is wrong, or at least misleading. clientSocket.Connected will only become false after clientSocket.close() is called. I think this is a throwback to the original C Berkeley sockets API and its terminology. A socket is bound when it has a local address associated with it, and a socket is connected when it has a remote address associated with it. Even though the remote side has closed the connection, the local socket still has the association and so it is still "connected".

However, here is a method that does work:

!(socket.Poll(0, SelectMode.SelectRead) && socket.Available == 0)

It relies on that fact that a closed connection will be marked as readable even though no data is available.

If you want to detect conditions such as broken network cables or computers abruptly being turned off, the situation is a bit more complex. Under those conditions, your computer never receives a packet indicating that the socket has closed. It needs to detect that the remote side has vanished by sending packets and noticing that no response comes back. You can do this at the application level as part of your protocol, or you can use the TCP KeepAlive option. Using TCP Keep Alive from .NET isn't particularly easy; you're probably better off building a keep-alive mechanism into your protocol (alternately, you could ask a separate question for "How do I enable TCP Keep Alive in .NET and set the keep alive interval?").

Daniel Stutzbach
socket.Poll(0, SelectMode.SelectRead) always returns true for me even after the server side connection has been closed.
BowserKingKoopa
Also the msdn docs say that the Poll method cannot detect certain conditions "such as a broken network cable, or that the remote host was shut down ungracefully". I just want to know if the server side socket is there or not, I don't care why it's not there.
BowserKingKoopa
@BrowserKingKoopa: Whoops! The code I originally posted tested that the socket is *disconnected*. I've fixed it. When the remote side has disconnected, Poll() will return true but socket.Available will be 0.I also added a paragraph about handling broken network cables.
Daniel Stutzbach
+1  A: 

Maybe solution is to send some dummy data through it and check if it times out?

Migol
A: 

I recommend stripping out the higher-level language stuff and explore what happens at the lower-level IO.

The lowest I've explored was while writing isectd (find on sourceforge). Using the select() system call, a descriptor for a closed socket becomes read-ready, and when isectd would attempt the recv() the socket's disconnected state can be confirmed.

As a solution, I recommend not writing your own socket IO and use someone else's middleware. There are lots of good candidates out there. Don't forget to consider simple queuing services as well.

PS. I would have provided URLs to all the above but my reputation (1) doesn't allow it.

tggagne
+2  A: 

Just write to your socket as normal. You'll know when it's disconnected by the Exception that says your data couldn't be delivered.

If you don't have anything to write...then who cares if it's disconnected? It may be disconnected now, but come back before you need it - why bother tearing it down, and then looping a reconnect until the link is repaired...especially when you didn't have anything to say anyway?

If it bothers you, implement a keep alive in your protocol. Then you'll have something to say every 30 seconds or so.

Mark Brackett
+1 if server sent all data and it's not keep alive it should close socket and client should handle it propertly. from side of client if it received all data it wanted it just closes connection too, server will handle it.you should just catch exceptions on s.Receive/s.Send to know when somebody's disconnected, Poll will also throw exception on disconnected socket
hoodoos