LINUX下select设置超时

本文深入探讨了Linux环境下通过非阻塞connect和select函数设置连接超时的方法,包括创建socket、设置非阻塞模式、调用connect进行连接尝试、使用select检查连接状态,以及超时处理策略。提供了从套接字创建到连接成功或超时的完整流程,适合网络编程和系统管理员使用。

LINUX设置连接超时方法:

非阻塞 connect:

在一个 TCP 套接字被设置为非阻塞之后调用 connect ,connect 会立即返回  EINPROGRESS  错误,表示连接操作正在进行中,但是仍未完成,与此同时 TCP 三次握手操作会同时进行。在这之后,我们可以通过调用 select 来检查这个链接是否建立成功



在阻塞套接字的一般情况下,connect ()直到客户端对SYN消息的ACK消息到达之前才会返回。使connect()调用具有超时机制的一个方法是让套接字成为非阻塞的套接字体,然后用select()来等待它完成。
s = socket(AF_INET, SOCK_STREAM, 0);
//下面获取套接字的标志
if ((flags = fcntl(s, F_GETFL, 0)) < 0) {
    //错误处理
}

//下面设置套接字为非阻塞
if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
    //错误处理
}

if ((retcode = connect(s, (struct sockaddr*)&peer, sizeof(peer)) && 
    errno != EINPROGRESS) {
   //因为套接字设为NONBLOCK,通常情况下,连接在connect()返回
   //之前是不会建立的,因此它会返回EINPROGRESS错误,如果返回
   //任何其他错误,则要进行错误处理
}

if (0 == retcode) {  //如果connect()返回0则连接已建立
    //下面恢复套接字阻塞状态
    if (fcntl(s, F_SETFL, flags) < 0) {
        //错误处理
    }

    //下面是连接成功后要执行的代码
    
    exit(0)
}


(要设备send/recv超时只需从此处开始修改相应值,前面不用)
FD_ZERO(&rdevents);
FD_SET(s, &rdevents);  //把先前的套接字加到读集合里面
wrevents = rdevents;   //写集合
exevents = rdevents;   //异常集合

tv.tv_sec = 5;  //设置时间为5秒
tv_tv_usec = 0;

retcode = select(s+1, &rdevents, &wrevents, &exevents, &tv);
if (retcode < 0) {  //select返回错误???
    //错误处理
}
else if (0 == retcode) {  //select 超时???
    //超时处理
}
esle {
    //套接字已经准备好
    if (!FD_ISSET(s, &rdevents) && !FD_ISSET(s, &wrevents)) {
        //connect()失败,进行错处理
    }

    if (getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
        //getsockopt()失败,进行错处理
    }

    if (err != 0) {
        //connect()失败,进行错处理
    }
(send/recv超时到此为止,返回send()/recv()函数)


    //到这里说明connect()正确返回
    //下面恢复套接字阻塞状态
    if (fcntl(s, F_SETFL, flags) < 0) {
        //错误处理
    }

    //下面是连接成功后要执行的代码      
    exit(0)



处理非阻塞 connect 的步骤:   
第一步,创建 socket,返回套接字描述符;  
第二步,调用 fcntl 或 ioctlsocket 把套接口描述符设置成非阻塞;  
第三步,调用 connect 开始建立连接;  
第四步,判断连接是否成功建立:  
    A)如果 connect 返回 0 ,表示连接成功(服务器和客户端在同一台机器上时就有可能发生这种情况);  
    B)调用 select 来判定连接建立的是否成功;  
      如果 select 返回 0 ,则表示在 select 的超时时间内未能成功建立连接;我们需要返回超时错误给用户,同时关闭连接,以防止TCP三次握手继续进行下去;  
      如果 select 返回大于 0 的值,则说明检测到可读或可写或异常的套接字描述符存在;此时我们可以通过调用 getsockopt 来检测集合中的套接口上是否存在待处理的错误,如果连接建立是成功的,则通过 getsockopt(sockfd,SOL_SOCKET,SO_ERROR,(char *)&error,&len) 获取的 error 值将是 0 ,如果建立连接时遇到错误,则 error 的值是连接错误所对应的 errno 值,比如ECONNREFUSED,ETIMEDOUT等。



### Linux C语言 select 函数超时设置与使用教程 在Linux环境下,`select()`函数可以用于监控多个文件描述符的状态变化,并且可以通过设置超时参数来控制等待的时间。以下是对`select()`函数超时设置的详细说明和示例代码。 #### 1. `select()`函数原型 `select()`函数的原型如下: ```c #include <sys/select.h> int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); ``` - `nfds`: 监控的最大文件描述符值加1。 - `readfds`, `writefds`, `exceptfds`: 分别表示需要监控的可读、可写和异常条件的文件描述符集合。 - `timeout`: 指定`select()`函数的超时时间。如果为`NULL`,则`select()`将无限期等待[^2]。 #### 2. 超时参数设置 `timeout`参数是一个指向`struct timeval`结构体的指针,定义如下: ```c struct timeval { long tv_sec; // 秒 long tv_usec; // 微秒 }; ``` - 如果`timeout`被设置为`NULL`,则`select()`将一直阻塞直到有文件描述符就绪[^2]。 - 如果`timeout->tv_sec = 0`且`timeout->tv_usec = 0`,则`select()`将立即返回,不进行任何等待。 - 如果`timeout`被设置为非零值,则`select()`将在指定的时间内等待文件描述符变为就绪状态。 #### 3. 示例代码 以下是一个使用`select()`函数并设置超时的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/select.h> int main() { int ret; fd_set readfds; struct timeval timeout; // 初始化文件描述符集合 FD_ZERO(&readfds); FD_SET(STDIN_FILENO, &readfds); // 设置超时时间为5秒 timeout.tv_sec = 5; timeout.tv_usec = 0; printf("Waiting for input...\n"); // 调用select函数 ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &timeout); if (ret == -1) { perror("select"); } else if (ret == 0) { printf("Timeout occurred! No data after 5 seconds.\n"); } else { if (FD_ISSET(STDIN_FILENO, &readfds)) { char buffer[1024]; memset(buffer, 0, sizeof(buffer)); fgets(buffer, sizeof(buffer), stdin); printf("Input received: %s", buffer); } } return 0; } ``` #### 4. 注意事项 - 当`select()`返回时,`timeout`参数可能被修改以反映剩余时间。因此,在每次调用`select()`之前,需要重新初始化`timeout`参数[^2]。 - 如果`select()`因信号中断而返回-1,可以通过检查`errno`是否为`EINTR`来判断中断原因[^2]。 #### 5. 总结 通过合理设置`timeout`参数,`select()`函数可以在指定时间内等待文件描述符变为就绪状态,从而避免程序无限期阻塞。上述示例展示了如何在标准输入上使用`select()`并设置超时
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值