使用socket选项SO_RCVTIMEO和SO_SNDTIMEO设置超时时间

Posted qq_34132502

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用socket选项SO_RCVTIMEO和SO_SNDTIMEO设置超时时间相关的知识,希望对你有一定的参考价值。

socket选项SO_RCVTIMEOSO_SNDTIMEO,他们分别 用来设置socket接受 / 发送数据超时时间。
因此,这两个选项仅对数据接收和发送相关的socket专用系统调用有效(sendsendmsgrecvrecvmsgacceptconnect

在程序中,我们可以根据系统调用的返回值以及errno来判断超时时间是否已到,进而决定是否开始处理定时任务。

下例为设置connect超时时间:

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

// 超时连接函数
int timeout_connect(const char* ip, int port, int time) {
    int ret = 0;
    struct sockaddr_in address;
    bzero(&address, sizeof(address));
    address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &address.sin_addr);
    address.sin_port = htons(port);

    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
    assert(sockfd >= 0);

    // 通过选项SO_RCVTIMEO和SO_ENDTIMEO所设置的超时事件类型是timeval,
    // 这和select系统调用的超时时间参数类型相同
    struct timeval timeout;
    timeout.tv_sec = time;
    timeout.tv_usec = 0;
    socklen_t len = sizeof(timeout);
    ret = setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, len);
    assert(ret != -1);

    ret = connect(sockfd, (struct sockaddr*)&address, sizeof(address));
    if (ret == -1) {
        // 超时对应的错误号是EINPROGRESS。
        // 下面这个条件如果成立,我们就可以处理定时任务了
        if (errno == EINPROGRESS) {
            printf("connection timeout, process timeout logic\\n");
            return -1;
        }
        printf("error occur when connecting to server\\n");
        return -1;
    }
    return sockfd;
}

int main(int argc, char* argv[]) {
    if (argc <= 2) {
        printf("usage: %s ip_address port_number\\n", basename(argv[0]));
        return 1;
    }
    const char* ip = argv[1];
    int port = atoi(argv[2]);

    int sockfd = timeout_connect(ip, port, 10);
    if (sockfd < 0) {
        return 1;
    }
    return 0;
}

【注】
timeval

struct timeval {
     time_t       tv_sec;   
     suseconds_t  tv_usec;
};

其中tv_sec为时间的秒部分,tv_usec为时间的毫秒部分。

以上是关于使用socket选项SO_RCVTIMEO和SO_SNDTIMEO设置超时时间的主要内容,如果未能解决你的问题,请参考以下文章

通过 SO_RCVTIMEO 套接字选项在 Ruby 中设置套接字超时

如何在 C 中设置 SO_RCVTIMEO 选项仅用于读取而不用于接受

使用SO_REVTIMEO套接字选项为recvfrom设置超时

linux网路编程--网络超时检测

Linux(程序设计):60---定时机制之SO_RCVTIMEOSO_SNDTIMEO选项(附设置connect超时时间案例)

socket_connect没有超时