IO多路转接

1.select

初识select

系统提供 select 函数来实现多路复用输入 / 输出模型 .
select 系统调用是用来让我们的程序监视多个文件描述符的状态变化的 ;
程序会停在 select 这里等待,直到被监视的文件描述符有一个或多个发生了状态改变 ;

select函数模型

select的函数原型如下: #include <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

参数解释

参数 nfds 是需要监视的最大的文件描述符值 +1
rdset,wrset,exset 分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合;
参数 timeout 为结构 timeval ,用来设置 select() 的等待时间

参数timeout取值

NULL :则表示 select ()没有 timeout select 将一直被阻塞,直到某个文件描述符上发生了事件 ;
0 :仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。
特定的时间值:如果在指定的时间段里没有事件发生, select 将超时返回。

关于fd_set结构

其实这个结构就是一个整数数组 , 更严格的说 , 是一个 " 位图 ". 使用位图中对应的位来表示要监视的文件描述符 .
提供了一组操作 fd_set 的接口 , 来比较方便的操作位图 .

void FD_CLR(int fd, fd_set *set); // 用来清除描述词组 set 中相关 fd 的位
int FD_ISSET(int fd, fd_set *set); // 用来测试描述词组 set 中相关 fd 的位是否为真
void FD_SET(int fd, fd_set *set); // 用来设置描述词组 set 中相关 fd 的位
void FD_ZERO(fd_set *set); // 用来清除描述词组 set 的全部位

timeval结构

timeval 结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。

函数返回值

执行成功则返回文件描述词状态已改变的个数
如果返回 0 代表在描述词状态改变前已超过 timeout 时间,没有返回
当有错误发生时则返回 -1 ,错误原因存于 errno ,此时参数 readfds writefds, exceptfds timeout 的值变成不可预测。
错误值可能为:
EBADF 文件描述词为无效的或该文件已关闭
EINTR 此调用被信号所中断
EINVAL 参数 n 为负值。
ENOMEM 核心内存不足

select执行流程

理解 select 模型的关键在于理解 fd_set, 为说明方便,取 fd_set 长度为 1 字节, fd_set 中的每一 bit 可以对应一个文件描述符fd 。则 1 字节长的 fd_set 最大可以对应 8 fd
* 1 )执行 fd_set set; FD_ZERO(&set); set 用位表示是 0000,0000 * 2 )若 fd 5, 执行 FD_SET(fd,&set); 后set 变为 0001,0000( 5 位置为 1) * 3 )若再加入 fd 2 fd=1, set 变为 0001,0011 * 4 )执行select(6,&set,0,0,0)阻塞等待 * 5 )若 fd=1,fd=2 上都发生可读事件,则 select 返回,此时 set 变为0000,0011。注意:没有事件发生的 fd=5 被清空

select就绪条件

读就绪

socket 内核中 , 接收缓冲区中的字节数 , 大于等于低水位标记 SO_RCVLOWAT. 此时可以无阻塞的读该文件描述符, 并且返回值大于 0;
socket TCP 通信中 , 对端关闭连接 , 此时对该 socket , 则返回 0;
监听的 socket 上有新的连接请求 ;
socket 上有未处理的错误 ;

写就绪

socket 内核中 , 发送缓冲区中的可用字节数 ( 发送缓冲区的空闲位置大小 ), 大于等于低水位标记SO_SNDLOWAT, 此时可以无阻塞的写 , 并且返回值大于 0;
socket 的写操作被关闭 (close 或者 shutdown). 对一个写操作被关闭的 socket 进行写操作 , 会触发 SIGPIPE信号;
socket 使用非阻塞 connect 连接成功或失败之后 ;
socket 上有未读取的错误 ;

异常就绪

socket 上收到带外数据 . 关于带外数据 , TCP 紧急模式相关 ( 回忆 TCP 协议头中 , 有一个紧急指针的字段 )

select的特点

可监控的文件描述符个数取决与 sizeof(fd_set) 的值 . 我这边服务器上 sizeof(fd_set) 512 ,每 bit 表示一个文件描述符,则我服务器上支持的最大文件描述符是512*8=4096.
fd 加入 select 监控集的同时,还要再使用一个数据结构 array 保存放到 select 监控集中的 fd
一是用于再 select 返回后, array 作为源数据和 fd_set 进行 FD_ISSET 判断。
二是 select 返回后会把以前加入的但并无事件发生的 fd 清空,则每次开始 select 前都要重新从 array 取得fd逐一加入 (FD_ZERO 最先 ) ,扫描 array 的同时取得 fd 最大值 maxfd ,用于 select 的第一个参数。

select的优点

1.可移植性好:select几乎在所有的平台上都支持,具有良好的跨平台兼容性。

2.超时精度高:select对于超时值的精度可以达到微秒级别,比poll的毫秒级别精度更高。

select的缺点

1.每次调用 select, 都需要手动设置 fd 集合 , 从接口使用角度来说也非常不便 .
2.每次调用 select ,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大
3.同时每次调用 select 都需要在内核遍历传递进来的所有 fd ,这个开销在 fd 很多时也很大
4.select 支持的文件描述符数量太小
5.代码编写难度大

 select的一般编码格式

1.需要有一个第三方数组,用来保存所以合法的fd

2.while(true)

{

        1.遍历数组,更新出最大值

        2.遍历数组,添加所有需要关心的fd到fd_set位图中

        3.调用select进行事件检测

        4.遍历数组,找到就绪的事件,根据就绪事件,完成对应的动作

}

2.poll

poll函数接口

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
// pollfd 结构
struct pollfd {
        int fd; /* file descriptor */
        short events; /* requested events */
        short revents; /* returned events */
};

参数说明

fds 是一个 poll 函数监听的结构列表 . 每一个元素中 , 包含了三部分内容 : 文件描述符 , 监听的事件集合 , 返回的事件集合.
nfds 表示 fds 数组的长度 .
timeout 表示 poll 函数的超时时间 , 单位是毫秒 (ms) 

events和revents的取值

返回结果

返回值小于 0, 表示出错 ;
返回值等于 0, 表示 poll 函数等待超时 ;
返回值大于 0, 表示 poll 由于监听的文件描述符就绪而返回 .

poll的优点

1.效率高
2.输入输出参数分离,不需要进行大量的重置
3.poll参数级别,没有可以管理的fd上限

poll的缺点

1.poll依旧需要不少的遍历,在用户层检测事件就绪与内核检测fd就绪,都是一样的,用户还需要维护数组

2.poll需要内核到用户的拷贝

3.poll的代码也比较复杂 

3.epoll

按照man手册的说法: 是为处理大批量句柄而作了改进的poll.

epoll 3 个相关的系统调用 .
1.epoll_create

 int epoll_create(int size);

2.epoll_ctl

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

它不同于 select() 是在监听事件时告诉内核要监听什么类型的事件 , 而是在这里先注册要监听的事件类型 .
第一个参数是 epoll_create() 的返回值 (epoll 的句柄 ).
第二个参数表示动作,用三个宏来表示 .
第三个参数是需要监听的 fd.
第四个参数是告诉内核需要监听什么事

第二个参数的取值

EPOLL_CTL_ADD :注册新的 fd epfd 中;
EPOLL_CTL_MOD :修改已经注册的 fd 的监听事件;
EPOLL_CTL_DEL :从 epfd 中删除一个 fd

struct epoll_event结构如下:

events 可以是以下几个宏的集合:
EPOLLIN : 表示对应的文件描述符可以读 ( 包括对端 SOCKET 正常关闭 );
EPOLLOUT : 表示对应的文件描述符可以写 ;
EPOLLPRI : 表示对应的文件描述符有紧急的数据可读 ( 这里应该表示有带外数据到来 );
EPOLLERR : 表示对应的文件描述符发生错误 ;
EPOLLHUP : 表示对应的文件描述符被挂断 ;
EPOLLET : EPOLL 设为边缘触发 (Edge Triggered) 模式 , 这是相对于水平触发 (Level Triggered) 来说的 .
EPOLLONESHOT :只监听一次事件 , 当监听完这次事件之后 , 如果还需要继续监听这个 socket 的话 , 需要再次把这个socket 加入到 EPOLL 队列里 .

3.epoll_wait

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

收集在 epoll 监控的事件中已经发送的事件 .
参数 events 是分配好的 epoll_event 结构体数组 .
epoll 将会把发生的事件赋值到 events 数组中 (events 不可以是空指针,内核只负责把数据复制到这个events数组中,不会去帮助我们在用户态中分配内存 ).
maxevents 告之内核这个 events 有多大,这个 maxevents 的值不能大于创建 epoll_create() 时的 size.
参数 timeout 是超时时间 ( 毫秒, 0 会立即返回, -1 是永久阻塞 ).
如果函数调用成功,返回对应 I/O 上已准备好的文件描述符数目,如返回 0 表示已超时 , 返回小于 0 表示函数失败.

epoll的工作原理 

首先,epoll区别于select和poll的点在于,就绪是通过下层主动来的。

 

epoll模型: 

当某一进程调用 epoll_create 方法时, Linux 内核会创建一个 eventpoll 结构体,这个结构体中有两个成员与epoll 的使用方式密切相关。
每一个 epoll 对象都有一个独立的 eventpoll 结构体,用于存放通过 epoll_ctl 方法向 epoll 对象中添加进来的事件.
这些事件都会挂载在红黑树中,如此,重复添加的事件就可以通过红黑树而高效的识别出来 ( 红黑树的插入时间效率是lgn ,其中 n 为树的高度 ).
而所有添加到 epoll 中的事件都会与设备 ( 网卡 ) 驱动程序建立回调关系,也就是说,当响应的事件发生时会调用这个回调方法.
这个回调方法在内核中叫 ep_poll_callback, 它会将发生的事件添加到 rdlist 双链表中 .
epoll 中,对于每一个事件,都会建立一个 epitem 结构体 .
struct eventpoll{
....
/* 红黑树的根节点,这颗树中存储着所有添加到 epoll 中的需要监控的事件 */
struct rb_root rbr;
/* 双链表中则存放着将要通过 epoll_wait 返回给用户的满足条件的事件 */
struct list_head rdlist;
....
};

struct epitem{
struct rb_node rbn;// 红黑树节点
struct list_head rdllink;// 双向链表节点
struct epoll_filefd ffd; // 事件句柄信息
struct eventpoll *ep; // 指向其所属的 eventpoll 对象
struct epoll_event event; // 期待发生的事件类型
}
当调用 epoll_wait 检查是否有事件发生时,只需要检查 eventpoll 对象中的 rdlist 双链表中是否有 epitem元素即可.
如果 rdlist 不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户 . 这个操作的时间复杂度
O(1).

epoll的优点

1.接口使用方便 : 虽然拆分成了三个函数 , 但是反而使用起来更方便高效 . 不需要每次循环都设置关注的文件描述符, 也做到了输入输出参数分离开
2.数据拷贝轻量 : 只在合适的时候调用 EPOLL_CTL_ADD 将文件描述符结构拷贝到内核中 , 这个操作并不频繁( select/poll 都是每次循环都要进行拷贝 )
3.事件回调机制 : 避免使用遍历 , 而是使用回调函数的方式 , 将就绪的文件描述符结构加入到就绪队列中 ,epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪 . 这个操作时间复杂度 O(1). 即使文件描述符数目很多, 效率也不会受到影响 .
4.没有数量限制 : 文件描述符数目无上限

epoll工作方式

epoll2种工作方式-水平触发(LT)和边缘触发(ET).

水平触发 Level Triggered 工作模式
epoll 默认状态下就是 LT 工作模式 .
epoll 检测到 socket 上事件就绪的时候 , 可以不立刻进行处理 . 或者只处理一部分 .
如上面的例子 , 由于只读了 1K 数据 , 缓冲区中还剩 1K 数据 , 在第二次调用 epoll_wait , epoll_wait 仍然会立刻返回并通知socket 读事件就绪 .
直到缓冲区上所有的数据都被处理完 , epoll_wait 才不会立刻返回 .
支持阻塞读写和非阻塞读写
边缘触发 Edge Triggered 工作模式
如果我们在第 1 步将 socket 添加到 epoll 描述符的时候使用了 EPOLLET 标志 , epoll 进入 ET 工作模式 .
epoll 检测到 socket 上事件就绪时 , 必须立刻处理 .
如上面的例子 , 虽然只读了 1K 的数据 , 缓冲区还剩 1K 的数据 , 在第二次调用 epoll_wait 的时候 ,
epoll_wait 不会再返回了 .
也就是说 , ET 模式下 , 文件描述符上的事件就绪后 , 只有一次处理机会 .
ET 的性能比 LT 性能更高 ( epoll_wait 返回的次数少了很多 ). Nginx 默认采用 ET 模式使用 epoll.
只支持非阻塞的读写

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/715066.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器硬件得基础知识介绍

服务器硬件是计算机硬件的一种&#xff0c;专门用于构建服务器系统。服务器硬件通常具有高性能、高可靠性和可扩展性等特点&#xff0c;以满足企业级应用的需求。本文将从以下几个方面介绍服务器硬件的基础知识&#xff1a;服务器概述、CPU、内存、存储、网络、电源和散热、服务…

【机器学习】CIFAR-10数据集简介、下载方法(自动)

【机器学习】CIFAR-10数据集简介、下载方法(自动) &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望得到您的订阅和支…

0904多元复合函数求导-多元函数微分法及其应用

文章目录 1 复习一元函数复合函数求导2 一元函数与多元函数复合的情形3 多元函数与多元函数复合的情形4 其他情形5 抽象复合函数求导6 全微分不变性结语 1 复习一元函数复合函数求导 y f ( u ) , u ϕ ( x ) ⇒ f [ ϕ ( x ) ] d y d x d y d u ⋅ d u d x f ′ ( u ) ⋅ ϕ…

Python正则表达式:从基础到高级应用的全面总结与实战【第103篇—JSON模块】

Python正则表达式&#xff1a;从基础到高级应用的全面总结与实战 正则表达式是一种强大的文本匹配和处理工具&#xff0c;广泛应用于文本处理、数据抽取、表单验证等领域。本文将从正则表达式的基础知识出发&#xff0c;逐步深入&#xff0c;最终结合代码实战&#xff0c;带你…

赵文彬将出席无磷锅炉工艺助剂在锅炉水节水节能应用

演讲嘉宾&#xff1a;赵文彬 集团副总/技术总监 上远未来水务集团有限公司 演讲题目&#xff1a;无磷锅炉工艺助剂在锅炉水节水节能方面的应用 会议简介 “十四五”规划中提出&#xff0c;提高工业、能源领城智能化与信息化融合&#xff0c;明确“低碳经济”新的战略目标&a…

mac 安装hbuilderx

下载 HBuilderX下载地址: 下载地址 选额mac版本点击下载 安装 如图&#xff0c;将HBuilderX拖到Applications&#xff0c;才是正确的安装姿势。 MacOSX&#xff0c;软件必须安装到/Applications目录&#xff0c;如未安装到此目录&#xff0c;可能会出现插件安装失败、项目创建…

Linux中的动静态库

目录 一、静态库 &#xff08;1&#xff09;静态库的优缺点&#xff1a; &#xff08;2&#xff09;Linux下静态库的创建和执行 1.直接编译​编辑 2.指定路径和库名 3.用LIBRARY_PATH环境变量来配置路径 二、动态库 &#xff08;1&#xff09;动态库的优缺点 &#xff…

javaweb请求与响应

前言 前面介绍了对应的服务器端的相关代码。这里开始学习服务器端与客户端的数据请求与响应 这里的仅仅是一个简单的调用&#xff0c;并没有经过servelert接口来进行调用&#xff0c;同前面的一样&#xff0c;我们介绍对应的本地服务器进行的部署项目。 代码 //属于简单的不…

Scratch 第十三课-飞机大战游戏

第十三课-飞机大战游戏 学习目标 这节课我们做一款大家都爱玩的飞机大战游戏&#xff0c;学习重点&#xff1a; 如何导入外部角色如何让飞机发射子弹鼠标控制角色移动 程序设计 程序分析 &#xff1a; 飞机大战游戏相信很多小朋友都玩过&#xff0c;我方飞机在下方&#xf…

LabVIEW石油钻机提升系统数字孪生技术

LabVIEW石油钻机提升系统数字孪生技术 随着数字化、信息化、智能化的发展&#xff0c;石油钻采过程中的石油钻机数字化技术提升成为了提高钻井效率、降低生产成本的重要途径。基于中石油云平台提供的数据&#xff0c;采用数字孪生技术&#xff0c;对石油钻机提升系统进行数字化…

[Redis]——初识Redis

一、Redis为非关系型数据库 ❓我们常见的MySQL、SQLServer都是关系型数据库&#xff0c;那他们之间有什么区别与联系呢&#xff1f; &#x1f4d5;关系型数据库与非关系型数据库的区别&#xff08;面试题&#xff09; 解释&#xff1a; SQL数据库中的表是有结构的&#xff0c;包…

腾讯云学生云服务器_学生云主机_学生云数据库_云+校园特惠套餐

2024年腾讯云学生服务器优惠活动「云校园」&#xff0c;学生服务器优惠价格&#xff1a;轻量应用服务器2核2G学生价30元3个月、58元6个月、112元一年&#xff0c;轻量应用服务器4核8G配置191.1元3个月、352.8元6个月、646.8元一年&#xff0c;CVM云服务器2核4G配置842.4元一年&…

小程序和页面生命周期详解

目录 小程序的生命周期 创建&#xff08;onLoad&#xff09;&#xff1a; 显示&#xff08;onShow&#xff09;&#xff1a; 隐藏&#xff08;onHide&#xff09;&#xff1a; 卸载&#xff08;onUnload&#xff09;&#xff1a; 错误监听&#xff08;onError&#xff09;…

JVM 第二部分-2(堆,方法区)

4.堆 堆 一个Java程序&#xff08;main方法&#xff09;对应一个jvm实例&#xff0c;一个jvm实例只有一个堆空间堆是jvm启动的时候就被创建&#xff0c;大小也确定了。大小可以用参数设置。堆是jvm管理的一块最大的内存空间 核心区域&#xff0c;是垃圾回收的重点区域堆可以位…

洛谷P1509找啊找啊找GF

题解&#xff1a;这题我们需要考虑两个因素 &#xff0c;既要有钱&#xff0c;也需要有人品&#xff0c;但是呢&#xff0c;还想花最少得时间泡到最多的女生&#xff0c;那么这题我们就要用到以往的二维dp数组&#xff0c;但是真的是二维的吗&#xff1f;不&#xff0c;因为要考…

如何让大项目自动化测试更加灵活简洁

如何把大象放到冰箱里&#xff1f;第一打开冰箱门&#xff0c;第二把大象放进去&#xff0c;第三把冰箱门关好。 这个问题言外之意是大象那么大&#xff0c;怎么能放进冰箱&#xff0c;为什么要把大象放冰箱&#xff0c;就开始纠结这个问题了&#xff0c;它是想表明不用太多纠结…

Day20-磁盘管理

Day20-磁盘管理 1. cut 切:2. 磁盘历史和内外部物理结构介绍2.1 磁盘发展趋势和实现措施2.2 磁盘知识的体系结构2.3 机械磁盘的外部结构2.4 SSD固态硬盘的外部结构2.5 固态硬盘内部结构2.6 缓存在服务器各硬件上的速度和大小对比另类维度图解&#xff0c;从上到下由高速到低速&…

DataX及Datax-web杂记

&#x1f47d;个人博客&#xff1a;https://everspring.github.io/ &#x1f47d;公众号&#xff1a;爱历史的IT男 一. DataX调试 DataX之前调试不是很方便&#xff0c;要打包后才能调试。23年7月后一位叫"FuYouJ "的开源者提交了datax-example模块&#xff0c;就方…

EasyRecovery2024国产免费的手机数据恢复软件

一、功能介绍 EasyRecovery手机数据恢复软件是一款功能全面的数据恢复工具&#xff0c;专为移动设备设计。其主要功能包括&#xff1a; 文件恢复&#xff1a;能够恢复手机中因各种原因丢失的文件&#xff0c;如照片、视频、音频、文档等。深度扫描&#xff1a;通过深度扫描手…

【数据结构】实现栈

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解栈&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 一 .栈的概念及结构二 .栈的实现栈的结构体初始化销毁栈顶插入栈顶删除显示栈顶元素是否为空栈的大…