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. */
	}

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!