新知

Linux Socket 编程领域,为了处理大量连接请求场景,需要使用非阻塞IO和复用。

select , poll 是Linux API 提供的IO 复用方式。

自从Linux 2.6 加入epoll之后,高性能服务器领域得到广泛应用,Nginx 就是使用epoll 来实现IO复用支持高并发。

select模型

 int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
 select函数监视   的  文件描述符  分3类, writefds,readfds,exceptfds.
调用后select 函数会阻塞,直到有描述符就绪(有数据 可读,可写,或者有except),
            或者超时(timeout 指定等待时间, 立即返回设为null)。
select 函数有返回后,通过遍历fd_set,来找到就绪的描述符。
 
select 的优势 几乎所有平台支持,良好的跨平台性。
select 的劣势 单进程能够监视的文件描述符的数量存在最大限制。Linux 一般为1024。
 
 
poll模型
int poll (struct pollfd *fds, unsigined int nfds, int timeout);

不同于select 使用三个参数 表示三个fdset 的方式,poll 使用一个pollfd 的指针实现。

struct pollfd{
  int fd;/* 文件描述 */
  short events;  /**/   
  short revents; /**/  
}

pollfd 结构体包含了要监视的 event 和发生的  event.

pollfd 没有数量限制(但是数量过大后性能也会下降)。

和 select 函数一样,poll  返回后,需要轮询pollfd 来获取就绪的描述符。

 select 和 poll 都需要在返回后,通过遍历文件描述符 来 获取已经就绪的socket.

大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述数量的增长,效率也会线性下降。

epoll模型

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_create 函数   创建epoll 文件描述符 size 一个建议值。

epoll_ctl 完成对 描述符fd  执行 op 操作控制, event 与 fd 关联的监听事件。

    op 操作有三种  添加 EPOLL_CTL_ADD,删除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。

    分别添加/删除/修改 对fd 的监听事件。

epoll_wait 等待epfd 上的IO事件,最多返回maxevents个事件。

在select/poll中,进程只有在调用一定方法后,内核才对所有监视的文件描述符进行扫描,

而epoll 事先通过epoll_ctl 注册一个文件描述符,一旦某个文件描述就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait时便得到通知。

epoll 的优点

1.监视的描述符数量不受限制,1GB 内存大约时10万左右。cat /proc/sys/fs/file-max

2.IO的效率不会随着监视fd 的数量增长而下降。epoll 不同于select/poll 的轮询方式,而是通过每个fd定义的回调函数来实现。就绪的fd才会执行回调函数。

3.支持水平触发,边沿触发俩种模式。

水平触发模式:文件描述符 状态改变后,如果没有采取行动,它将后面反复通知,这种情况相对简单,libevent 等开源库采用这种模式。

边沿触发模式:只告诉进程哪些文件描述符 刚刚变为就绪态,只说一遍,如果没有采取行动,不会再次告知。性能更高,Nginx使用边沿触发。

4.mmap 加速内核与用户空间的信息传递。epoll 是通过内核与用户空间mmap 同一块内存,避免无谓的内存拷贝。

原文地址:https://www.cnblogs.com/zhco/p/9526357.html