linux---select,poll,epoll的原理以及优缺点

2023-05-16

多路转接IO(也叫IO多路复用)是一种处理高并发的IO事件监控,同时对大量的描述符进行时间监控,监控是否具备IO条件。
就绪:包括了读就绪事件(就是有数据到来的时候),写就绪事件(缓冲区有空闲的空间),异常事件(发生异常)。对于服务器来说,很多时候我们都是监控的读事件,对于写事件和异常事件都只会在特定的情况下使用。

  1. select
    select模型:通过对几个事件集合中的描述符进行事件监控,当集合中有就绪事件的时候就返回。
    select其实是在内核中开辟一块数组空间用来存储用户空间传递的文件描述符进行监控,监控这件事也是内核做的,我们只需要传递文件描述符,在用户空间进行检测,当有了就绪事件就拷贝到用户空间进行处理。
	   #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>
       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

nfds:监控的描述符中最大描述符+1。
fd_set:描述符集合(实际上是一个位图),位图的大小取决于FD_SETSIZE=1024.所以我们最多监控的文件描述符最大只能是1024。
readfd,writefds,exceptfds:分别是读就绪事件,写就绪事件,异常就绪事件的集合。

FD_ZERO(fd_set *fdset):清空fdset与所有文件句柄的联系。 
FD_SET(int fd, fd_set *fdset):建立文件句柄fd与fdset的联系。 
FD_CLR(int fd, fd_set *fdset):清除文件句柄fd与fdset的联系。 
FD_ISSET(int fd, fdset *fdset):检查fdset联系的文件句柄fd是否可读写,>0表示可读写。

返回之前会将集合中没有就绪的描述符清理掉。
timeout:等待超时事件
返回值:>0,返回就绪事件的个数。=0:监控事件超时。<0监控出错

流程
1)定义一个描述符集合:fd_set(位图,最大值为1024)
2)将集合拷贝到内核中进行监控,监控的原理就是对所有描述符轮询编译状态
3)当有描述符就绪的时候,在返回前,将没有就绪的描述符剔除掉
4)用户操作,对所有描述符进行遍历,看哪一个还在集合中,那么这个就和就是已经就绪的
5)重新fd_set拷贝到内核中进行监控
注意:监控的fd_set,但是我们不能让他传递到内核中去,不然传递回来的时候已经改变,所以我们需要定义一个中间变量拷贝到内核中,当传递回来的时候中间变量中就是已经准备好的文件描述符,然而我们监控的文件描述符就可以继续定义变量监控。

select优缺点

  • 优点:遵循POSIX标准,可以跨平台,监控的超市可以精确到微秒
  • 缺点:
    1)所有监控的文件描述符是由上线的,默认是1024,取决于FD_SETSIZE的大小
    2)select实现的监控原理是在内核中轮询遍历状态,因此会随着描述符增多性能下降
    3)select每次监控的时候都会修改监控集合中的值,都需要重新向内核拷贝监控描述符集合
    4)select要监控的集合中的描述符每次都要向内核拷贝数据。
  1. poll
    poll实际上和select类似,都是在内核中开辟一个空间,但是和select不是监控每种事件,poll监控的是事件结构化的事件集合。
struct pollfd{
	int fd;
	short events;//监控的事件
	short revents;//就绪的事件
}

常用的事件就是POLLIN和POLLOUT

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

原理:
1)用户定义事件数组,对描述符添加关心事件
2)poll实现监控也是将数据拷贝到内核中,然后进行轮询遍历监控,性能随着文件描述符增多而下降
3)用户根据返回的revents判断哪一个事件就绪然后重新操作
4)poll也不会告诉用户哪一个描述符就绪,只是告诉用户有就绪事件,需要用户遍历查找。

poll优缺点:

  • 优点
    1)采用事件结构的方式对描述符进行监控,简化了多个事件集合的监控方式
    2)没有描述符的具体上限
  • 缺点
    1)不能跨平台
    2)随着描述符增多性能下降

poll已经被淘汰了,因为他的功能可以使用其他模型替代,而且性能高,比如我们下面讲的epoll。select比poll的优点就是poll不能跨平台。但是比起epoll来说poll一无是处。

  1. epoll模型

epoll模型linux下性能最高的IO多路转接
在epoll下就绪事件变得不同。对于可读事件就绪就是接受缓冲区的数据大小大于低水位标记(一般为一字节)。对于可写事件就绪就是可写缓冲区的空闲空间大小大于低水位标记(1B)。
epoll在内核中是一红黑树进行节点的删除和添加,还有一个rdlist双向链表,用来存储就绪事件的链表。
epoll也是采用事件结构来进行监控的。

  • 创建一个epoll结点
       #include <sys/epoll.h>
       int epoll_create(int size);

功能:在内核中创建一个结构体,eventpoll{};在结构体中我们只关心两个参数,一个是红黑树,一个就是双向链表rdlist.
size:能监控的描述符上限,但是在linux2.6.8版本之后就被忽略了,但是参数必须大于0。
返回值:返回一个描述符,epoll的操作句柄。

  • 向epoll树上添加结点,删除结点,修改结点
       #include <sys/epoll.h>
       int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

功能:在内核的eventpoll结构中添加移除,修改所监控的事件结构。
epfd:epoll_create返回的eventpoll结构体的操作句柄
op:用户要进行的操作

EPOLL_CTL_ADD:向内核中eventpoll添加要监控的事件结构
EPOLL_CTL_DEL:向内核中eventpoll删除要监控的事件结构
EPOLL_CTL_MOD:向内核中eventpoll修改要监控的事件结构
  • 开始监控
       #include <sys/epoll.h>
       int epoll_wait(int epfd, struct epoll_event *events,
                      int maxevents, int timeout);

功能:开始监控eventpoll中的红黑树上保存的时间结构节点,如果有就绪事件就拷贝到当前的双向链表rdlist中。
epfd:eventpoll操作句柄
events:就绪事件的结构体集合
maxevents:用于确定最后一次最多获取的就绪事件个数
timeout:超时时间,只能到ms。

步骤:
1)第一步告诉内核要开始对文件描述符进行监控了
2)操作系统对描述符进行监控,采用的是事件触发方式进行监控。为每一个要监控的描述符都定义了一个事件,并且对这个事件都有回调函数(ep_poll_callback())。
3)这个事件回调函数要做的就是将就绪的这个描述符所对应的epoll_event事件结构添加到双向链表中(将事件结构地址添加到双向链表中)
4)epoll_wait并没有立即返回,是每隔一会儿来看看双向链表中是否为空,进而判断是否有描述符就绪。
5)若链表不为空的话就表示有文件描述符就绪,则epoll_wait直接返回。在返回之前,将就绪的描述符对应事件结构向用户太拷贝一份,
6)epoll会将就绪描述符对应的事件拷贝到用户态,直接告诉用户有那些描述符就绪,进而用户可以直接操作就绪的描述符。

epoll的优缺点

  • 优点
    1)epoll没有监控的上线
    2)采用事件结构简化了select监控集合的监控流程
    3)epoll是一个异步阻塞操作,发起调用,让操作系统进行文件描述符的监控,使用事件回调函数对描述符进行监控,避免了select的遍历轮询,性能不会随着文件描述符增多而下降
    4)epoll发起调用进行等待,循环判断内核中epoll就绪时间链表是不是为空来确定是否有就绪事件,若有就绪事件,则将对应的事件拷贝到用户态,直接告诉了用户那些描述符就绪了,不需要循环判断。
    5)epoll描述符的事件结构,只需要向内核中拷贝一次,不需要每次都拷贝

  • 缺点
    1)不能跨平台
    2)延时时间只能精确到毫秒

epoll的两种触发方式

  • 水平触发:只要缓冲区中的数据大小大于低水位标记的话,就会触发可读或者可写事件。
  • 边缘触发方式
    1)对于可读事件,只要每次有新的时间按到来的时候才会触发一次可读事件,
    2)对于可写事件:每次只要缓冲区空闲空间从0大于低水位标记的时候才会触发可是事件。

通常来说,读写事件混合监控的时候,对于可写事件就会使用边缘触发方式(防止可写事件每次不写入数据但是有空闲的时候都会触发事件)。
若是可读事件被设置为边缘触发,需要用户一次性将数据读取完毕,但是因为不知道数据有多少,因此只能循环从缓冲区中读取数据,当循环读取但是缓冲区中没有数据的时候recv就会阻塞。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux---select,poll,epoll的原理以及优缺点 的相关文章

随机推荐

  • python 深度学习-数学基础-2-导数

    z z的变化值比上距离的极限
  • python 深度学习-数学基础-3-微积分

  • rt-thread CAN通信(can dev write data failed!)解决,硬件定时器、以及CANfestival包的使用

    本文采用正点原子STM32f407ZGT6探索者 关于rtt的CAN通信配置可以参考RT Thread studio 添加CAN通信功能 按上面配置完成后串口会打印下图所示问题 xff1a xff08 can dev write data
  • (二)STM32串口总结(库函数版)

    一 STM32F103有两个串口 图中 TXD RXD 是相对 CH340G 来说的 xff0c 也就是 USB 串口的发送和接收引脚 而 USART1 RX 和 USART1 TX 则是相对于 STM32F103ZET6 来说的 也就是说
  • Matlab画图 线条的颜色、宽度等相关设置

    线条的属性有 xff1a Color 颜色 LineWidth 线条宽度 LineStyle 线型 LineJoin 线条边角的样式 AlignVertexCenters 锐化垂直线和水平线 线条属性的默认值为 0 0 0 39 39 39
  • 一、图像预处理

    四种图像的基本数据结构 xff1a Image 指Halcon的图像类型 Region 指图像中的一块区域 XLD 指图像中某一块区域的轮廓 Tuple 类似于数组 xff0c 用于存储一幅或多幅图像 内核矩阵的选择 xff1a 核越大越模
  • halcon边缘检测

    边缘检测 Ronny丶 博客园 寻找边缘的传统方法 xff0c 即图像中的暗 光转换 xff0c 是应用边缘滤波器 这些滤光器可以在光和暗区域的边界找到像素 从数学术语中来说 xff0c 这意味着这些滤波器决定了图像的梯度 此图像渐变通常作
  • ZED双目摄像头

    ZED stereol abs 配置踩过的坑 现在种树也不晚 博客园 介绍 xff1a CUDA CUDA 是 ZED SDK 使用的 NVIDIA 库 xff0c 用于在显卡上运行快速 AI 和计算机视觉任务 在 ZED SDK 安装过程
  • linux---五种高级IO模型

    阻塞IO模型非阻塞IO模型信号驱动IO模型异步IO模型多路转接IO模型高级IO重要概念 阻塞IO模型 在内核将数据准备好 xff0c 系统调用会一直等待 xff0c 所有的套接字默认都是阻塞IO方式 阻塞IO是最常见的IO模型 非阻塞IO模
  • Ubuntu错误处理集

    1 W GPG 错误 xff1a https developer download nvidia com compute cuda repos ubuntu1604 x86 64 Release 由于没有公钥 xff0c 无法验证下列签名
  • Linux下配置虚拟CAN

    1 加载vcan模块 sudo modprobe vcan 2 添加vcan0网卡 sudo ip link add dev vcan0 type vcan 3 查看当前CAN网络 ifconfig a 4 开启vcan0 sudo ip
  • ROS基础

    一 ROS的核心概念 节点 xff1a 节点管理器 xff1a 话题 xff1a 消息 xff1a 服务 xff1a 参数 xff1a 二 命令行工具的使用 命令行工具都是以ros开头的 常用命令 rostopicrosserviceros
  • Linux下编译Opencv和contrib

    1 安装准备 1 1 安装依赖项 sudo apt get install cmake sudo apt get install build essential libgtk2 0 dev libavcodec dev libavforma
  • YOLOv5和YOLOv7环境(GPU)搭建测试成功

    本来是用doc写的 xff0c 直接复制到这里很多图片加载缓慢 xff0c 我直接把doc上传到资源里面了 xff0c 0积分下载 xff1a 10条消息 YOLOv5和YOLOv7开发环境搭建和demo运行 Python文档类资源 CSD
  • 单片机通信总述——理论部分(CAN、串口、SPI、I2C等)

    一 基础概念 1 1 通信方法 并行通信 xff1a 传输原理 xff1a 数据各个位同时传输 xff1b 优点 xff1a 速度快 xff1b 缺点 xff1a 占用引脚资源多 是指使用 8 16 32 及 64 根或更多的数据线 有多少
  • Ubuntu系统搭建

    一 创建环境常见问题 1 1 windows11下打开虚拟机蓝屏问题 参考这篇文章 xff0c 控制面板 xff0c 启用和关闭windows功能 xff08 对话框 xff09 113条消息 VMware安装Ubuntu开启蓝屏解决方案
  • J-Link工具查看单片机内存等信息

    1 打开下图应用 2 输入 connect xff08 连接开发板 xff09 AC78013FDLA xff08 你的单片机型号 xff09 SWD xff08 仿真器接口 xff09 1000HZ xff08 接口速度 xff09 连接
  • Qt调用ffmpeg动态库和静态库及编译ffmpeg的方法

    一 编译 二 引入ffmpeg库文件 1 Qt工程下创建lib文件夹 xff0c lib文件夹下再创建ffmepg文件夹 2 将编译好的ffmpeg里面的include 和lib文件夹粘贴到如下文件夹下 xff08 3 xff09 在 pr
  • autoware花屏重影问题

    autoware 安装 花屏 重影问题 最近尝试下autoware来做建图 xff0c 无奈各类安装太过麻烦 xff0c 这里给几个小问题做下纪律 1 xff0c 安装过程 xff0c 走的官网那个 xff0c 事实证明官网教程最全面 xf
  • linux---select,poll,epoll的原理以及优缺点

    多路转接IO xff08 也叫IO多路复用 xff09 是一种处理高并发的IO事件监控 xff0c 同时对大量的描述符进行时间监控 xff0c 监控是否具备IO条件 就绪 xff1a 包括了读就绪事件 xff08 就是有数据到来的时候 xf