Linux:多路转接 select、poll、epoll

news2024/11/17 0:40:31

目录

1:select

1. 参数解释

2. 函数返回值

3. fd_set

4. fd_set 相关接口

5. timeval 

5. 常见使用

6. 理解 select 执行过程

 7. select 的特点

8. select 缺点

9. select 应用

2:socket 就绪条件

1. 读事件就绪(Readable)

 2. 写就绪(Writable)

3. 异常事件就绪(Exception)

 3:poll

1. events 和 revents

2. poll优点

3. poll缺点

4. poll 应用

4:epoll 

 1. epoll_wait

2. epoll 工作原理

 3. 接口总结

4. epoll 的优点

5. epoll 应用


1:select

#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

   select 函数是 POSIX 标准定义的一个系统调用,用于监视多个文件描述符(file descriptors),以确定它们是否具有可读、可写或异常条件。

1. 参数解释

        1: int nfds:这是监视的文件描述符集合中最大的文件描述符加一。也就是说,如果你监视的文件描述符最大是 fd_max,那么你应该将 nfds 设置为 fd_max + 1。

        2: fd_set *readfds这是一个指向 fd_set 结构的指针,该结构包含了你想要监视以检查是否有数据可读的文件描述符集合。如果 NULL,则表示不监视任何读文件描述符。

        3: fd_set *writefds这是一个指向 fd_set 结构的指针,包含了你想要监视以检查是否可写的文件描述符集合。如果 NULL,则表示不监视任何写文件描述符。

        4: fd_set *exceptfds这是一个指向 fd_set 结构的指针,包含了你想要监视以检查是否有异常条件的文件描述符集合。在大多数情况下,这用于检查 OOB(out-of-band,紧急)数据。如果 NULL,则表示不监视任何异常文件描述符。

        5: struct timeval *timeout:这是一个指向 timeval 结构的指针,它指定了 select 调用等待文件描述符状态改变的最大时间。

参数 timeout 取值:

        • NULL: 则表示 select() 没有 timeout, select 将一直被阻塞, 直到某个文件描述符上发生了事件;

        • 0: 仅检测描述符集合的状态, 然后立即返回, 并不等待外部事件的发生。

        特定的时间值: 如果在指定的时间段里没有事件发生, select 将超时返回。

2. 函数返回值

        1: 如果有文件描述符准备好了,select 返回准备好的文件描述符的数量。

        2: 如果返回 0 代表在描述词状态改变前已超过 timeout 时间, 没有返回。

        3: 当有错误发生时则返回-1, 错误原因存于 errno, 此时参数 readfds, writefds,exceptfds 和 timeout 的值变成不可预测。

错误值可能为:

        • EBADF 文件描述词为无效的或该文件已关闭。

        • EINTR 此调用被信号所中断。

        EINVAL 参数 n 为负值。

        ENOMEM 核心内存不足。

3. fd_set

        其实这个结构就是一个整数数组, 更严格的说, 是一个 "位图"。使用位图中对应的位来表示要监视的文件描述符。

4. 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 的全部位
5. timeval 

5. 常见使用
fd_set readset;
FD_SET(fd,&readset);
select(fd+1,&readset,NULL,NULL,NULL);
if(FD_ISSET(fd,readset)){……}
6. 理解 select 执行过程

        fd_set 长度为 1 字节, fd_set中的每一 bit 可以对应一个文件描述符 fd。 则 1 字节长的 fd_set 最大可以对应 8 个 fd。

        (1): FD_ZERO(&set); 初始化fd_set,所有位都为0,即0000,0000

        (2)FD_SET(5, &set); 将第5位设置为1,其他位保持不变,变为0001,0000

        (3):接着将fd=2fd=1加入集合,分别设置第2位和第1位为1,变为0001,0011

        (4):select(6, &set, 0, 0, 0); 调用select函数,监控fd_set中文件描述符的可读事件。参数6表示监控的文件描述符最大值为5(因为是从0开始计数的,所以6-1=5),select会阻塞直到有事件发生或超时。

        (5):如果fd=1fd=2上都发生了可读事件,select会返回,此时fd_set中只有第1位和第2位为1,变为0000,0011。注意,没有事件发生的fd=5对应的位被清空了,因为select函数的行为是只保留那些有事件发生的文件描述符。

 7. select 的特点

         1可监控的文件描述符个数取决于 sizeof(fd_set) 的值. 我这边服务器上sizeof(fd_set)= 512, 每 bit 表示一个文件描述符, 则服务器上支持的最大文件描述符是 512*8=4096

        2将 fd 加入 select 监控集的同时, 还要再使用一个数据结构 array (辅助数组)保存放到 select监控集中的 fd。
        是用于再 select 返回后, array 作为源数据和 fd_set 进行 FD_ISSET 判断。
        是 select 返回后会把以前加入的但并无事件发生的 fd 清空, 则每次开始select 前都要重新从 array 取得 fd 逐一加入(FD_ZERO 最先), 扫描 array 的同时取得 fd 最大值 maxfd, 用于 select 的第一个参数。

8. select 缺点

        1每次调用 select, 都需要手动设置 fd 集合, 从接口使用角度来说也非常不便。

        2每次调用 select, 都需要把 fd 集合从用户态拷贝到内核态, 这个开销在 fd 很多时会很大。

        3同时每次调用 select 都需要在内核遍历传递进来的所有 fd, 这个开销在 fd 很多时也很大。

        5select 支持的文件描述符数量太小。
 

9. select 应用


SelectServer · XiangChao/Linux - 码云 - 开源中国 (gitee.com)icon-default.png?t=O83Ahttps://gitee.com/RuofengMao/linux/tree/master/SelectServer

2:socket 就绪条件

1. 读事件就绪(Readable)

        • socket 内核中, 接收缓冲区中的字节数, 大于等于低水位标记 SO_RCVLOWAT。 此时可以无阻塞的读该文件描述符, 并且返回值大于 0;

        • socket TCP 通信中, 对端关闭连接, 此时对该 socket 读, 则返回 0

        • 监听的 socket 上有新的连接请求;

        • socket 上有未处理的错误;

 2. 写就绪(Writable)

        • socket 内核中, 发送缓冲区中的可用字节数(发送缓冲区的空闲位置大小), 大于等于低水位标记 SO_SNDLOWAT, 此时可以无阻塞的写, 并且返回值大于 0;

        • socket 的写操作被关闭(close 或者 shutdown). 对一个写操作被关闭的 socket 进行写操作, 会触发 SIGPIPE 信号;

        • socket 使用非阻塞 connect 连接成功或失败之后;

        • socket 上有未读取的错误;

3. 异常事件就绪(Exception)

        •异常事件就绪意味着socket上发生了一些非正常的事件,如连接断开、错误发生等。

        •这通常发生在连接被对方强制关闭,或者在socket上发生了一些错误,需要立即处理。

        •在select函数中,如果一个socket的异常事件就绪,那么在调用select后,该socket会在返回的异常文件描述符集合中被标记。

 3:poll

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

struct pollfd {
    int   fd;         /* 文件描述符 */
    short events;     /* 需要监控的事件 */
    short revents;    /* 已经发生的事件,由 `poll` 函数填充 */
};

参数说明:
    fd:需要监控的文件描述符。
    events:需要监控的事件类型,可以是以下宏的组合:
    POLLIN:有数据可读。
    POLLOUT:写入不会阻塞。
    POLLERR:发生错误。
    POLLHUP:对端关闭连接。
    revents:实际发生的事件,由 poll 函数在调用返回后填充。

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

1. events 和 revents

2. poll优点

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

        2. pollfd结构包含了要监视的event和发生的event,不再使用select“参数-值”传递的方式. 接口使用比select更方便。

        3. poll并没有最大数量限制 (但是数量过大后性能也是会下降)。

3. poll缺点

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

       2. 每次调用poll都需要把大量的pollfd结构从用户态拷贝到内核中。

       3. 同时连接的大量客户端在一时刻可能只有很少的处于就绪状态, 因此随着监视的描述符数量的增长, 其效率也会线性下降。

4. poll 应用

 Poll · XiangChao/Linux - 码云 - 开源中国 (gitee.com)icon-default.png?t=O83Ahttps://gitee.com/RuofengMao/linux/tree/master/Poll

4:epoll 

1:
    创建 epoll 实例:

    int epoll_create(int size);
 
    size 参数通常被忽略,但可以作为内核的提示,告知可能监控的文件描述符数量。

2:
    使用 epoll_ctl 注册事件:

    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    
    epfd:epoll 实例的文件描述符。
    op:操作类型,如 EPOLL_CTL_ADD(添加)、EPOLL_CTL_MOD(修改)、EPOLL_CTL_DEL(删除)。
    fd:要监控的文件描述符。
    event:指向 struct epoll_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 */
           };
events 可以是以下几个宏的集合:
    • EPOLLIN : 表示对应的文件描述符可以读 (包括对端 SOCKET 正常关闭);
    • EPOLLOUT : 表示对应的文件描述符可以写;
    • EPOLLPRI : 表示对应的文件描述符有紧急的数据可读 (这里应该表示有带外数据到来);
    • EPOLLERR : 表示对应的文件描述符发生错误;
    • EPOLLHUP : 表示对应的文件描述符被挂断;
    • EPOLLET : 将 EPOLL 设为边缘触发(Edge Triggered)模式, 这是相对于水平触发(Level Triggered)来说的.
    • EPOLLONESHOT: 只监听一次事件, 当监听完这次事件之后, 如果还需要继
续监听这个 socket 的话, 需要再次把这个 socket 加入到 EPOLL 队列里.

3:
    等待事件的发生:

    int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
    
    epfd:epoll 实例的文件描述符。
    events:用于存储发生的事件的数组。
    maxevents:数组的大小,即最多可以返回的事件数量。
    timeout:等待时间(毫秒),-1 表示无限期等待,0 表示立即返回。

4:
    处理事件:
    在 epoll_wait 返回后,遍历 events 数组,处理每个发生的事件。
 1. epoll_wait

        参数 events 是分配好的 epoll_event 结构体数组。

        • epoll 将会把发生的事件赋值到 events 数组中 (events 不可以是空指针, 内核只负责把数据复制到这个 events 数组中, 不会去帮助我们在用户态中分配内存)。

        • maxevents 告之内核这个 events 有多大, 这个 maxevents 的值不能大于创建epoll_create()时的 size。

        • 参数 timeout 是超时时间 (毫秒, 0 会立即返回, -1 是永久阻塞)。

        如果函数调用成功返回对应 I/O 上已准备好的文件描述符数目, 如返回 0 表示已超时, 返回小于 0 表示函数失败

2. epoll 工作原理

         每一个 epoll 对象都有一个独立的 eventpoll 结构体, 用于存放通过 epoll_ctl 方法向 epoll 对象中添加进来的事件。

        • 这些事件都会挂载在中, 如此, 重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是 lgn, 其中 n 为树的高度)。

        • 而所有添加到 epoll 中的事件都会与设备(网卡)驱动程序建立回调关系, 也就是说, 当响应的事件发生时会调用这个回调方法。

        • 这个回调方法在内核中叫 ep_poll_callback,它会将发生的事件添加到 rdlist 双链表中。

         在 epoll 中, 对于每一个事件, 都会建立一个 epitem 结构体。

        • 当调用 epoll_wait 检查是否有事件发生时, 只需要检查 eventpoll 对象中的rdlist 双链表中是否有 epitem 元素即可。

        • 如果 rdlist 不为空, 则把发生的事件复制到用户态, 同时将事件数量返回给用户. 这个操作的时间复杂度是 O(1)。

 3. 接口总结

         调用 epoll_create 创建一个 epoll 句柄;

        • 调用 epoll_ctl, 将要监控的文件描述符进行注册;

        • 调用 epoll_wait, 等待文件描述符就绪;

4. epoll 的优点

        • 接口使用方便: 虽然拆分成了三个函数, 但是反而使用起来更方便高效. 不需要每次循环都设置关注的文件描述符, 也做到了输入输出参数分离开。

        • 数据拷贝轻量: 只在合适的时候调用 EPOLL_CTL_ADD 将文件描述符结构拷贝到内核中, 这个操作并不频繁(而 select/poll 都是每次循环都要进行拷贝)。

        • 事件回调机制: 避免使用遍历, 而是使用回调函数的方式, 将就绪的文件描述符结构加入到就绪队列中, epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪. 这个操作时间复杂度O(1)。 即使文件描述符数目很多, 效率也不会受到影响。

        • 没有数量限制: 文件描述符数目无上限。

注意

        我们定义的 struct epoll_event 是我们在用户空间中分配好的内存. 势必还是需要将内核的数据拷贝到这个用户空间的内存中。

5. epoll 应用

Epoll · XiangChao/Linux - 码云 - 开源中国 (gitee.com)icon-default.png?t=O83Ahttps://gitee.com/RuofengMao/linux/tree/master/Epoll

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

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

相关文章

智能优化算法-海马优化算法(SHO)(附源码)

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1.内容介绍 海马优化算法 (Seahorse Optimization Algorithm, SHO) 是一种基于群体智能的元启发式优化算法&#xff0c;它模拟了海马的觅食行为、繁殖行为以及社会互动&#xff0c;用于解决复杂的优化问题。 SHO的工作机制…

精选干货!分享5款ai智能写论文软件

在当今信息爆炸的时代&#xff0c;AI智能写作工具已经成为我们写作过程中的得力助手。特别是对于学术论文的撰写&#xff0c;这些工具不仅能够提高写作效率&#xff0c;还能帮助用户生成高质量的文稿。以下是五款值得推荐的AI智能写论文软件&#xff0c;其中特别推荐千笔-AIPas…

Path系统环境变量和CLASSPATH环境变量

Path系统环境变量 概述&#xff1a;Path环境变量不是java的&#xff0c;它隶属于windows操作系统 作用&#xff1a; PATH环境变量实际上就是给windows操作系统指路的。 在Path环境变量中有很多路径&#xff0c;路径和路径之间采用 分号(;) 隔开在DOS命令窗口中输入一条DOS命…

Vscode中搭建ABAP开发环境

文章目录 前提&#xff08;在SAP系统中测试&#xff09;1.1 登录sap 系统1.2激活测服务测试1.3 添加服务 下载Vscode2.1 安装ABAP Remote filesystem 打开ABAP System3.1 按照CtrlshiftP 找到AbapFs Connect to an ABAP system 前提&#xff08;在SAP系统中测试&#xff09; 1…

2-89 基于matlab的图像去噪方法

基于matlab的图像去噪方法&#xff0c;对比了常见的几种去噪方法&#xff0c;含中值滤波&#xff0c;均值滤波&#xff0c;维纳滤波&#xff0c;高斯滤波&#xff0c;以及三种形态学滤波&#xff08;一般的&#xff0c;改进的&#xff0c;多结构元素形态学滤波&#xff09;&…

HarmonyOS开发之Tab样式(背景高亮样式)

一&#xff1a;开发环境 二&#xff1a;效果图 三&#xff1a;实现步骤 Entry Component struct TabsPage {State tabArray:string[] ["首页","分类","应用","热点","我的"]State focusIndex: number 0;State index: num…

嵌入式学习(哈希表)

哈希表中元素是由哈希函数确定的&#xff0c;将数据元素的关键字key作为自变量&#xff0c;通过一定的函数关系&#xff08;称为哈希函数&#xff09;&#xff0c;计算出的值&#xff0c;即为该元素的存储地址。 哈希函数&#xff1a;指将哈希表中元素的关键键值映射为元素存储…

局域网远程桌面工具:NoMachine 介绍、安装与使用

局域网远程桌面工具&#xff1a;NoMachine 介绍、安装与使用 NoMachine 简介Linux 安装Windows安装使用 NoMachine 简介 NoMachine是一款很常见的远程桌面工具&#xff0c;尤其在EDA领域&#xff0c;常常被用作远程接入方案。NoMachine可以用于个人远程连接&#xff0c;类似于…

4.第二阶段x86游戏实战2-CE加强修改移动速度(浮点数存放方式与转换)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

2.3.2 协程调度器实现与性能测试

LINUX 精通 8 day24 20240909 晚19&#xff1a;35 - 20: 47 课程链接地址 老师画图用的是excalidraw 可以在线 本地&#xff01; Excalidraw&#xff1a;开源实用的白板画图工具&#xff08;在线/本地安装&#xff09;-CSDN博客 2.3.2 协程调度器实现与性能测试 复习了上…

HTML/CSS/JS学习笔记 Day3(HTML--网页标签 下)

跟着该视频学习&#xff0c;记录笔记&#xff1a;【黑马程序员pink老师前端入门教程&#xff0c;零基础必看的h5(html5)css3移动端前端视频教程】https://www.bilibili.com/video/BV14J4114768?p12&vd_source04ee94ad3f2168d7d5252c857a2bf358 Day3 内容梳理&#xff1a;…

使用ChatGPT生成爆款小红书文案,有手就行!

小红书&#xff0c;作为当下热门的社交电商平台&#xff0c;以其独特的社区氛围、精准的用户画像和高粘性的互动模式&#xff0c;吸引了大量年轻用户&#xff0c;尤其是女性用户。平台上的内容风格多样&#xff0c;涵盖了美妆、时尚、生活方式等多个领域。 本文将介绍小红书平台…

为何家用无线路由器不能实现PROFINET通信?

家用无线路由器和工业通信设备到底有什么不同&#xff1f;工控人加入PLC工业自动化精英社群 首先&#xff0c;在技术上&#xff0c;两者存在明显的差异。 家用无线路由器主要是为了提供互联网接入和家庭设备间的连接&#xff0c;而PROFINET则是专为工业自动化设计的通信协议。就…

1分钟教你用AI制作美女热舞视频,收益可观,操作简单(附工具及教程资料)

美女跳舞&#xff0c;听着是不是就觉得会很哇塞&#xff1f; 不管是男的女的、老的少的都喜欢看&#xff0c;而且一般美女跳舞的账号涨粉都很快&#xff0c;势头都贼猛。 今天就给大家分享一个很热门的小副业——AI美女跳舞。 更多实操和AI绘画工具&#xff0c;可以扫描下方&…

通过SSH服务远程操作Linux(ubuntu)主机

首先SSH是什么&#xff1f;SSH&#xff08;Secure SHell&#xff09;是Linux、Unix、Mac及其他网络设备最常用的远程CLI管理协议&#xff0c;SSH使用秘钥对数据进行加密&#xff0c;保证了远程管理数据的安全性。Secure Shell (SSH) 是一种网络协议&#xff0c;允许用户通过加密…

OpenCV-轮廓特征

文章目录 一、简介1.意义2.类别 二、代码实现1.数据预处理2.计算周长3.绘制外接圆轮廓4.绘制外接矩阵 三、总结 一、简介 1.意义 在OpenCV中&#xff0c;轮廓检测后得到的轮廓不仅是一系列点的集合&#xff0c;还可以进一步分析以提取有用的特征。这些特征包括但不限于轮廓的…

纷享销客CRM+契约锁:“好应用+电子签” 融合领先实践

9月6日&#xff0c;主题为“智享未来 领创CRM新纪元”的2024纷享销客伙伴大会湖北站圆满结束&#xff0c;此次盛会吸引了来自不同行业的精英代表、技术专家&#xff0c;共同探讨CRM领域的最新趋势、创新实践与未来机遇。纷享销客战略伙伴契约锁受邀参加本次大会&#xff0c;为现…

一区霜冰算法+双向深度学习模型+注意力机制!RIME-BiTCN-BiGRU-Attention

一区霜冰算法双向深度学习模型注意力机制&#xff01;RIME-BiTCN-BiGRU-Attention 目录 一区霜冰算法双向深度学习模型注意力机制&#xff01;RIME-BiTCN-BiGRU-Attention效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现RIME-BiTCN-BiGRU-Attention霜冰算法…

NLP-新词挖掘

一、背景 网络领域的新词发现&#xff08;挖掘&#xff09;是一个非常重要的nlp课题。在处理文本对象时&#xff0c;非常关键的问题在于“切词”这个环节&#xff0c;几乎所有的后续结果都依赖第一步的切词。因此切词的准确性在很大程度上影响着后续的处理&#xff0c;切词结果…

树莓派通过串口驱动SU-03T语音模块

树莓派通过串口驱动SU-03T语音模块 文章目录 树莓派通过串口驱动SU-03T语音模块一、SU-03T语音模块的配置和烧录1.1 PIN引脚配置&#xff1a;1.2 设置唤醒词&#xff1a;1.3 设置控制详情&#xff1a;1.4 下载SDK并烧录到语音模块&#xff1a; 二、测试语音模块三、树莓派通过串…