Socket 编程发展

    据 w3techs 在 2015 年 8 月 10 日的统计数据表明,在全球 Top 1000 的网站中,有 43.7% 的网站在使用 Nginx,这使得 Nginx 超越了 Apache,成为了高流量网站最信任的 Web 服务器足足有两年时间。已经确定在使用 Nginx 的站点有:Wikipedia,WordPress,Reddit,Tumblr,Pinterest,Dropbox,Slideshare,Stackexchange 等,可以持续罗列好几个小时,他们太多了。

    下图是统计数据:

    select 模型

    下面是 select 函数接口:

    select 函数监视的文件描述符分 3 类,分别是 writefdsreadfdsexceptfds

    • 调用后 select 函数会 阻塞,直到有描述符就绪(有数据 可读、可写、或者有 except),或者超时(timeout 指定等待时间,如果想立即返回,设为 null 即可)。
    • select 函数返回后,通过 遍历 fd_set,来找到就绪的描述符。

    select 目前几乎在所有的平台上支持,其良好 跨平台支持 是一大 优点

    select 的一个 缺点 在于 单个进程能够监视的文件描述符的数量存在最大限制,在 Linux 上一般为 1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低。

    poll 模型

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

    • 同时,pollfd 并没有最大数量限制(但是数量过大后性能也是会下降)。

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

    从上面看,selectpoll 都需要在返回后,通过遍历文件描述符来获取已经就绪的 socket。事实上,同时连接的大量客户端在某一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。

    epoll 模型

    epoll 的接口如下:

    主要是 epoll_createepoll_ctlepoll_wait 三个函数。

    • epoll_create 函数创建 epoll 文件描述符,参数 size 并不是限制了 epoll 所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。
    • epoll_ctl 完成对指定描述符 fd 执行 op 操作控制,event 是与 fd 关联的监听事件。op 操作有三种:添加 EPOLL_CTL_ADD,删除 ,修改 EPOLL_CTL_MOD。分别对应着添加、删除和修改对 fd 的监听事件。
    • epoll_wait 等待 epfd 上的 IO 事件,最多返回 maxevents 个事件。

    模型之间的对比

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

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

    libevent_benchmark

    epoll优点

    主要是以下几个方面:

    1. IO 的效率不会随着监视的 fd 数量的增长而下降。(如上图所示)

      • epoll 不同于 selectpoll 轮询的方式,而是通过每个 fd 定义的 回调函数 来实现的。
      • 只有就绪的 fd 才会执行回调函数。
    2. 支持水平触发和边沿触发两种模式

      • 水平触发模式,文件描述符状态发生变化后,如果没有采取行动,它后面将 反复通知,这种情况下编程相对简单,libevent 等开源库很多都是使用的这种模式。
    3. mmap 加速内核与用户空间的信息传递。