select()阻塞函数
发布人:shili8
发布时间:2024-12-27 04:01
阅读次数:0
**Select() 阻塞函数**
在 Unix/Linux 系统中,`select()` 是一个用于等待多个文件描述符的 I/O 可读或可写状态改变的阻塞函数。它允许程序同时监控多个 socket、管道和其他类型的文件描述符,直到其中任何一个达到可读或可写状态。
**函数原型**
cint select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
**参数解释**
* `nfds`:要监控的文件描述符总数。
* `readfds`、`writefds` 和 `exceptfds`:三个 `fd_set` 结构体,分别用于存储可读、可写和异常事件的文件描述符集合。
* `timeout`:一个 `struct timeval` 结构体,指定了等待超时时间。
**返回值**
`select()` 函数返回以下值:
* 当至少有一个文件描述符达到可读或可写状态时,返回已监控的文件描述符总数(即 `nfds`)。
* 如果所有文件描述符都没有达到可读或可写状态,并且超时时间已经过去,则返回0。
* 如果发生错误,则返回 -1。
**fd_set 结构体**
`fd_set` 是一个用于存储一组文件描述符的结构体。它可以使用以下函数进行操作:
* `FD_ZERO(fdset)`:清空 `fdset` 中的所有文件描述符。
* `FD_SET(fd, fdset)`:将 `fd` 添加到 `fdset` 中。
* `FD_CLR(fd, fdset)`:从 `fdset` 中移除 `fd`。
**示例代码**
c#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/select.h> #define MAX_CLIENTS10int main() { int client_sockets[MAX_CLIENTS]; fd_set read_fds, write_fds; // 初始化客户端 socket 数组 for (int i =0; i < MAX_CLIENTS; i++) { client_sockets[i] = -1; } while (1) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); // 将可读和可写的客户端 socket 添加到对应集合中 for (int i =0; i < MAX_CLIENTS; i++) { if (client_sockets[i] != -1) { FD_SET(client_sockets[i], &read_fds); FD_SET(client_sockets[i], &write_fds); } } struct timeval timeout; timeout.tv_sec =5; // 等待超时时间为5 秒 timeout.tv_usec =0; int num_ready = select(MAX_CLIENTS, &read_fds, &write_fds, NULL, &timeout); if (num_ready >0) { // 有客户端 socket 可读或可写,进行处理 for (int i =0; i < MAX_CLIENTS; i++) { if (FD_ISSET(client_sockets[i], &read_fds)) { printf("Client %d is ready to read ", i); } if (FD_ISSET(client_sockets[i], &write_fds)) { printf("Client %d is ready to write ", i); } } } else if (num_ready ==0) { // 等待超时,进行其他处理 printf("Waiting timeout, doing other tasks... "); } else { // 发生错误,进行错误处理 perror("select()"); exit(1); } // 在本例中,我们不进行任何客户端 socket 处理,只是重复监控 } return0; }
**注释**
* 本示例代码使用 `fd_set` 结构体来存储可读和可写的客户端 socket。
* 每次循环中,我们清空 `read_fds` 和 `write_fds` 集合,然后将所有客户端 socket 添加到对应集合中。
* 我们使用 `select()` 函数监控这些 socket,直到其中任何一个达到可读或可写状态。
* 当有客户端 socket 可读或可写时,我们进行处理;当等待超时时,我们进行其他处理;当发生错误时,我们进行错误处理。
**总结**
`select()` 阻塞函数允许程序同时监控多个文件描述符,直到其中任何一个达到可读或可写状态。它返回已监控的文件描述符总数,如果超时时间已经过去,则返回0。如果发生错误,则返回 -1。使用 `fd_set` 结构体可以方便地存储和操作一组文件描述符。本示例代码展示了如何使用 `select()` 函数监控客户端 socket,并进行相应处理。