I/O多路复用的简单操作及理解

简介: I/O多路复用


本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。


三种方式:

  • select()

    • 底层为线性表
    • 跨平台通用
  • poll()

    • Linux Api, Windows中对应为WSAPoll()
    • 底层为线性表
  • epoll()

    • 底层为红黑树
    • Linux专属
    • 效率最高

做了什么

  • 将本该由程序员处理的缓冲区维护工作交给了内核,由内核监测缓冲区上的事件

select()

#include <sys/select.h>

struct timeval {
    time_t          tv_sec;  //秒
    suseconds_t     tv_usec; //微秒
};

itn select(int nfds, fd_set *reabufs, fd_set *writefds,
            fd_set *exceptfds, struct timeval *timeout);
  • nfds:委托内核监测的文件描述符数量

    • 三个集合中最大的文件描述符+1 / 直接1024(上限值)
    • 内核需要线性遍历这些集合中的文件描述符,+1这个值是循环结束的条件
    • Windows中无效,指定为-1即可
  • readfds:内核只检测这个集合中文件描述符的读缓冲区

    • 传入传出参数
    • 常用
  • writefds:内核只检测这个集合中文件描述符对应的写缓冲区

    • 传入传出参数
    • 不常用,不需要使用的话可以指定为NULL
  • execptfds:内核只检测这个集合中文件描述符是否有异常状态

    • 传入传出参数
  • timeout:超时时长,用来强制接触select()的阻塞

    • NULL:检测不到就绪的文件描述符就一直阻塞
    • 固定秒数:一直检测不到就绪的文件描述符,指定时长后解除阻塞,返回0
    • 0:不等待,不阻塞
  • 返回值:

    • 大于0:成功,返回已就绪的文件描述符的个数
    • 等于-1:调用失败
    • 等于0:超时,没有检测到就绪的文件描述符

tips

  • fd_set是一个1024bit大小的东西,nfds的上限1024就是由此得来,fd_set拥有1042个标志位,每一个位都对应着0 / 1,代表着这个位对应的文件描述符的状态,由内核维护每一个位的状态

基于select处理服务器端并发的操作流程

  • 对fd_set标志位处理( FD_ZERO() \ FD_SET() )
  • 轮询检测指定fd( FD_ISSET() )

code

select_server

poll()

  • 不具备可移植性,性能又弱于epoll,一般不使用此函数

epoll()

概述

  • eventpoll
  • 高效:

    • 底层为红黑树
    • 使用回调机制而不是线性扫描,处理效率不会随着集合的变大而下降
    • 并没有使用共享内存
  • 没有最大文件描述符限制(取决于硬件)

函数

#include <sys/epoll.h>

// 创建epoll实例
int epoll_create(int size);
// 管理epoll红黑树(添加, 修改, 删除)
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
// 检测epoll树中是否有就绪的文件描述符
int epoll_wait(int epfd, struct epoll_event *event, int maxevents, int timeout);

工作模式

水平模式

  • level trigger(LT)
  • 默认工作方式,支持blockno-block socket
  • 通知次数多,易于编写,但效率低
  • 读事件:

    • 文件描述符对应的读缓冲区还有数据,读事件就会被触发,epoll_wait()解除阻塞
    • 读缓冲区一次没有读完,读事件一直触发
    • 读数据是被被动的,必须通过读事件才知道有数据到达了,因此对于读事件的检测是必须
  • 写事件:

    • 如果文件描述符对应的写缓冲区可写,写事件就会被触发,epoll_wait()解除阻塞
    • 如果写缓冲区没有写满,写事件一直触发
    • 写数据是主动的,并且写缓冲区一般都是可写的(未满),所以对写事件的检测不是必须
    • code

    epoll_server_LT

边缘触发

  • edge trigger(ET)
  • 高速工作模式,只支持no-block socket
  • 通知次数少(只有新事件才会通知),编写较难,但效率高
  • 读事件:

    • 当读缓冲区有新的数据进入,读事件触发一次,没有新数据不会触发事件
    • 如果数据没有被全部取走,并且没有新数据进入,读时间不会再次出发,只通知一次
    • 如果数据被全部取走或只取走一部分,此时有新数据进入,读事件触发,并且只通知一次
  • 写事件:

    • 当写缓冲区可写,写事件只触发一次
    • 写缓冲区从不满到被写满,期间写事件只触发一次
    • 写缓冲区从满到不满,状态变为可写,写事件只会被触发一次
  • code

epoll_server_ET

ET模式下注意事项

  • 一个程序如果使用了ET模式,就应该使用非阻塞的fd,避免在read或write时使其中一个任务被"锁死"
  • 如何编程:

    • 使用非阻塞的fd
    • 在read或write返回EAGAIN时才进入epoll_wait的调用
  • EAGAIN:

    • nonblock fd read 返回 EAGAIN:缓冲区数据被读完
    • nonblock fd write 返回 EAGAIN:表示缓冲区被写满(待数据发送出去之后,缓冲重新进入可写状态,会触发EPOLLOUT事件,不会造成 epoll_wait被挂起)

SHOW ME THE CODE

  • 设置非阻塞fd
int cfd = accept(serverFd, NULL, NULL);\

int flag = fcntl(cfd, F_GETFL);
flag |= O_NONBLOCK;
fcntl(cfd, F_SETFL, flag);
  • 设置ET模式
ev.events = EPOLLIN | EPOLLET;
  • 设置EAGIAN的判定
while (1) {
  int len = recv(fd, buf, sizeof(buf), 0);
  if (len == -1) {
    if (errno == EAGAIN) { // 判断是异常终止或数据接收完毕
      printf("数据接受完毕\n");
        break;
    }
    perror("recv error");
    exit(1);
  } else if (len == 0) {
    printf("客户端断开连接!\n");
    epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
    break;
  }
}

参考

  1. Linux 教程
  2. epoll 相关问题简单说明
目录
相关文章
|
域名解析 弹性计算 Apache
WordPress自助建站教程
本场景将基于一台基础环境为CentOS 7.8的ECS(云服务器)实例,在LAMP环境中安装WordPress,帮助您快速搭建自己的云上博客。
|
人工智能 自动驾驶 数据安全/隐私保护
人工智能的伦理困境:我们如何确保AI的道德发展?
【10月更文挑战第21天】随着人工智能(AI)技术的飞速发展,其在各行各业的应用日益广泛,从而引发了关于AI伦理和道德问题的讨论。本文将探讨AI伦理的核心问题,分析当前面临的挑战,并提出确保AI道德发展的建议措施。
|
消息中间件 存储 JSON
RocketMQ 消费进度持久化
本文介绍了RocketMQ中消费进度的持久化机制,包括普通消息和延迟消息的消费偏移量是如何存储的。普通消息的消费进度存储于`consumerOffset.json`文件,格式为`{Topic}@{ConsumerGroup}`,而延迟消息则存储于`delayOffset.json`文件,以`{delayLevel:offset}`的形式记录。文章详细分析了相关文件内容及代码实现,并指出Broker分别以5秒和10秒的间隔进行持久化操作。
283 6
|
存储 人工智能 搜索推荐
【2023年第十一届泰迪杯数据挖掘挑战赛】C题:泰迪内推平台招聘与求职双向推荐系统构建 建模及python代码详解 问题一
本文详细介绍了第十一届泰迪杯数据挖掘挑战赛C题的解决方案,包括爬取泰迪内推平台的招聘与求职信息、构建企业和求职者画像、开发岗位匹配度与求职者满意度模型以及设计招聘求职双向推荐模型的步骤和Python代码实现。
213 2
【2023年第十一届泰迪杯数据挖掘挑战赛】C题:泰迪内推平台招聘与求职双向推荐系统构建 建模及python代码详解 问题一
|
SQL 消息中间件 存储
小象超市(原美团买菜) 的大屏图表
小象超市(原美团买菜) 的大屏图表
559 0
|
机器学习/深度学习 存储 数据采集
数字化与数智化有什么区别?
数字化(Digitalization)是将信息转换为数字(即计算机可读)格式的过程。数智化(Digital and Intelligent Transformation)是数字智慧化与智慧数字化的融合。
716 1
|
编解码 前端开发 iOS开发
响应式图片的实现(含picture标签、srcset属性、sizes属性的使用方法,设备像素比详解)
响应式图片的实现(含picture标签、srcset属性、sizes属性的使用方法,设备像素比详解)
371 0
|
数据采集 安全 搜索推荐
什么是谷歌独立站?
答案是:谷歌独立站就是利用Wordpress或者Shopify做的个人网站。 谷歌独立站的特点 内容为王 一个成功的谷歌独立站始终注重内容的质量和原创性。 高质量的内容能够吸引更多的用户,同时也更容易获得其他网站的链接,从而提高在Google搜索结果中的排名。 结构清晰 谷歌独立站的结构通常非常清晰,每个页面都有明确的目的,易于导航。 这不仅有助于提供良好的用户体验,也使谷歌的爬虫更容易抓取和索引网站内容。
1788 1
什么是谷歌独立站?
|
关系型数据库 OLAP OLTP
|
Web App开发 前端开发 安全
Chrome浏览器进程:了解多进程架构优劣的探索
Chrome浏览器进程:了解多进程架构优劣的探索