Linux I/O多路复用系统调用(select, poll, epoll)

概念

I/O多路复用(multiplexing)的本质是通过一种机制(系统内核缓冲I/O数据),让单个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是读就绪或写就绪),能够通知程序进行相应的读写操作。Linux支持I/O多路复用的系统调用有select、poll、epoll。

select

API

#include <sys/select.h>
#include <sys/time.h>

int select(int max_fd, 
           fd_set *readset, 
           fd_set *writeset, 
           fd_set *exceptset, 
           struct timeval *timeout)
           
FD_ZERO(int fd, fd_set* fds)   //清空集合
FD_SET(int fd, fd_set* fds)    //将给定的描述符加入集合
FD_ISSET(int fd, fd_set* fds)  //将给定的描述符从文件中删除  
FD_CLR(int fd, fd_set* fds)    //判断指定描述符是否在集合中

流程

在这里插入图片描述

poll

API

#include <poll.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout);

typedef struct pollfd {
    int fd;        // 需要被检测或选择的文件描述符
    short events;  // 对文件描述符fd上感兴趣的事件
    short revents; // 文件描述符fd上当前实际发生的事件
} pollfd_t;

事件

POLLIN 有数据可读
POLLRDNORM 有普通数据可读
POLLRDBAND 有优先数据可读
POLLPRI 有紧迫数据可读
POLLOUT 写数据不会导致阻塞
POLLWRNORM 写普通数据不会导致阻塞
POLLWRBAND 写优先数据不会导致阻塞
POLLMSGSIGPOLL 消息可用

当需要监听多个事件时,使用POLLIN | POLLRDNORM设置 events 域;当poll调用之后检测某事件是否发生时,fds[i].revents & POLLIN进行判断。

epoll

epoll在Linux2.6内核正式提出,是基于事件驱动的I/O方式,相对于select和poll来说,epoll没有描述符个数限制,使用一个文件描述符管理多个描述符,将用户关心的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。优点如下:

  • 没有最大并发连接的限制,能打开的fd上限远大于1024(1G的内存能监听约10万个端口)
  • 采用回调的方式,效率提升。只有活跃可用的fd才会调用callback函数,也就是说 epoll 只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,epoll的效率就会远远高于select和poll。
  • 内存拷贝。使用mmap()文件映射内存来加速与内核空间的消息传递,减少复制开销。

epoll对文件描述符的操作有两种模式:LT(level trigger,水平触发)和ET(edge trigger)。

  • 水平触发:默认工作模式,即当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序可以不立即处理该事件;下次调用epoll_wait时,会再次通知此事件。

  • 边缘触发:当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次通知此事件。(直到你做了某些操作导致该描述符变成未就绪状态了,也就是说边缘触发只在状态由未就绪变为就绪时通知一次)。

ET模式很大程度上减少了epoll事件的触发次数,因此效率比LT模式下高。

API

#include <sys/epoll.h>

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句柄描述符,失败时返回-1。

epoll_ctl

注册要监听的事件类型。四个参数解释如下:

  • epfd表示epoll句柄;
  • op表示fd操作类型:
    • EPOLL_CTL_ADD(注册新的fd到epfd中), -
    • EPOLL_CTL_MOD(修改已注册的fd的监听事件),
    • EPOLL_CTL_DEL(从epfd中删除一个fd)
  • fd是要监听的描述符;
  • event表示要监听的事件
struct epoll_event {
    __uint32_t events;  /* Epoll events */
    epoll_data_t data;  /* User data variable */
};

typedef union epoll_data {
    void *ptr;
    int fd;
    __uint32_t u32;
    __uint64_t u64;
} epoll_data_t;

epoll_wait

等待事件的就绪,成功时返回就绪的事件数目,调用失败时返回 -1,等待超时返回 0。

  • epfd是epoll句柄
  • events表示从内核得到的就绪事件集合
  • maxevents告诉内核events的大小
  • timeout表示等待的超时事件

比较

在这里插入图片描述

应用

  • 单线程 + epoll:redis
  • 多线程 + epoll:nattyserver
  • 多进程 + epoll:nginx
  • 多核 + epoll:ntyco
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值