C socket UPD sendto/revfrom timeout/retry

1k views Asked by At

How can I retry sending (let's say using a while loop or something similar) in the following code that I have, whenever I have a timeout? I abridged some parts of my code.

I am not familiar with C error codes and error handling so I don't know where to catch/handle the error and what error code to look for.

sock = socket(create socket....)
if (sock < 0 ) { 
    exit(EXIT_FAILURE); 
} 
servaddr initializations.....

sendto(sock, etc etc........);

struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&timeout,sizeof(timeout)) < 0) {
    perror("Error");
}
addrlen = sizeof(servaddr);
if(recvfrom (sock, etc, etc......) < 0)
{
     printf("revfrom failed.\n");
}
1

There are 1 answers

0
Marco Bonelli On BEST ANSWER

From man 7 socket:

SO_RCVTIMEO and SO_SNDTIMEO:

Specify the receiving or sending timeouts until reporting an error. The argument is a struct timeval. If an input or output function blocks for this period of time, and data has been sent or received, the return value of that function will be the amount of data transferred; if no data has been transferred and the timeout has been reached, then -1 is returned with errno set to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for connect(2)) just as if the socket was specified to be nonblocking. If the timeout is set to zero (the default), then the operation will never timeout. Timeouts only have effect for system calls that perform socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect for select(2), poll(2), epoll_wait(2), and so on.

So, in your case, the code to keep trying if the timeout is reached would look something like this:

struct timeval timeout = {.tv_sec = 5, .tv_usec = 0};

if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
    perror("setsockopt failed");
    // Handle error
}

// ...

while (sendto(sock, /*...*/) == -1) {
    if (errno != EAGAIN && errno != EWOULDBLOCK) {
        // Some unexpected error happened.
        perror("sendto failed");
    }

    // Otherwise it was a timeout, just continue trying.
}

Note that SO_SNDTIMEO is for sending, and SO_RCVTIMEO is for receiving. If you want to set both then do two setsockopt calls.


In any case, it seems to me like you are wasting your time with this. If you want to keep trying until you get data, then just don't bother doing any setsockopt, as the default behavior is to wait indefinitely until data is received:

If the timeout is set to zero (the default), then the operation will never timeout.