Socket Timeouts

From Nutwiki
Revision as of 17:03, 27 October 2016 by Harald (Talk | contribs) (1 revision imported)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Description

This example shows how to use socket options to detect a socket timeout.

A normal socket waits indefinitely when receiving data. It will sit there and wait for data to arrive and do nothing else in the mean time. This allows for predictable code behaviour but has one major disadvantage: A socket is unable to tell if there still is a connection or not.

Most client applications will do their best to notify the server that they are about to close the connection. In case they don't though - for example when the ethernet cable is pulled or the client crashes - the socket will wait forever.

In order to circumvent this, we can tell the socket to wait a certain time and then signal a "timeout" to the program.

NOTE: Since we have no way of knowing for sure if the connection is still alive or not, this timeout may also occur due to other things like simply no data being sent during this time. We just assume that the connection was lost if there was no data to be received during our wait.

Testing this example

In order to see this example do anything, you have to connect to your device after launching the program. The easiest way of doing this is to start up a telnet client (Windows users can press Start -> Run -> "telnet" to launch the telnet client included with Windows) and then connect to your device by typing "open DEVICE_IP 23" where DEVICE_IP is the IP of your device.

Getting the "connection still alive" message

Simply type anything you want. This will be sent to your device and tell it that the connection is still alive.

Getting the "connection timed out" message

Just don't type anything in your telnet client for 10 seconds.

Getting the "client closed connection" message

After connecting close the telnet window. Telnet will notify your device that it is now closing the connection.

Source Code

<source lang="c">

  1. include <dev/board.h>
  2. include <sys/timer.h>
  3. include <sys/socket.h>
  1. include <stdio.h>
  2. include <io.h>
  1. include <pro/dhcp.h>

static char buff[128];

int main(void) {

   TCPSOCKET *sock;
   u_long baud = 115200;
   u_long tmo = 10000;
   int rc = 0;
   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   NutRegisterDevice(&DEV_ETHER, 0x8300, 5);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   if (NutDhcpIfConfig(DEV_ETHER_NAME, NULL, 0)) {
       puts("Configuring " DEV_ETHER_NAME " failed.");
   }
   puts("Socket timeout example");
   sock = NutTcpCreateSocket();
   NutTcpSetSockOpt(sock, SO_RCVTIMEO, &tmo, sizeof(tmo));
   puts("Now awaiting connection...");
   if (NutTcpAccept(sock, 23) == 0) {
       /* We have a connection! Yay! */
       puts("Incoming connection accepted. We'll now check every second if the socket is still alive.");
       do {
           puts("The connection is still alive!");
           NutSleep(1000);
           rc = NutTcpReceive(sock, buff, sizeof(buff));
       } while (rc > 0);
       if (rc == 0) {
           puts("The connection with the client was lost due to a timeout.");
       } else {
           puts("The client closed the connection.");
       }
   }
   NutTcpCloseSocket(sock);
   for (;;);

} </source>

Details

<source lang="c"> TCPSOCKET *sock; u_long baud = 115200; u_long tmo = 10000; int rc = 0;

NutRegisterDevice(&DEV_DEBUG, 0, 0); NutRegisterDevice(&DEV_ETHER, 0x8300, 5);

freopen(DEV_DEBUG_NAME, "w", stdout); _ioctl(_fileno(stdout), UART_SETSPEED, &baud);

if (NutDhcpIfConfig(DEV_ETHER_NAME, NULL, 0)) {

   puts("Configuring " DEV_ETHER_NAME " failed.");

} </source> First we set up the debug device to be able to output to the terminal and the ethernet device so we can communicate over ethernet. Then we configure the network via DHCP (falling back to our last good configuration if that doesn't work).

The variable tmo is set to 10000 by default. This is - you guessed it - our timeout. 10000 milliseconds = 10 seconds. Adjust as you see fit.

<source lang="c"> puts("Socket timeout example");

sock = NutTcpCreateSocket(); NutTcpSetSockOpt(sock, SO_RCVTIMEO, &tmo, sizeof(tmo)); </source>

We print a title for the example and then create a socket. Pay special attention to the last line here. This is the line which sets the socket timeout option! If you don't set this, there will be no timeout at all.

<source lang="c"> puts("Now awaiting connection..."); if (NutTcpAccept(sock, 23) == 0) { </source>

Here we start listening for a connection on port 23. This call is BLOCKING, meaning it will wait until someone tries to connect and only then will the program resume execution.

<source lang="c"> do {

   puts("The connection is still alive!");
   NutSleep(1000);
   rc = NutTcpReceive(sock, buff, sizeof(buff));

} while (rc > 0); </source>

This loop will repeatly check if there is any data that we received. NutTcpReceive returns the number of bytes received or 0 in case of a timeout. If there was an error it returns -1. So we can safely assume that the connection is still alive while we receive any number of bytes > 0 and it is very likely that it has died when we get a number <= 0.

<source lang="c"> if (rc == 0) {

   puts("The connection with the client was lost due to a timeout.");

} else {

   puts("The client closed the connection.");

} </source>

With the returned number of bytes we can now distinguish between a timeout (0) and an error (-1). If we have a 0, this means "There was no data that coming in during our timeout time! The connection is probably dead!" If the client closes the connection that counts as "error" as well so we'll say exactly that if we get a -1.

<source lang="c"> NutTcpCloseSocket(sock); </source>

Since we are all well mannered, we close our used socks afterwards...

Output

<source lang="text"> Socket timeout example Now awaiting connection... Incoming connection accepted. We'll now check every second if the socket is still alive. The connection is still alive! The connection is still alive! The connection is still alive! The connection is still alive! The connection is still alive! The connection is still alive! The connection is still alive! The connection with the client was lost due to a timeout. </source>

See also