XMind: ZEN - Trial Version
select API模型:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select 用三个fd数组分别表示要监听可读、可写、异常事件的描述符数组。
readfds、writefds、exceptfds这三个数组既是输入参数,也是输出参数。 它们也用于内核空间想用户空间传递就绪的文件描述符。
select使用模型:
while(1) {
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(fd0, rfds); //
FD_SET(fd1, wfds); //
ret = select(MAX_FDS+1, &rfds, &wfds, &efds, &tv);
if (FD_ISSET(fd0, &rfds)) {
...
} else (FD_ISSET(fd1, &wfds)) {
...
}
}
select调用时,会通过三个数组参数把要监听的文件描述符(和对应的事件)传递给内核。
select因有就绪事件而返回时,内核再把相应就绪的文件描述符通过三个数组返回。
此时程序需要遍历监听文件描述符,判断其是否在相应的就绪fds中。
select模型有如下缺陷
#include <poll.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
struct pollfd {
int fd; /* file descriptor */
short events; /* events to look for */
short revents; /* events returned */
};
poll函数讲描述符和事件区关联起来了。 同时讲注册到事件和就绪到事件区分开来。 内核只需要修改revents。
int main() {
int ret = 0;
struct pollfd pollfds[1];
char buf[10];
pollfds[0].fd = 1;
pollfds[0].events = POLLIN;
while(1) {
memset(buf, 0, sizeof(buf));
ret = poll(pollfds, 2, 0);
if (pollfds[0].revents == POLLIN) {
scanf("%s", buf);
printf("buf:%s\n", buf);
}
}
return 0;
}
可以看出,相比select函数,poll把监听描述符和事件到设置从for循环中移动出来了。
相对select的改进
仍然存在都不足:
epoll 是linux特有的API
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
与select和poll只有一个函数不同,epoll API提供了一组函数来实现IO复用。
struct epoll_event event;
struct epoll_event *events; // 用户保存内核返回的就绪事件
int efd;
int listenfd = 0; // 监听标准输入
efd = epoll_create(0);
event.data.fd = listenfd;
event.events = EPOLLIN | EPOLLET;
ret = epoll_ctl (efd, EPOLL_CTL_ADD, listenfd, &event);
while(1) {
int n, i;
n = epoll_wait(efd, events, MAXEVENTS, -1);
for (i = 0; i < n; i++) {
if (events[i].events & EPOLLIN) {
// handle EpollIN, 可以从events[i].data.fd获取文件描述符
}
}
epoll所做的改进
文件描述符的操作有LT和ET两种方式,epoll两种模式都支持。
epoll将就绪事件通知应用程序后,应用程序可以不用立即处理。 下次调用epoll_wait的时候,还会继续通知。
epoll将就绪事件通知应用程序后,应用程序**必须**立即处理。 下次调用epoll_wait的时候,不会重复通知。
举个栗子,如果是ET模式,epoll_wait检测到事件可读性,通知应用程序后,应用程序就需要吧本次可读读数据都读完。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。