网络中超时接收的函数之一 select

本文介绍了一个用于检测套接字读取是否超时的C++函数intReadTimeOut。该函数通过使用select系统调用并在指定的时间间隔内监视特定套接字来工作。当超时发生时,函数会返回-1并设置errno为ETIMEDOUT。
int ReadTimeOut(int nSocket, unsigned int nWaitSeconds) {
//默认为0,当wait_seconds==0时,不检测直接返回0
int nRet = 0;
//需要检测超时
if (nWaitSeconds > 0) {
fd_set stReadSocketSet;  //读套接字结构体
struct timeval stTimeOut;  //超时结构体
FD_ZERO(&stReadSocketSet);


//将要监听的套接字放到读套接字结构体中
FD_SET(nSocket, &stReadSocketSet);


stTimeOut.tv_sec = nWaitSeconds;
stTimeOut.tv_usec = 0;
do {
nRet = select(nSocket + 1, &stReadSocketSet, NULL, NULL,
&stTimeOut);
//select会阻塞直到检测到事件或则超时,如果超时,select会返回0,
//如果检测到事件会返回1,如果异常会返回-1,如果是由于信号中断引起的异常errno==EINTR
//如果是有信号引起的异常则继续阻塞select,直到检测到事件或则超时
} while (nRet < 0 && errno == EINTR);
//select超时退出
if (nRet == 0) {
cout << "读超时" << endl;
nRet = -1;
errno = ETIMEDOUT;
}
//select检测到可读事件
else if (nRet == 1) {
//cout<<"可读"<<endl;
nRet = 0;
}
}
return nRet;

}

### `select` 函数超时返回机制 `select` 函数是一种用于多路复用 I/O 操作的系统调用,它允许程序监视多个文件描述符,以判断它们是否准备好进行读、写或异常事件处理。为了防止无限期阻塞,`select` 提供了超时机制,可以在指定的时间后强制返回,即使没有文件描述符处于就绪状态。 #### 超时控制结构体 `select` 函数超时控制是通过 `struct timeval` 结构体实现的,该结构体定义如下: ```c struct timeval { long tv_sec; // 秒 long tv_usec; // 微秒 }; ``` 如果将 `timeout` 参数设置为 `NULL`,则 `select` 会一直阻塞,直到至少一个文件描述符就绪。若设置为非空值,则 `select` 会在指定的时间内等待,超时后返回 0,表示超时[^1]。 例如: ```c struct timeval timeout = {3, 0}; // 设置超时为3秒 int n = select(maxfd + 1, &readfds, NULL, NULL, &timeout); if (n == 0) { printf("select timeout\n"); // 超时无事件 } ``` 这段代码中,`select` 在最多等待 3 秒后返回。如果在这段时间内没有任何文件描述符变为可读状态,则返回值为 0,并打印超时信息[^1]。 #### 超时返回的机制 当 `select` 被调用时,内核会检查传入的文件描述符集合,并判断是否有事件发生。在等待过程中,如果发生以下情况之一,`select` 将返回: - 至少一个文件描述符处于就绪状态; - 等待时间超过 `timeout` 所指定的时间,此时返回 0; - 被信号中断,此时返回 -1 并设置 `errno` 为 `EINTR`。 超时机制的实现依赖于内核的调度机制。内核会为 `select` 的等待设置一个定时器,一旦定时器到期,即使没有文件描述符就绪,也会强制 `select` 返回。 #### 超时精度与系统调度 `select` 的超时精度受限于系统的时钟粒度(通常为 10ms 或 1ms),因此实际的超时时间可能略长于设定值。此外,系统调度的延迟也可能影响超时的精确性。例如,在高负载环境下,进程可能无法立即被调度执行,导致实际等待时间超过预期[^1]。 #### 应用场景 超时机制在实际编程中非常有用,例如: - **网络通信**:用于控制连接或数据接收的最大等待时间; - **资源监控**:定期检查多个设备或文件的状态变化; - **用户交互**:在无用户输入时执行默认操作。 以下是一个完整的示例,展示了如何使用 `select` 设置超时来等待文件描述符变为可读状态: ```c #include <sys/time.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> int main() { int fd = open("testfile", O_RDONLY); if (fd < 0) { perror("open error"); return 1; } fd_set read_fds; struct timeval timeout = {2, 0}; // 2秒超时 FD_ZERO(&read_fds); FD_SET(fd, &read_fds); int ret = select(fd + 1, &read_fds, NULL, NULL, &timeout); if (ret == -1) { perror("select error"); } else if (ret == 0) { printf("Timeout: no data available\n"); } else { if (FD_ISSET(fd, &read_fds)) { printf("Data is available now.\n"); } } close(fd); return 0; } ``` 该程序尝试在 2 秒内读取文件内容,若超时则输出提示信息[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值