概述
不说废话,争取一遍讲明白,让大家少翻几篇博客。
select: 采用 文件描述集合+扫描 来实现
int select (int __nfds,
fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
struct timeval *__restrict __timeout)
fd_set可以简单理解为一个1024位的二进制数,
我想要注册文件描述符为20进去呢,就把第20位置为1。然后把这个三个存在于用户态的fd_set复制进内核区,当有事件触发的时候select函数就会返回,这个时候他比较含蓄,她不告诉我到底是那个时间发生了,她让我一个一个找,所以我需要一个一个的遍历这个集合。线性扫描+反复拷贝+最大数量导致性能低下。
extern int poll (
struct pollfd *__fds,
nfds_t __nfds,
int __timeout);
struct pollfd {
int fd; /* File descriptor to poll. */ short int events; /* Types of events poller cares about. */
short int revents; /* Types of events that actually occurred. */ };
poll本质和select是一样的,只不过用了一个能看懂的结构体 poll_events ,这个结构体里面保存了一个文件描述符号,一个目标时间,剩下的一个是发生事件,poll调用传入一串由这个结构体组成的数组,复制到内核以后,内核以链表的形态保存,并且做一次遍历,如果发生相关事件,就把结构体最后一个成员置为,然后返回这个数组,如果没有发生目标事件,就会挂起当前进程。总而言之 遍历+拷贝 也是服务器性能的大杀手,但是没有1024这个上限了。
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);
epoll把io复用分成了三个模块 创建 注册 阻塞
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 */
}
向epoll_crt注册一个事件 的参数:
epoll描述符,注册描述符,添加/删除/修改 epoll结构体
epoll_event结构体里面是这个描述符的数据和事件。
调用wait函数需要给一个空结构体数组,wait会把发生的事件写到里面,这样给我们的都是发生的,我们就不需要再去寻找到底哪个发生了。另外epoll模块也不需要频繁的在用户态和内核态发生拷贝。
关于ET和LT模式,实际上是一种出发epollwait返回的机制,举一个read监控的案例:监控read套接字又两种状态,套接字可读,套接字不可读:在LT模式下,只要套接字可读就会触发wait返回。
ET不是这样,ET只有发生不可读到可读的一个跳变才会触发wait返回。如果在ET模式下调用read,但是没有读完,那么这个时候套接字仍旧是可读状态,再来新数据还是可读状态,还是不会触发wait返回,也就是永远不会返回了,所以在ET模式下要读到EAGIN错误(缓冲区已空)让他将状态变成不可读,这样一来,再有数据可读的时候,状态会从不可读跳变为可读,会触发。
最后
以上就是纯情冰淇淋为你收集整理的linux下的epoll select poll 机制与区别 LT ET区别的全部内容,希望文章能够帮你解决linux下的epoll select poll 机制与区别 LT ET区别所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复