C 插座 UPD sendto/revfrom timeout/retry

C socket UPD sendto/revfrom timeout/retry

每当超时时,如何在我拥有的以下代码中重试发送(假设使用 while 循环或类似的东西)?我删减了部分代码。

我不熟悉 C 错误代码和错误处理,所以我不知道 catch/handle 错误在哪里以及要查找什么错误代码。

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");
}

来自 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.

因此,在您的情况下,如果达到超时则继续尝试的代码如下所示:

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.
}

注意SO_SNDTIMEO是发送,SO_RCVTIMEO是接收。如果您想同时设置两者,请执行两次 setsockopt 调用。


无论如何,在我看来你是在浪费时间。如果您想一直尝试直到获得数据,那么就不要费心做任何事情 setsockopt,因为默认行为是无限期等待直到收到数据:

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