select函数
原理
select通过一个文件描述符集合(fd_set)来监控多个文件描述符。它会检查这些文件描述符是否准备好进行读、写或异常操作。fd_set是一个位数组,每个位对应一个文件描述符。select会扫描这个数组,检查每个文件描述符的状态。
使用方法
使用FD_SET宏将文件描述符添加到fd_set中,然后调用select函数。select函数会返回准备好操作的文件描述符的数量,并更新fd_set,将未准备好的文件描述符从集合中移除。
优点
- select的API相对简单,容易理解和使用。
- 几乎所有操作系统都支持select,具有很好的兼容性。
缺点
- select的最大文件描述符数量通常受限于系统定义的FD_SETSIZE(通常是1024)。当监控大量文件描述符时,性能会显著下降。
- select需要扫描整个fd_set来确定哪些文件描述符准备好,这在文件描述符数量较多时效率较低。
- select需要为每个文件描述符分配一个位,当文件描述符数量较多时,会浪费较多的内存资源。
- 不适用于需要处理大量文件描述符的场景。
- #include <sys/select.h>
- #include <sys/time.h>
- int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
- //nfds:需要监控的文件描述符的最大值加1
- //readfds:指向可读文件描述符集合的指针
- //writefds:指向可写文件描述符集合的指针
- //exceptfds:指向异常条件文件描述符集合的指针
- //timeout:超时时间
- //ret:返回集合中文件描述符的数量,调用完成后没有改变的文件描述符会被清除
复制代码- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/select.h>
- #include <unistd.h>
- int main() {
- // 创建两个文件描述符,用于示例
- int pipefds[2];
- if (pipe(pipefds) == -1) {
- perror("pipe");
- exit(EXIT_FAILURE);
- }
- // 初始化文件描述符集合
- fd_set readfds;
- FD_ZERO(&readfds);
- FD_SET(pipefds[0], &readfds); // 读端
- FD_SET(STDIN_FILENO, &readfds); // 标准输入
- // 设置超时时间
- struct timeval timeout;
- timeout.tv_sec = 5; // 5秒超时
- timeout.tv_usec = 0;
- // 调用 select
- int ret = select(pipefds[0] + 1, &readfds, NULL, NULL, &timeout);
- if (ret == -1) {
- perror("select");
- exit(EXIT_FAILURE);
- } else if (ret == 0) {
- printf("Select timeout\n");
- } else {
- if (FD_ISSET(pipefds[0], &readfds)) {
- printf("Pipe read end is ready for reading\n");
- }
- if (FD_ISSET(STDIN_FILENO, &readfds)) {
- printf("Standard input is ready for reading\n");
- }
- }
- // 关闭文件描述符
- close(pipefds[0]);
- close(pipefds[1]);
- return 0;
- }
复制代码 poll函数
原理
poll使用一个pollfd结构数组来监控文件描述符。每个pollfd结构包含一个文件描述符、要监控的事件(如读、写)和事件状态。poll函数会检查这些结构,确定哪些文件描述符已经准备好指定的事件。
使用方法
创建一个pollfd数组,为每个文件描述符设置要监控的事件,然后调用poll函数。poll函数会返回准备好操作的文件描述符的数量,并更新每个pollfd结构的事件状态。
优点
- poll没有像select那样的文件描述符数量限制,可以处理更多的文件描述符。
- poll直接返回准备好操作的文件描述符,不需要像select那样扫描整个集合,效率相对较高。
缺点
- poll需要为每个文件描述符分配一个pollfd结构,当文件描述符数量较多时,会占用较多的内存资源。
- 虽然poll没有文件描述符数量限制,但在文件描述符数量非常多时,性能也会受到影响,因为poll需要逐个检查每个pollfd结构。
- 不适用于高并发的场景
- struct pollfd {
- int fd; // 文件描述符
- short events; // 需要监控的事件
- short revents; // 实际发生的事件
- };
- #include <poll.h>
- int poll(struct pollfd *fds, nfds_t nfds, int timeout);
- //fds:指向 pollfd 结构数组的指针
- //nfds:pollfd 结构数组的大小。
- //timeout:超时时间(毫秒)。如果设置为 -1,则表示阻塞直到有文件描述符准备好。
- //ret:>0 状态改变的文件描述符的数量 =0 超时 -1,表示调用发生错误。
复制代码- #include <stdio.h>
- #include <stdlib.h>
- #include <poll.h>
- #include <unistd.h>
- int main() {
- // 创建两个文件描述符,用于示例
- int pipefds[2];
- if (pipe(pipefds) == -1) {
- perror("pipe");
- exit(EXIT_FAILURE);
- }
- // 初始化 pollfd 结构数组
- struct pollfd fds[2];
- fds[0].fd = pipefds[0]; // 读端
- fds[0].events = POLLIN;
- fds[1].fd = STDIN_FILENO; // 标准输入
- fds[1].events = POLLIN;
- // 调用 poll
- int ret = poll(fds, 2, -1); // 阻塞等待
- if (ret == -1) {
- perror("poll");
- exit(EXIT_FAILURE);
- }
- // 检查结果
- if (ret > 0) {
- if (fds[0].revents & POLLIN) {
- printf("Pipe read end is ready for reading\n");
- }
- if (fds[1].revents & POLLIN) {
- printf("Standard input is ready for reading\n");
- }
- }
- // 关闭文件描述符
- close(pipefds[0]);
- close(pipefds[1]);
- return 0;
- }
复制代码 来源:新程序网络收集,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |