Detect TCP client disconnect

focusmaarten wrote on Tuesday, February 12, 2019:

Hey all,

I’m using FreeRTOS+TCP to start up a small server through which I serve a CLI to a connecting user. I only want a single user connected at a time, so it is important for me to detect a client disconnecting as soon as possible. For now, the only way I’ve found to figure out the client has disconnected, is to try to send or receive something and check the return value from the function.

But, if a client disconnects nicely (i.e. sends a nice TCP FIN message with all the necessary acks going back and forth), the TCP/IP stack knows that the client has disconnected, right? Is there a way I can know right away that the socket has been closed remotely?

heinbali01 wrote on Tuesday, February 12, 2019:

For your application, ipconfigTCP_KEEP_ALIVE will be helpful. It sends mini-packets to the peer, just to test if it is still alive. After 3 times “no answer”, the connection will be broken.

If your TCP server will only have 1 client at the time, consider using FREERTOS_SO_REUSE_LISTEN_SOCKET.

Normally, FreeRTOS_accept() returns a new socket. The server socket itself will never connect and it will only be used to call accept().
With the FREERTOS_SO_REUSE_LISTEN_SOCKET option, a successful FreeRTOS_accept() will return the server socket itself. After the connection has gone, please call FreeRTOS_closesocket() for that server socket.
After that, create a new server socket and call accept() again.

I wrote some code that causes a graceful disconnect here

But normally when the peer takes the initialive to disconnect ( like a telnet server ), you can use this type of code:

    for( ;; )
    {
    BaseType_t xResult;

        xResult = FreeRTOS_recv( xSocket, pcBuffer, sizeof( pcBuffer ), 0 );
        if( ( xResult < 0 ) && ( xResult != -pdFREERTOS_ERRNO_EAGAIN ) )
        {
            break;
        }
		if( xResult > 0 )
		{
			/* Do something with the data received. */
		}
    }

Now when the peer sends a shutdown, FreeRTOS_recv() will return immediately with -pdFREERTOS_ERRNO_ENOTCONN or so.

You can also poll the current status: FreeRTOS_issocketconnected().

Personally I like to use the option ipconfigSOCKET_HAS_USER_SEMAPHORE. That allows you to attach semaphore to all sockets. If any socket has an important event ( RX, TX, error, disconnect ), the semaphore will be given to. When using this technique, the sockets are used in a non-blocking way ( e.g. with FREERTOS_MSG_DONTWAIT ).
The main loop will look like this:

    for( ;; )
    {
		xSemaphoreTake (xMySemaphore, pdMS_TO_TICKS( 10000 ));
		/* Check all sockets in a non-blocking way. */
	}
1 Like

focusmaarten wrote on Tuesday, February 12, 2019:

Hey Hein, thanks for the very thorough answer :slight_smile: The semaphore mechanism might be useful, thanks for pointing it out!

Hi everyone,
link in Hein reply is not working anymore!

Are you able to use the code snippet he provided?

Five years ago, I wrote:

I wrote some code that causes a graceful disconnect here.

That post was stored by sourceforge.net, today the forum has a different host. All posts have been preserved in the new forum, but the attachments have got lost.

I do not remember what code was in the link, do you? Was it showing code of a Windows TCP client?

Today I made some new code, a simple TCP echo server which shows:

  • how a disconnection is detected
  • when a graceful shutdown is necessary
  • how a graceful shutdown is performed
  • how the FIN-flag can be sent along with the last data using the socket option FREERTOS_SO_CLOSE_AFTER_SEND

I tested all code in an STM32F4, along with a recent copy of the IP-stack.

telnet_session.zip (3.4 KB)

Find a PCAP in the ZIP file, this is the summary:

You see that the last steps are combined: sending data along with the FIN flag.

About the attachment telnet_session.zip:

telnet_session.pcap : PCAP of a session between laptop and DUD
telnet_main.c : Create a parent TCP socket and starts a task for every connection
telnet_session.c : Handles a connected child socket

Hi Hein,
it is a good example which make clear how handle API return code.
My problem is however not solved. I opened a new tread which has a better title and explanation.