Pokud nastavíte, aby soket fungoval v neblokujícím režimu, každé volání ke čtení přečte pouze aktuálně dostupná data (pokud existují). To se tedy v podstatě rovná okamžitému časovému limitu.
Na zásuvce můžete nastavit neblokovací režim pomocí funkce, jako je tato:
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);
}
(Další informace o čtení z neblokujících soketů naleznete v read
manuálová stránka)
Neříkáte, jaký je operační systém, ale pokud používáte Linux, můžete použít volání select. Vrátí se, pokud je v deskriptoru souboru něco ke čtení, nebo jej můžete nastavit tak, aby vypršel časový limit, pokud není co číst. Návratový kód označuje který.
Jako alternativa k select()
, pro konkrétní případ sériového portu (terminálu) můžete použít tcsetattr()
přepne deskriptor souboru do nekanonického režimu s časovým limitem čtení.
Chcete-li to provést, zrušte nastavení ICANON
příznak a nastavte VTIME
řídicí znak:
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);
Poznámka VTIME
se měří v desetinách sekundy a typ používaný pro tento typ je obvykle unsigned char
, což znamená, že maximální časový limit je 25,5 sekundy.
select() bere 5 parametrů, nejprve nejvyšší deskriptor souboru + 1, pak fd_set pro čtení, jeden pro zápis a jeden pro výjimky. Posledním parametrem je struct timeval, používaný pro časový limit. Vrátí -1 při chybě, 0 při časovém limitu nebo počtu deskriptorů souborů v sadách, které jsou nastaveny.
#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);
}