IO 多路复用模型
IO 多路复用模型
1. select
为了能够完成IO多路复用机制,可选用 select 函数。
nfds 所监听的最大的文件描述符+1(用来限定范围)
fd_set 文件描述符集合
timeout 超时时间
FD_ZERO 清空监听队列,初始化
FD_SET 加入一个 fd 到 fdset 中。
FD_ISSET 判断一个 fd 是否在就绪队列中
FD_CLR 将 fd 从 fdset 中移除
int select(int nfds,
fd_set *_Nullable restrict readfds,
fd_set *_Nullable restrict writefds,
fd_set *_Nullable restrict exceptfds,
struct timeval *_Nullable restrict timeout);
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
select 缺陷
- fd_set 从用户态拷贝的内核态。
- fd_set 是一个位图,1024bit, 更改大小困难。
- 监听集合和就绪集合高度耦合。
- 大量监听,少量就绪
2. epoll
epoll 内部使用红黑树作监听集合,线性表作就绪集合。
epoll 的数据结构是文件对象,内部由监听集合和就绪集合组成。(内核态)
当就绪后,会将就绪集合拷贝到用户态。
epoll_create :epoll_create() returns a file descriptor referring to the new epoll instance.
epoll_ctl :add, modify, or remove entries in the interest list of the epoll
epoll_wait :The epoll_wait() system call waits for events on the epoll(7) instance referred to by the file descriptor epfd.
epoll_create(int size);
epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
// op 就是 option, 不同的操作
// EPOLL_CTL_ADD
// EPOLL_CTL_MOD
// EPOLL_CTL_DEL
//以下是epoll_event的数据结构
struct epoll_event {
uint32_t events; /* Epoll events 事件属性*/
epoll_data_t data; /* User data variable 额外信息*/
};
// 四选一的union
union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
};
typedef union epoll_data epoll_data_t;
int epoll_wait(int epfd,
struct epoll_event *events,
int maxevents,
int timeout);
示例
void test0() {
int netfd;
// 1. 创建epoll文件对象
int epfd = epoll_create(1);
// 2. 增加监听,设置监听属性
struct epoll_event event;
// 事件的读属性, event 可以多次使用
event.events = EPOLLIN;
event.data.fd = STDIN_FILENO;
epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event);
event.events = EPOLLIN;
event.data.fd = netfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, netfd, &event);
// 3. 等待文件就绪
struct epoll_event ready_set[10];
while (1) {
int ready_num = epoll_wait(epfd, ready_set, 10, -1);
// 4. 遍历就绪集合
for (int i = 0; i < ready_num; i++) {
if (ready_set[i].data.fd == STDIN_FILENO) {
// ...
} else if (ready_set[i].data.fd == netfd){
//...
}
}
}
}