tags:

views:

7203

answers:

9

If I'm running a simple server and have accept()ed a connection from a client, what is the best way to tell when the client has disconnected? Normally, the client in this case I supposed to send a close command, but what if it DCs manually? How can I tell or handle this?

+6  A: 

Look here (for the worst case scenarios):

http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html (Checking for dead peers)

Blauohr
+4  A: 

select (with the read mask set) will return with the handle signalled, but when you use ioctl* to check the number of bytes pending to be read, it will be zero. This is a sign that the socket has been disconnected.

* for Windows use ioctlsocket.

sep
Thanks! This answer was quite helpful to me as well :)
Michael Mior
+3  A: 

To expand on this a bit more:

If you are running a server you either need to use TCP_KEEPALIVE to monitor the client connections, or do something similar yourself, or have knowledge about the data/protocol that you are running over the connection.

Basically, if the connection gets killed (i.e. not properly closed) then the server won't notice until it tries to write something to the client, which is what the keepalive achieves for you. Alternatively, if you know the protocol better, you could just disconnect on an inactivity timeout anyway.

Mr J
+2  A: 

If you're using overlapped (i.e. asynchronous) I/O with completion routines or completion ports, you will be notified immediately (assuming you have an outstanding read) when the client side closes the connection.

Graeme Perrow
A: 

I have to deal with a similar situation in the code I wrote and maintain at work. In my situation I have a bunch of clients that nominally stay permanently connected to the server. If they are going to disconnect they are supposed to send a disconnect message. However, they occasionally crash and the connection is lost without sending the disconnect message.

When this happen the socket always triggers. I'm using a blocking select and this trigger activates the message processing code. The messages normally being passed along the socket follow a known design I designed it) that always starts out by transmitting the length of the message in bytes (they are of variable length) as a 32-bit integer. So when processing a message I start by reading out this byte from the socket. For a good message, this is a positive number telling me the length of the message. When the socket is closed from the other end this value always ends up being -1. I simply check for this and do the appropriate clean-up on the server side.

I would recommend doing something similar. If you know what you should be getting, read out the first bit of the message from the triggered socket and make sure it is not garbage. If it is, handle appropriately.

Disclaimer: We are running Linux and compiling with gcc. This is a custom application running on dedicated hardware. I would also add that this is not the behavior described by the socket man pages but is what happens on our systems in reality.

dagorym
+2  A: 
"""
tcp_disconnect.py
Echo network data test program in python. This easily translates to C & Java.

A server program might want to confirm that a tcp client is still connected 
before it sends a data. That is, detect if its connected without reading from socket.
This will demonstrate how to detect a TCP client disconnect without reading data.

The method to do this:
1) select on socket as poll (no wait)
2) if no recv data waiting, then client still connected
3) if recv data waiting, the read one char using PEEK flag 
4) if PEEK data len=0, then client has disconnected, otherwise its connected.
Note, the peek flag will read data without removing it from tcp queue.

To see it in action: 0) run this program on one computer 1) from another computer, 
connect via telnet port 12345, 2) type a line of data 3) wait to see it echo, 
4) type another line, 5) disconnect quickly, 6) watch the program will detect the 
disconnect and exit.

John Masinter, 17-Dec-2008
"""

import socket
import time
import select

HOST = ''       # all local interfaces
PORT = 12345    # port to listen

# listen for new TCP connections
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)
# accept new conneciton
conn, addr = s.accept()
print 'Connected by', addr
# loop reading/echoing, until client disconnects
try:
    conn.send("Send me data, and I will echo it back after a short delay.\n")
    while 1:
        data = conn.recv(1024)                          # recv all data queued
        if not data: break                              # client disconnected
        time.sleep(3)                                   # simulate time consuming work
        # below will detect if client disconnects during sleep
        r, w, e = select.select([conn], [], [], 0)      # more data waiting?
        print "select: r=%s w=%s e=%s" % (r,w,e)        # debug output to command line
        if r:                                           # yes, data avail to read.
            t = conn.recv(1024, socket.MSG_PEEK)        # read without remove from queue
            print "peek: len=%d, data=%s" % (len(t),t)  # debug output
            if len(t)==0:                               # length of data peeked 0?
                print "Client disconnected."            # client disconnected
                break                                   # quit program
        conn.send("-->"+data)                           # echo only if still connected
finally:
    conn.close()
checking that the socket is ready but has no data is working very well for my project. It is a simple solution
luc
A: 

It's really easy to do relyable and not messy :D

        Try
            Clients.Client.Send(BufferByte)
        Catch verror As Exception
            BufferString = verror.ToString
        End Try
        If BufferString <> "" Then
            EventLog.Text &= "User disconnected: " + vbNewLine
            Clients.Close()
        End If
David
A: 

Don't rely on any other advice but implement a ping or better put dead-man switch protocol..

rama-jka toti
A: 

apr library from apache project is a good reference for this problem. It use poll with a timeout value to check if the other side connection is broken or not.

arsane