本文主要是介绍IO多路复用,select、poll和epoll简介,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 前言
- 1、select
- 2、poll
- 3、epoll
- 4、总结
前言
select、poll 和 epoll 是 Linux 下用于多路复用 I/O(Input/Output)的系统调用,它们用于监视多个文件描述符,以查看哪个文件描述符上有可读、可写或发生了异常的事件。
1、select
select 是最早的多路复用 I/O 机制之一。它允许你监控多个文件描述符,以检测哪些文件描述符有事件发生。它通过修改一个位掩码来表示每个文件描述符的状态。
- 使用方法
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>int main() {fd_set read_fds;int max_fd;struct timeval timeout;// 设置文件描述符集合FD_ZERO(&read_fds);FD_SET(STDIN_FILENO, &read_fds);max_fd = STDIN_FILENO;// 设置超时时间timeout.tv_sec = 5;timeout.tv_usec = 0;int ret = select(max_fd + 1, &read_fds, NULL, NULL, &timeout);if (ret == -1) {perror("select");exit(EXIT_FAILURE);} else if (ret == 0) {printf("Timeout occurred!\n");} else {if (FD_ISSET(STDIN_FILENO, &read_fds)) {printf("Data is available on stdin.\n");}}return 0;
}
- select的几个宏
/*
用于将文件描述符添加到文件描述符集合中
fd:要添加的文件描述符。
fdset:要修改的文件描述符集合。
*/
void FD_SET(int fd, fd_set *fdset);/*
用于从文件描述符集合中删除指定的文件描述符
fd:要删除的文件描述符。
fdset:要修改的文件描述符集合。
*/
void FD_CLR(int fd, fd_set *fdset);/*
用于检查文件描述符集合中是否包含指定的文件描述符
fd:要检查的文件描述符。
fdset:要检查的文件描述符集合。
*/
int FD_ISSET(int fd, fd_set *fdset);/*
用于清空文件描述符集合
fdset:要清空的文件描述符集合。
*/
void FD_ZERO(fd_set *fdset);
- select函数的五个参数含义
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 会一直等待直到有事件发生。
- 优缺点分析
(1)优点
简单: select 的接口简单易用,广泛支持。
兼容性: 几乎所有 UNIX-like 操作系统都支持 select。
(2)缺点
文件描述符限制: 默认情况下,select 的文件描述符数量限制为 1024(可以通过重新编译内核或修改宏 FD_SETSIZE 增加,但不建议)。
性能瓶颈: 每次调用 select 都需要将文件描述符集合从用户态复制到内核态,这在文件描述符数量很大时可能会带来性能问题。
线性扫描: select 需要线性扫描文件描述符集合,效率较低。
2、poll
poll 是 select 的改进版,功能和 select 类似,但解决了一些 select 的局限性。poll 使用一个结构体数组来表示文件描述符及其相关的事件,而不是使用位掩码。
- 使用方法
#include <poll.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>int main() {struct pollfd fds;int timeout = 5000; // 超时时间:5秒fds.fd = STDIN_FILENO;fds.events = POLLIN;fds.revents = 0;int ret = poll(&fds, 1, timeout);if (ret == -1) {perror("poll");exit(EXIT_FAILURE);} else if (ret == 0) {printf("Timeout occurred!\n");} else {if (fds.revents & POLLIN) {printf("Data is available on stdin.\n");}}return 0;
}
- poll函数的参数
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
fds: pollfd 结构体数组,每个结构体表示一个文件描述符及其事件。
nfds: pollfd 结构体数组的大小。
timeout: 超时时间,单位是毫秒。如果设置为 -1,poll 将无限期等待直到有事件发生;如果设置为 0,poll 将立即返回。
- pollfd结构体
struct pollfd {int fd; // 文件描述符short events; // 监控的事件类型short revents; // 实际发生的事件
};
- 事件常量
POLLIN: 文件描述符可读(例如,有数据可读或连接可接受)。
POLLOUT: 文件描述符可写(例如,缓冲区有足够空间)。
POLLERR: 文件描述符发生错误。
POLLHUP: 文件描述符挂起(通常用于检测连接的关闭)。
POLLNVAL: 文件描述符无效(例如,关闭了的文件描述符)。
- 优缺点分析
(1)优点
文件描述符数量无上限: 没有像 select 那样的文件描述符数量限制。
灵活性: 可以同时监控多个文件描述符及其事件。
(2)缺点
性能瓶颈: 每次调用 poll 时都需要遍历 pollfd 数组,这在监控大量文件描述符时会带来性能开销。
3、epoll
4、总结
select 适合处理少量文件描述符和需要跨平台支持的场景。它简单易用,但有文件描述符数量限制,并且在文件描述符数量多时性能较差。
poll 适合需要监控大量文件描述符的场景。它没有文件描述符数量限制,但在大量文件描述符时性能依然较差。
这篇关于IO多路复用,select、poll和epoll简介的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!