maheshg
maheshg

Reputation: 339

how to use timeouts with read() on a socket in c++ on Unix

I want to use read() with ioctl(), but want to control how much time read should wait, by using a timeout. Any idea on how to do this?

so far what i know is:

//CLIENT.cpp
struct timeval tv={1,0};
setsockopt( mysocket, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv));
connect(mysocket, &sock_dest, sizeof(struct sockaddr));
len = read(mysocket, buffer, 10);

I tried using a 5 sec delay on server, but it did not timeout...

Upvotes: 0

Views: 11081

Answers (3)

Chris Dodd
Chris Dodd

Reputation: 126175

You can do what you want by setting up an alarm to interrupt the system call. You need some basic setup somewhere in main or early in your program init process:

#include <signal.h>

sig_atomic_t alarm_counter;

void alarm_handler(int signal) {
    alarm_counter++;
}

void setup_alarm_handler() {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = alarm_handler;
    sa.flags = 0;
    if (sigaction(SIGALRM, &sa, 0) < 0)
        die("Can't establish signal handler");
}
// call setup_alarm_handler in main

Then, you can use it like:

alarm(10); // set a 10 second timeout
(len = connect(mysocket, &sock_dest, sizeof(struct sockaddr))) < 0 ||
(len = read(mysocket, buffer, 10));
alarm(0); // cancel alarm if it hasn't happened yet
if (len == -1 && errno == EINTR)
    // timed out before any data read
else if (len == -1)
    // other error

This way you can have a timeout for a sequence of calls (this will timeout if either the connect or the read takes too long individually or in total), rather than having to figure out how long each call took, so you know how long to wait for each subsequent call.

Upvotes: 2

ColoradoEric
ColoradoEric

Reputation: 71

Are you sure it's blocking on the read, or is it perhaps blocking on the connect()? I don't believe that the SO_RCVTIMEO (and SO_SNDTIMEO) options affect the connect() behavior.

In general, I like to use non-blocking sockets (fcntl with O_NONBLOCK), and then catch the EWOULDBLOCK errno and do a select() with the socket in the read set and the desired timeout.

Upvotes: 0

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153792

ioctl() won't do what you want. To use a timeout on reads you need to use poll() or the older interface select() (I'd use poll()). The timeout set with SO_RCVTIMEO may get reset every time new data is received. So, for your example it may wait for up to 10 seconds. poll() returns after the specified timeout telling you whether there is any data. Once that is the case you can just read whatever is there using non-blocking read().

Upvotes: 4

Related Questions