I know about TCP keep-alive mechanism and that freertos plus tcp supports it, but my question is a little different.
Let me describe in more detail what is happening, so that it is clear what my question is.
I have redefined macros in FreeRTOSIPConfig.h
# define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 )
# define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 )
and then I explicitly set timeouts during initialization. In this case, FreeRTOS_recv correctly uses them and returns according to the specified timeouts.
We start the board, go through initialization, make sure that there is ping, after which we connect as a TCP client from the PC to the server on the MCU, and the read, write and write stream is launched by the timer. From the client PC we send packets with a certain period.
Listen Task and create other Tasks
void prvConnectionListeningTask( void *pvParameters )
{
struct freertos_sockaddr xClient, xBindAddress;
Socket_t xListeningSocket, xConnectedSocket;
socklen_t xSize = sizeof( xClient );
static const TickType_t xReceiveTimeOut = portMAX_DELAY;
const BaseType_t xBacklog = TCP_NUMBER_OF_CLIENTS;
/* Attempt to open the socket. */
xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET4, /* Or FREERTOS_AF_INET6 for IPv6. */
FREERTOS_SOCK_STREAM, /* SOCK_STREAM for TCP. */
FREERTOS_IPPROTO_TCP);
/* Check the socket was created. */
configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );
/* Set a time out so accept() will just wait for a connection. */
FreeRTOS_setsockopt( xListeningSocket,
0,
FREERTOS_SO_RCVTIMEO,
&xReceiveTimeOut,
sizeof( xReceiveTimeOut ) );
/* Set the listening port to TCP_Port. */
memset( &xBindAddress, 0, sizeof(xBindAddress) );
xBindAddress.sin_port = ( uint16_t ) TCP_Port;
xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );
xBindAddress.sin_family = FREERTOS_AF_INET4; /* FREERTOS_AF_INET6 to be used for IPv6 */
/* Bind the socket to the port that the client RTOS task will send to. */
FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );
/* Set the socket into a listening state so it can accept connections.
The maximum number of simultaneous connections is limited to 20. */
FreeRTOS_listen( xListeningSocket, xBacklog );
for( ;; )
{
/* Wait for incoming connections. */
xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );
Client_ConnectedSocket=xConnectedSocket;
configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET );
/* Spawn a RTOS task to handle the connection. */
Client_Connect=true;
xTaskCreate( prvServerConnectionRead,
"TCP_Connection_Read",
usUsedStackSize,
( void * ) xConnectedSocket,
tskIDLE_PRIORITY,
&RTOS_Handle_Read );
xTaskCreate( prvServerConnectionWrite,
"TCP_Connection_Write",
usUsedStackSize,
( void * ) xConnectedSocket,
tskIDLE_PRIORITY,
&RTOS_Handle_Write );
xTaskCreate( prvServerConnectionTimer,
"TCP_Connection_Timer",
usUsedStackSize,
0,
tskIDLE_PRIORITY,
&RTOS_Handle_Timer );
}
}
Read Task
void prvServerConnectionRead( void *pvParameters )
{
uint8_t cReceivedString[ ipconfigTCP_MSS ];
Socket_t xConnectedSocket;
static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 3000 );
static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 3000 );
TickType_t xTimeOnShutdown;
ulConnectionCount++;
xConnectedSocket = ( Socket_t ) pvParameters;
FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xReceiveTimeOut ) );
for( ;; )
{
if(Client_Connect)
{
/* Receive data on the socket. */
Size = FreeRTOS_recv( xConnectedSocket, IN_Array, sizeof( IN_Array ), 0 );
if( Size > 0 )
{
vTaskResume(RTOS_Handle_Write);
}
else
{
if(Size==0)
{
//break;
}
else
{
/* Socket closed? */
if(Size==-pdFREERTOS_ERRNO_ENOMEM)
break;
if(Size==-pdFREERTOS_ERRNO_ENOTCONN)
break;
if(Size==-pdFREERTOS_ERRNO_EINTR)
break;
if(Size==-pdFREERTOS_ERRNO_EINVAL)
break;
}
}
}
else
{
break;
}
}
Client_Connect=false;
/* Initiate a shutdown in case it has not already been initiated. */
FreeRTOS_shutdown( xConnectedSocket, FREERTOS_SHUT_RDWR );
/* Wait for the shutdown to take effect, indicated by FreeRTOS_recv()
returning an error. */
xTimeOnShutdown = xTaskGetTickCount();
do
{
if( FreeRTOS_recv( xConnectedSocket, cReceivedString, ipconfigTCP_MSS, 0 ) < 0 )
{
break;
}
} while( ( xTaskGetTickCount() - xTimeOnShutdown ) < tcpechoSHUTDOWN_DELAY );
/* Finished with the socket and the task. */
FreeRTOS_closesocket( xConnectedSocket );
vTaskResume(RTOS_Handle_Write);
vTaskDelete( NULL );
}
Write Task
void prvServerConnectionWrite( void *pvParameters )
{
int32_t lSent;
Socket_t xConnectedSocket;
xConnectedSocket = ( Socket_t ) pvParameters;
for( ;; )
{
if(Client_Connect==false)
{
vTaskDelete(RTOS_Handle_Timer);
vTaskDelete( NULL );
}
vTaskSuspend(NULL);
if(Timer_Size==0)
{
lSent = FreeRTOS_send( xConnectedSocket, IN_Array, Size, 0 );
}
else
{
lSent = FreeRTOS_send( xConnectedSocket, Timer_Array, Timer_Size, 0 );
Timer_Size=0;
}
if( lSent < 0 )
{
/* Socket closed */
Client_Connect=false;
vTaskDelete(RTOS_Handle_Timer);
vTaskDelete( NULL );
}
}
}
Timer Task
void prvServerConnectionTimer()
{
for (int i=0;i<20;i++)
{
Timer_Array[i]=i+48;
Timer_Size=20;
}
Timer_Array[Timer_Size-1]='\0';
for( ;; )
{
Timer_Size=20;
vTaskResume(RTOS_Handle_Write);
vTaskDelay(500);
}
}
Accordingly, the MCU returns the received packets back to the client, and also sends other packets to the client according to the timer (500 ms). At the same time, according to the read timeout (FreeRTOS_recv==0), we do not disconnect the client and do not clear the connection.
If you disconnect the network cable from the PC, then after 32 seconds FreeRTOS_recv will return from the next reading with the value -pdFREERTOS_ERRNO_ENOTCONN, which means that the socket has closed or was closed.
This is clearly due to attempts to send packets according to the 500 ms timer, because if you turn it off, then I do not know when FreeRTOS_recv will return with a negative value and whether it will return at all (this did not happen within a reasonable time).
Actually, the question is what it depends on when the socket decides that attempts to send packets are pointless and closes it, which will lead to FreeRTOS_recv==-pdFREERTOS_ERRNO_ENOTCONN.
Thanks