IO多路复用机制

来源:互联网 发布:奥巴马医保 知乎 编辑:程序博客网 时间:2024/06/06 00:05
上篇文章讲到IO模式,这篇文章讲其中一种模式-IO多路复用模式。
IO多路复用技术根据实现不同,分为三种,select、poll、epoll。
1、select
int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select把监听的文件描述符分为3类,readfds、writefdds、exceptfds。
1.1 进程调用select后会阻塞
1.2 当有描述符就绪时,readfds可读或writefds可写或exceptfds有excpet或超时,函数返回
1.3 select返回后,通过遍历fdset,找到就绪的描述符
1.4 对就绪描述符进行读/写操作

2、poll
int poll (struct pollfd *fds, unsigned int nfds, int timeout);
struct pollfd {
    int fd;        /* file descriptor */
    short events;  /* requested events to watch */
    short revents; /* returned events witnessed */
};
和select不同之处在于,
2.1 poll用结构pollfd来表示select中的三个fds
2.2 pollfd包括了要监视的时间和发生的时间,而select采用“参数-值”的传递方式
2.3 pollfd没有最大数量限制,而select有最大数量限制


3、epoll
epoll用到三个接口

3.1 int epoll_create(int size);
3.1.1 epoll_create创建一个epoll监听句柄
3.1.2 参数size用来告诉内核这个epoll句柄监听的IO数目。
3.1.3 参数size并不是最大的监听数目,只是对内核初始化结构的建议。

3.2 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
struct epoll_event {
  __uint32_t events;  /* Epoll events */
  epoll_data_t data;  /* User data variable */
};

//events可以是以下几个宏的集合:
EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

3.2.1 对epoll fd执行op操作
3.2.2 -epfd:epoll描述符,调用epoll_create的返回值
3.2.3 -op:  添加EPOLL_CTL_ADD、删除EPOLL_CTL_DEL、修改EPOLL_CTL_MOD
3.2.4 -fd:  是需要监听的f文件描述符
3.2.5 -epoll_event:是告诉内核需要监听什么事

3.3 int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
3.3.1 等待epfd上的io事件,最多返回maxevents个事件。
3.3.2 参数events用来从内核得到事件的集合
3.3.3 maxevents告之内核这个events有多大,maxevents的值不能大于创建epoll_create()时的size,
3.3.4 参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。

3.4 工作模式
3.4.1 水平触发模式(level trigger)
当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用epoll_wait时,会再次响应应用程序并通知此事件。

3.4.2 边缘触发模式(edge trigger)
当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次响应应用程序并通知此事件