How to implement a timeout in read function call?
If you set the socket do operate in non-blocking mode, each call to read will read only the data currently available (if any). So this is effectively equal to an immediate timeout.
You can set non-blocking mode on a socket with a function like this:
int setnonblock(int sock) {
int flags;
flags = fcntl(sock, F_GETFL, 0);
if (-1 == flags)
return -1;
return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}
(For more information about reading from non-blocking sockets see the read
man page)
You don't say what the OS is but if you're running under Linux, you could use the select call. It returns if there is something to read on the file descriptor or you can set it up so that it will timeout if there is nothing to read. The return code indicates which.
As an alternative to select()
, for the specific case of a serial port (terminal) you can use tcsetattr()
to put the file descriptor into non-canonical mode, with a read timeout.
To do this, unset the ICANON
flag, and set the VTIME
control character:
struct termios termios;
tcgetattr(filedesc, &termios);
termios.c_lflag &= ~ICANON; /* Set non-canonical mode */
termios.c_cc[VTIME] = 100; /* Set timeout of 10.0 seconds */
tcsetattr(filedesc, TCSANOW, &termios);
Note VTIME
is measured in tenths of a second, and that the type used for it is typically an unsigned char
, meaning that the maximum timeout is 25.5 seconds.
select() takes 5 parameters, first the highest file descriptor + 1, then a fd_set for read, one for write and one for exceptions. The last parameter is a struct timeval, used for timeout. It return -1 on error, 0 on timeout or the number of file descriptors in the sets that are set.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
int main(void)
{
fd_set set;
struct timeval timeout;
int rv;
char buff[100];
int len = 100;
int filedesc = open( "dev/ttyS0", O_RDWR );
FD_ZERO(&set); /* clear the set */
FD_SET(filedesc, &set); /* add our file descriptor to the set */
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
rv = select(filedesc + 1, &set, NULL, NULL, &timeout);
if(rv == -1)
perror("select"); /* an error accured */
else if(rv == 0)
printf("timeout"); /* a timeout occured */
else
read( filedesc, buff, len ); /* there was data to read */
close(filedesc);
}