当前位置: 首页 > news >正文

【无标题】I/O复用(epoll)三者区别▲

一、SOCKET-IO复用技术

定义:SOCKET - IO复用技术是一种高效处理多个套接字(socket)的手段,能让单个线程同时监听多个文件描述符(如套接字)上的I/O事件(像可读、可写、异常),进而提高程序的并发处理能力,避免为每个套接字创建一个线程或进程带来的资源开销(像一个管家)

是由函数select、poll和 Epoll 支持的

1.select、poll和 Epoll三者的区别:

select:轮回机制,存储容器数组,固定大小

poll:轮回机制,存储容器链表,动态扩展

epoll:事件驱动机制

2. 数据结构与扩展性

机制存储容器类型最大连接数限制动态扩展能力
select固定大小的位掩码数组通常为 1024(FD_SETSIZE)❌ 无法扩展
poll动态链表(struct pollfd)无硬性限制(取决于系统资源)✅ 动态添加
epoll内核红黑树 + 就绪链表无硬性限制(仅受内存约束)✅ 自动管理
  • select:使用固定大小的 fd_set(位掩码)存储文件描述符,需手动管理位操作,扩展性差。
  • poll:使用链表 struct pollfd 存储文件描述符,可动态添加,突破了 select 的限制。
  • epoll:使用内核红黑树高效管理所有待监控的文件描述符,自动扩容。

3. 工作机制

机制事件触发方式轮询方式性能特性
select水平触发(Level Triggered)遍历所有文件描述符O (n) 时间复杂度
poll水平触发遍历所有文件描述符O (n) 时间复杂度
epoll边缘触发(Edge Triggered)或水平触发仅遍历就绪链表O (1) 时间复杂度
  • 水平触发(LT):只要文件描述符就绪(如可读),就会持续通知。
  • 边缘触发(ET):仅在文件描述符状态变化(如从不可读到可读)时通知一次,需立即处理,否则数据可能丢失。

4. 性能对比

场景select/poll 表现epoll 表现
连接数少且活跃效率较高优势不明显
连接数多但不活跃性能急剧下降(轮询所有连接)性能稳定(仅处理就绪连接)
大量并发连接不适用(受 FD_SETSIZE 限制)非常高效

二、Epoll函数

基于以上三种方法对比,所以我们选用epoll进行使用较为合适

epoll两种模式的区别:

LT逻辑简单,但效率低,ET反之

核心数据结构是:1个红黑树和1个链表

1.创建

int epoll_create(int size);

参数size表明内核要监听的描述符数量。调用成功时返回一个epoll句柄描述符,失败时返回-1

2.注册要监听的事件类型

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

  • 参数:用于控制 epoll 实例对文件描述符的监听。
    • epfd是由epoll_create函数返回的 epoll 实例的文件描述符。
    • op参数指定操作类型,常见的值有EPOLL_CTL_ADD(将文件描述符fd添加到 epoll 实例的监听列表中)、EPOLL_CTL_MOD(修改文件描述符fd的监听事件)和EPOLL_CTL_DEL(从 epoll 实例的监听列表中删除文件描述符fd)。
    • fd是要进行操作的文件描述符。
    • event是一个指向struct epoll_event结构体的指针,用于指定要监听的事件类型以及关联的数据。
  • 返回值:成功时返回 0;失败时返回 -1,并设置errno以指示错误原因。

3.等待事件的就绪

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

  • 功能:等待 epoll 实例所监听的文件描述符上有事件发生。
    • epfd是 epoll 实例的文件描述符。
    • events是一个struct epoll_event类型的数组,用于存储发生事件的文件描述符及其相关事件信息。
    • maxevents指定了events数组的大小,即最多能返回的事件数量。
    • timeout指定等待的超时时间,以毫秒为单位。如果设置为 -1,则表示无限期等待,直到有事件发生;如果设置为 0,则表示立即返回,不进行等待。
  • 返回值:成功时返回发生事件的文件描述符数量;如果超时则返回 0;失败时返回 -1,并设置errno以指示错误原因。
#include "epollServer.h"epollServer::epollServer(int port)
{this->server = new TCPServer(port);init_epoll();
}void epollServer::init_epoll()
{// 创建epollepoll_fd = epoll_create(10);if (epoll_fd < 0) {perror("epoll_create error");return;}// 添加epoll关注事件//struct epoll_event epoll_event;epoll_event.data.fd = this->server->getServerfd();epoll_event.events = EPOLLIN;epoll_ctl(epoll_fd, EPOLL_CTL_ADD, this->server->getServerfd(), &epoll_event);cout << "epoll初始化完成..." << endl;
}void epollServer::start()
{struct epoll_event event_array[10] = { 0 };int event_num = 0;this->thread_pool = new ThreadPool2(5);// 主循环while (1) {cout << "epoll wait..." << endl;event_num = epoll_wait(epoll_fd, event_array, 10, -1);// cout<<event_arrayif (event_num < 0) {perror("epoll_wait error");continue;}for (int i = 0; i < event_num; i++) {if (event_array[i].data.fd == this->server->getServerfd()) {//处理连接请求cout << "有新客户端连接请求" << endl;int client_fd = accept(this->server->getServerfd(), NULL, NULL);if (client_fd < 0) {continue;}// 将新的客户端连接添加到epoll关注列表epoll_event.data.fd = client_fd;epoll_event.events = EPOLLIN;epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &epoll_event);}else if (event_array[i].events & EPOLLIN) {//处理请求监听的事件}}}
}

相关文章:

  • LeetCode 热题 100 24. 两两交换链表中的节点
  • JS正则表达式介绍(JavaScript正则表达式)
  • AI与机器人学:从SLAM到导航的未来
  • leetcode 2918. 数组的最小相等和 中等
  • Windows右键管理工具:轻松添加/删除/修改右键菜单项!
  • 常见的算法介绍
  • c++ struct类型加强
  • Python实例题:Python协程详解公开课
  • 如何让“语言不通”的纺织设备通过Profinet转CanOpen网关“聊”起来?
  • Ethercat转Profinet网关如何用“协议翻译术“打通自动化产线任督二脉
  • 数据库中的 Segment、Extent、Page、Row 详解
  • Vue3响应式原理源码解析(通俗易懂版)
  • C PRIMER PLUS——第7节:指针
  • OC语言学习——Foundation框架(上)
  • adamantix系统详细讲解
  • 数据结构与算法:树型dp
  • [C++] 大数减/除法
  • 鸿蒙 所有API缩略图鉴
  • Web3 初学者的第一个实战项目:留言上链 DApp
  • 质量保证计划,软件质量计划书,软件质量方案(word原件)
  • 中国工程院院士、国医大师石学敏逝世
  • 冷冰川谈黑白
  • 祝贺!苏翊鸣成功解锁“2160”
  • 竞彩湃|霍芬海姆看到保级曙光,AC米兰专注于意大利杯
  • 全国人大常委会启动食品安全法执法检查
  • 铲屎官花5万带猫狗旅行,宠旅生意有多赚?