select 与 fd_set

select(),确定一个或多个套接口的状态,本函数用于确定一个或多个套接口的状态,对每一个套接口,调用者可查询它的可读性、可写性及错误状态信息,用fd_set结构来表示一组等待检查的套接口,在调用返回时,这个结构存有满足一定条件的套接口组的子集,并且select()返回满足条件的套接口的数目。


用途:

确定一个或多个套接口的状态,如需要则等待。

#include <winsock.h>
int PASCAL FAR select( int nfds, fd_set FAR* readfds, fd_set FAR* writefds, fd_set FAR* exceptfds, const struct timeval FAR* timeout);

nfds:是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错!在Windows中这个参数的值无所谓,可以设置不正确。
readfds:(可选)指针,指向一组等待可读性检查的套接口。
writefds:(可选)指针,指向一组等待可写性检查的套接口。
exceptfds:(可选)指针,指向一组等待错误检查的套接口。
timeout:select()最多等待时间,对阻塞操作则为NULL。


返回值:

select()调用返回处于就绪状态并且已经包含在fd_set结构中的描述字总数;如果超时则返回0;否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError获取相应错误代码。

当返回为-1时,所有描述符集清0。

当返回为0时,超时不修改任何描述符集。

当返回为非0时,在3个描述符集里,依旧是1的位就是准备好的描述符。这也就是为什么,每次用select后都要用FD_ISSET的原因。


fd_set:

select()机制中提供一fd_set的数据结构,实际上是一long类型的数组,每一个数组元素都能与一打开的文件句柄(不管是socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一socket或文件发生了可读或可写事件。

常见用法:

fd_set set;
FD_ZERO(&set); /*将set清零使集合中不含任何fd*/
FD_SET(fd, &set); /*将fd加入set集合*/
FD_CLR(fd, &set); /*将fd从set集合中清除*/
FD_ISSET(fd, &set); /*在调用select()函数后,用FD_ISSET来检测fd在fdset集合中的状态是否变化返回整型,当检测到fd状态发生变化时返回真,否则,返回假(0)*/

以上式子中的fd为socket句柄。

在使用 `select` 函数进行 I/O 多路复用时,需要对返回值进行判断以确定有哪些文件描述符就绪。`select` 函数的返回值表示就绪文件描述符的数量,如果返回值为 0,则说明在超时时间内没有文件描述符就绪;如果返回值为 -1,则说明 `select` 函数调用失败。 在判断就绪的文件描述符时,可以使用 `FD_ISSET` 函数对每个文件描述符进行判断。`FD_ISSET` 函数返回值为非零表示该文件描述符存在于集合中,为零表示不存在于集合中。 如果需要统计有多少个文件描述符就绪,可以遍历文件描述符集合,对每个文件描述符调用 `FD_ISSET` 函数进行判断,并累加计数。 下面是一个简单的示例代码,用于统计有多少个文件描述符就绪: ```c #include <stdio.h> #include <stdlib.h> #include <sys/select.h> #include <unistd.h> int main() { fd_set rfds; // 用于存储文件描述符集合的 fd_set 结构体 int maxfd = STDIN_FILENO + 1; // 待监视的最大文件描述符值加一 struct timeval timeout = {5, 0}; // 超时时间为 5 秒 while (1) { FD_ZERO(&rfds); // 将读文件描述符集合清零 FD_SET(STDIN_FILENO, &rfds); // 将标准输入加入到读文件描述符集合 // 调用 select 函数进行 I/O 多路复用 int ret = select(maxfd, &rfds, NULL, NULL, &timeout); if (ret < 0) { perror("select error"); exit(1); } else if (ret == 0) { printf("timeout\n"); } else { int count = 0; // 遍历文件描述符集合,统计有多少个文件描述符就绪 for (int fd = 0; fd < maxfd; fd++) { if (FD_ISSET(fd, &rfds)) { count++; } } printf("%d file descriptor(s) are ready\n", count); // 如果标准输入可读,进行读操作 if (FD_ISSET(STDIN_FILENO, &rfds)) { char buf[1024]; int n = read(STDIN_FILENO, buf, sizeof(buf)); if (n < 0) { perror("read error"); exit(1); } else if (n == 0) { printf("EOF\n"); break; } else { printf("read: %s", buf); } } } } return 0; } ``` 在该程序中,当 `select` 函数返回时,程序首先遍历文件描述符集合,统计有多少个文件描述符就绪,然后通过 `FD_ISSET` 函数判断标准输入是否可读,如果可读则进行读操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值