个人学习-Linux-IO多路复用

[1]confirmwz博客:Epoll原理解析https://blog.csdn.net/armlinuxww/article/details/92803381;

[2]hechen知乎专栏: 一文看懂IO多路复用https://zhuanlan.zhihu.com/p/115220699;

weixin_39934085博客: io多路复用的原理和实现_彻底理解 IO 多路复用实现机制https://blog.csdn.net/weixin_39934085/article/details/110715861;

[3]UNIX网络编程:卷1[M].[美]W.Richard Stevens,Bill Fenner, Andrew M.Rudoff著;

IO多路复用,实际就是通过单线程或者单进程检测若干个文件描述符时候可以执行IO的能力;

当Linux作为服务端,使用socket和客户端进行通信时,执行顺序是,服务端socket启动,调用监听套接字,然后等待服务器链接;

// 伪代码
int lfd = socket();
// 绑定;
bind();
// 监听;
listen(lfd, 128);
// 等待链接:
int cfd = accept();
/* 使用cfd进行通信 */

​ 多路IO的思路,实际就是把所有需要操作的文件描述符交付内核监控,一旦文件描述符准备就绪,就通知应用程序进行处理,没有就绪,则应用程序阻塞,Linux主要存在三种方式select, poll, epoll 进行管理。(多路指多路网络连接,复用指同一进程)

函数原型:

SYNOPSIS
     #include
     void
     FD_CLR(fd, fd_set *fdset);  // 把文件描述符从fd_set中清楚
     void
     FD_COPY(fd_set *fdset_orig, fd_set *fdset_copy);
     int
     FD_ISSET(fd, fd_set *fdset);  // 判断fd是否在set中
     void
     FD_SET(fd, fd_set *fdset);   // 把fd插入fd_set
     void
     FD_ZERO(fd_set *fdset);  //  把fd_set全赋0进行初始化;
     int
     select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds,
         fd_set *restrict errorfds, struct timeval *restrict timeout);
        /*
            nfds 最大文件描述符;
            readfds : 读文件描述符集;
            writefds: 写文件描述符集;
            errorfds: 标准错误文件描述符集;
            timeout: 检索遍历超时时间;
        */

RETURN VALUES
     select() returns the number of ready descriptors that are contained in the
     descriptor sets, or -1 if an error occurred.  If the time limit expires,
     select() returns 0.  If select() returns with an error, including one due
     to an interrupted call, the descriptor sets will be unmodified and the
     global variable errno will be set to indicate the error.

调用过程:

  • 使用copy_from_user 从客户空间拷贝fd_set到内核空间;
  • 注册回调函数_pollwait();
  • 遍历所有fd, 调用相应poll方法;
  • __pollwait的主要工作,是把current挂进等待队列,不同设备存在不同的等待队列,对于tcp而言,对应port接收一条网络连接就会唤醒队列;
  • poll给fd_set赋值,用来描述文件是否就绪;
  • 把fd_set从内核空间拷贝回用户空间;

内核监控的fd_set被唤起的条件:

​ readfds:该文件描述符里的读缓冲区存在可读数据;

​ writers: 该描述符写缓冲区可写;

​ errorfds: 见识文件错误异常;

缺点:

select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。这样所带来的缺点是:

  • 单个进程所打开的FD是有限制的,通过 FD_SETSIZE 设置,默认1024 ;
  • 每次调用 select,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大;
  • 对 socket 扫描时是线性扫描,采用轮询的方法,效率较低(高并发)

相关API原型:

 #include
int epoll_create(int size);
int epoll_create1(int flags);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
typedef union epoll_data {
               void        *ptr;
               int          fd;
               uint32_t     u32;
               uint64_t     u64;
           } epoll_data_t;

struct epoll_event {
               uint32_t     events;      /* Epoll events */
               epoll_data_t data;        /* User data variable */
};
op:
EPOLL_CTL_ADD  // 添加文件描述符和相应event到epfd;
EPOLL_CTL_MOD  // 修改对应文件描述符事件;
EPOLL_CTL_DEL  // 删除相应文件描述符;
events:
EPOLLIN
The associated file is available for read(2) operations.

EPOLLOUT
The associated file is available for write(2) operations.

EPOLLRDHUP (since Linux 2.6.17)
Stream socket peer closed connection, or shut down writing half of connection.  (This flag is especially useful for writing simple  code to detect peer shutdown when using Edge Triggered monitoring.)
EPOLLPRI
There is urgent data available for read(2) operations.

EPOLLERR
Error  condition  happened on the associated file descriptor.  epoll_wait(2) will always wait for this event; it is not necessary to set it in events.

EPOLLHUP
Hang up happened on the associated file descriptor.  epoll_wait(2) will always wait for this event; it is not necessary to set it in events.

EPOLLET
Sets  the  Edge Triggered behavior for the associated file descriptor.  The default behavior for epoll is Level Triggered.  See epoll(7) for more detailed information about Edge and Level Triggered event distribution architectures.

int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);

调用过程:

1.调用poll_create,Linux会创建一个结构体,每一个epoll对象都会又个epoll_event结构体,来存放添加进来的事件,挂在红黑树下;

2.所有事件都会和设备驱动程序建立回调,相应驱动事件发生时,回调用相应的回调函数;

3.当epoll_ctl添加的fd和event发生时,就把发生的事件复制回用户空间。

优点:

  • 没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口);
  • 效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;即Epoll最大的优点就在于它只管你”活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll;

epoll 有 EPOLLLT 和 EPOLLET 两种触发模式,LT 是默认的模式(水平),ET 是 “高速” 模式(边沿)。

  • LT 模式下,只要这个 fd 还有数据可读,每次 epoll_wait 都会返回它的事件,提醒用户程序去操作;
  • ET 模式下,它只会提示一次,直到下次再有数据流入之前都不会再提示了,无论 fd 中是否还有数据可读。所以在 ET 模式下,read 一个 fd 的时候一定要把它的 buffer 读完,或者遇到 EAGIN 错误。

Original: https://www.cnblogs.com/Albert-lihai/p/16593436.html
Author: Albert_禄遥
Title: 个人学习-Linux-IO多路复用

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/644089/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • java多线程回顾3:线程安全

    1、线程安全问题 关于线程安全问题,有一个经典案例:银行取钱问题。 假设有一个账户,有两个线程从账户里取钱,如果余额大于取钱金额,则取钱成功,反之则失败。 下面来看下线程不安全的程…

    技术杂谈 2023年7月11日
    079
  • R语言—数据基础及练习

    ## 创建leadership数据框 manager ) date "10/24/08","10/28/08","10/1/08&…

    技术杂谈 2023年7月25日
    076
  • 基于多传感器融合的贵重物品定位管理物联网解决方案简析

    现实问题 朋友A要把他的贵重的一幅字画运送到远在千里之外的新家,虽然找了物流公司,他仍然不放心,万一被弄丢了或者损坏了咋办?能否帮我开发一个跟踪设备?可以实时记录货物的状态以及地址…

    技术杂谈 2023年5月31日
    0150
  • 安全方案的四个原则

    安全方案的四个原则 一、Secure by Default 原则(默认安全) 这是安全方案中的最基本的原则。该原则可以归纳为白名单、黑名单思想。 1.黑名单、白名单 白名单:除了名…

    技术杂谈 2023年6月21日
    084
  • io调度算法【转】

    转自:https://www.cnblogs.com/linhaostudy/p/15868785.html 正文 Linux 内核包含4个IO调度器,分别是 Noop IO sc…

    技术杂谈 2023年5月30日
    094
  • 建造者模式(创建型)

    建造者模式 介绍 建造者模式注重的是部件构建的过程,意在 通过一步一步地精确构造出一个复杂的对象。 可以将建造者模式理解为,假设我们有一个对象需要建立,这个对象是由多个组件(Com…

    技术杂谈 2023年6月21日
    095
  • 全面认识数据指标体系

    原创不易,求分享、求一键三连 Hi,各位亲爱的小伙伴,小钗公号遵循日复盘->周复盘->月复盘->季度复盘->年总结策略,所以某类型文章到后期才会成体系。 今…

    技术杂谈 2023年6月1日
    095
  • 8086汇编 杂项案例

    8086汇编 杂项案例 一、案例1 问题:完成下面的程序,利用栈,将程序中定义的数据逆序存放。 注:利用栈实现数据的逆至1)创建字存储数据2)将数据存放到通用寄存器3)将通用寄存器…

    技术杂谈 2023年6月1日
    097
  • iOS获取Wifi列表详解

    iOS 上获取 Wifi 列表其实也有很大限制,在 iOS 9 以前是不能获取Wifi列表的,只能获取当前连接的 Wifi 信息,也就表示只有连接了 Wifi 才能定位,刚才文章说…

    技术杂谈 2023年5月30日
    0140
  • 我是如何使用freemarker生成Word文件的?

    推荐:亲身体验,数次踩坑,遂撰写此文,以备各位不时之需。 背景 一天,产品经理递给我了一份word报告,我定睛一看这个文档有大大小小的标题层级,还有排版好的段落、各种一目了然的饼图…

    技术杂谈 2023年7月25日
    0112
  • openssh升级至7.2

    此处升级操作的原则是保留系统原有ssh服务,新安装高版本ssh服务 1、下载openssh源码包 http://www.openssh.com/portable.html 2、安装…

    技术杂谈 2023年7月11日
    087
  • Random在高并发下的缺陷以及JUC对其的优化

    Random可以说是每个开发都知道,而且都用的很6的类,如果你说,你没有用过Random,也不知道Random是什么鬼,那么你也不会来到这个技术类型的社区,也看不到我的博客了。但并…

    技术杂谈 2023年7月25日
    096
  • 如何使能TF-A的调试开关?

    答: 编译时指定DEBUG=1,示例如下:$ make .. DEBUG=1 .. (..表示其它参数) Original: https://www.cnblogs.com/dak…

    技术杂谈 2023年5月31日
    071
  • docker 安装mysql5.7

    拉取镜像 docker pull mysql:5.7 准备数据目录 mkdir -p /mall/docker/mysql/conf mkdir -p /mall/docker/m…

    技术杂谈 2023年7月24日
    088
  • scrapy实例:爬取天气、气温等

    1.创建项目 scrapy startproject weather # weather是项目名称 scrapy crawl _spidername_开始运行,程序自动使用star…

    技术杂谈 2023年5月31日
    090
  • 关于IoAttachDeviceToDeviceStack

    IoAttachDeviceToDeviceStack将Source Device附加到Target Device上。 打开windbgkd> u IoAttachDevic…

    技术杂谈 2023年5月31日
    091
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球