[c++] Detecting TCP Client Disconnect

Let's say 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, a client is supposed to send a close command, but what if it disconnects manually or loses network connection altogether? How can the server detect or handle this?

This question is related to c++ sockets tcp

The answer is


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.


Try looking for EPOLLHUP or EPOLLERR. How do I check client connection is still alive

Reading and looking for 0 will work in some cases, but not all.


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.


In python you can do a try-except statement like this:

try:
  conn.send("{you can send anything to check connection}")
except BrokenPipeError:
  print("Client has Disconnected")

This works because when the client/server closes the program, python returns broken pip error to the server or client depending on who it was that disconnected.


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.


I toyed with a few solutions but this one seems to work best for detecting host and/or client disconnection in Windows. It is for non-blocking sockets, and derived from IBM's example.

char buf;
int length=recv(socket, &buf, 0, 0);
int nError=WSAGetLastError();
if(nError!=WSAEWOULDBLOCK&&nError!=0){
    return 0;
}   
if (nError==0){
    if (length==0) return 0;
}

In python you can do a try-except statement like this:

try:
  conn.send("{you can send anything to check connection}")
except BrokenPipeError:
  print("Client has Disconnected")

This works because when the client/server closes the program, python returns broken pip error to the server or client depending on who it was that disconnected.


In TCP there is only one way to detect an orderly disconnect, and that is by getting zero as a return value from read()/recv()/recvXXX() when reading.

There is also only one reliable way to detect a broken connection: by writing to it. After enough writes to a broken connection, TCP will have done enough retries and timeouts to know that it's broken and will eventually cause write()/send()/sendXXX() to return -1 with an errno/WSAGetLastError() value of ECONNRESET, or in some cases 'connection timed out'. Note that the latter is different from 'connect timeout', which can occur in the connect phase.

You should also set a reasonable read timeout, and drop connections that fail it.

The answer here about ioctl() and FIONREAD is compete nonsense. All that does is tell you how many bytes are presently in the socket receive buffer, available to be read without blocking. If a client doesn't send you anything for five minutes that doesn't constitute a disconnect, but it does cause FIONREAD to be zero. Not the same thing: not even close.


TCP has "open" and a "close" procedures in the protocol. Once "opened", a connection is held until "closed". But there are lots of things that can stop the data flow abnormally. That being said, the techniques to determine if it is possible to use a link are highly dependent on the layers of software between the protocol and the application program. The ones mentioned above focus on a programmer attempting to use a socket in a non-invasive way (read or write 0 bytes) are perhaps the most common. Some layers in libraries will supply the "polling" for a programmer. For example Win32 asych (delayed) calls can Start a read that will return with no errors and 0 bytes to signal a socket that cannot be read any more (presumably a TCP FIN procedure). Other environments might use "events" as defined in their wrapping layers. There is no single answer to this question. The mechanism to detect when a socket cannot be used and should be closed depends on the wrappers supplied in the libraries. It is also worthy to note that sockets themselves can be reused by layers below an application library so it is wise to figure out how your environment deals with the Berkley Sockets interface.


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.


The return value of receive will be -1 if connection is lost else it will be size of buffer.

void ReceiveStream(void *threadid)
{
    while(true)
    {
        while(ch==0)
        {
            char buffer[1024];
            int newData;
            newData = recv(thisSocket, buffer, sizeof(buffer), 0);
            if(newData>=0)
            {
                std::cout << buffer << std::endl;
            }
            else
            {
                std::cout << "Client disconnected" << std::endl;
                if (thisSocket)
                {
                    #ifdef WIN32
                        closesocket(thisSocket);
                        WSACleanup();
                    #endif
                    #ifdef LINUX
                        close(thisSocket);
                    #endif
                }
                break;
            }
        }
        ch = 1;
        StartSocket();
    }
}

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.


It's really easy to do: reliable and not messy:

        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

I toyed with a few solutions but this one seems to work best for detecting host and/or client disconnection in Windows. It is for non-blocking sockets, and derived from IBM's example.

char buf;
int length=recv(socket, &buf, 0, 0);
int nError=WSAGetLastError();
if(nError!=WSAEWOULDBLOCK&&nError!=0){
    return 0;
}   
if (nError==0){
    if (length==0) return 0;
}

The return value of receive will be -1 if connection is lost else it will be size of buffer.

void ReceiveStream(void *threadid)
{
    while(true)
    {
        while(ch==0)
        {
            char buffer[1024];
            int newData;
            newData = recv(thisSocket, buffer, sizeof(buffer), 0);
            if(newData>=0)
            {
                std::cout << buffer << std::endl;
            }
            else
            {
                std::cout << "Client disconnected" << std::endl;
                if (thisSocket)
                {
                    #ifdef WIN32
                        closesocket(thisSocket);
                        WSACleanup();
                    #endif
                    #ifdef LINUX
                        close(thisSocket);
                    #endif
                }
                break;
            }
        }
        ch = 1;
        StartSocket();
    }
}

It's really easy to do: reliable and not messy:

        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

In TCP there is only one way to detect an orderly disconnect, and that is by getting zero as a return value from read()/recv()/recvXXX() when reading.

There is also only one reliable way to detect a broken connection: by writing to it. After enough writes to a broken connection, TCP will have done enough retries and timeouts to know that it's broken and will eventually cause write()/send()/sendXXX() to return -1 with an errno/WSAGetLastError() value of ECONNRESET, or in some cases 'connection timed out'. Note that the latter is different from 'connect timeout', which can occur in the connect phase.

You should also set a reasonable read timeout, and drop connections that fail it.

The answer here about ioctl() and FIONREAD is compete nonsense. All that does is tell you how many bytes are presently in the socket receive buffer, available to be read without blocking. If a client doesn't send you anything for five minutes that doesn't constitute a disconnect, but it does cause FIONREAD to be zero. Not the same thing: not even close.


"""
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()

Try looking for EPOLLHUP or EPOLLERR. How do I check client connection is still alive

Reading and looking for 0 will work in some cases, but not all.


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.


"""
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()

Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to sockets

JS file gets a net::ERR_ABORTED 404 (Not Found) mysqld_safe Directory '/var/run/mysqld' for UNIX socket file don't exists WebSocket connection failed: Error during WebSocket handshake: Unexpected response code: 400 TypeError: a bytes-like object is required, not 'str' Failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED No connection could be made because the target machine actively refused it 127.0.0.1 Sending a file over TCP sockets in Python socket connect() vs bind() java.net.SocketException: Connection reset by peer: socket write error When serving a file How do I use setsockopt(SO_REUSEADDR)?

Examples related to tcp

What does "app.run(host='0.0.0.0') " mean in Flask What is the difference between HTTP 1.1 and HTTP 2.0? Sending a file over TCP sockets in Python Telnet is not recognized as internal or external command How to open port in Linux adb connection over tcp not working now Understanding [TCP ACKed unseen segment] [TCP Previous segment not captured] How do I debug error ECONNRESET in Node.js? Differences between TCP sockets and web sockets, one more time Is SMTP based on TCP or UDP?