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

Linux学习-TCP并发服务器构建(epoll)

一、核心特点(对比 select、poll 优势)

  1. 存储结构:用红黑树存文件描述符集合,无数量上限,查找高效
  2. 数据拷贝:集合创建在内核层,避免应用层 - 内核层反复拷贝,降低开销
  3. 事件处理:返回到达事件,无需遍历,直接处理,效率高
  4. 触发模式:支持水平触发(低速)和边沿触发(高速),适配不同场景

二、操作流程与关键函数

  1. 创建集合int epoll_create(int size)
    • 功能:通知内核创建文件描述符集合
    • 参数:size 填监测的文件描述符预期数量(实际无严格限制,传正整数即可 )
    • 返回:成功返回集合的文件描述符(用于后续操作),失败返回 -1
  2. 管理集合(增删改)int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
    • 功能:操作 epoll 集合(添加、修改、删除文件描述符及事件)
    • 参数:
      • epfdepoll_create 返回的集合描述符
      • op:操作类型,如 EPOLL_CTL_ADD(添加)、EPOLL_CTL_MOD(修改)、EPOLL_CTL_DEL(删除)
      • fd:要操作的文件描述符
      • event:事件结构体,含 events(事件类型,如 EPOLLIN 读、EPOLLOUT 写 )和 data(关联数据,常用 data.fd 存关注的文件描述符 )
    • 返回:成功返回 0,失败返回 -1
  3. 监测事件int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
    • 功能:通知内核开始监测事件,阻塞等待事件触发
    • 参数:
      • epfd:要监测的集合描述符
      • events:数组,用于存返回的到达事件结果
      • maxevents:最多处理的事件个数(需 ≤ events 数组大小 )
      • timeout:超时时间,-1 表示一直阻塞,0 立即返回,正数为毫秒级超时
    • 返回:成功返回触发的事件数量,失败返回 -1
  4. 事件类型与数据结构
    • epoll_data_t 联合结构体:可存指针、文件描述符等,常用 fd 关联关注的描述符
    • struct epoll_event:含 events(事件类型标记,如 EPOLLIN/EPOLLOUT )和 dataepoll_data_t 类型数据 )

三、核心原理与数据结构

epoll 在内核中维护两个关键数据结构,共同实现高效事件管理:

  1. 红黑树(RB-Tree)

    • 用途:存储所有被监控的 FD 及其关联的事件(如 EPOLLINEPOLLOUT)。
    • 优势:插入、删除、查找 FD 的时间复杂度为 O(log n),支持动态增删大量 FD,无数量上限(仅受系统内存限制)。
  2. 就绪链表(Ready List)

    • 用途:缓存所有触发了事件的 FD(就绪 FD)。
    • 优势:epoll_wait 直接从链表中获取就绪 FD,无需遍历全部 FD,效率极高。

四、关键函数详解

1. 创建 epoll 实例:epoll_create
#include <sys/epoll.h>
int epoll_create(int size);
  • 功能:向内核申请创建一个 epoll 实例(管理 FD 集合的句柄)。

  • 参数size 是历史遗留参数,早期用于提示内核预分配空间,现代 Linux 中已忽略(只需传一个正整数即可)。

  • 返回值:成功返回 epoll 实例的文件描述符(epfd),失败返回 -1(需检查 errno)。

  • 注意epfd 本身也是一个 FD,使用完毕后需用 close(epfd) 释放资源。

2. 管理监控的 FD:epoll_ctl
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  • 功能:向 epoll 实例添加、修改或删除被监控的 FD 及事件。

  • 参数

    • epfdepoll_create 返回的实例句柄。
    • op:操作类型:
      • EPOLL_CTL_ADD:添加 FD 到监控集合。
      • EPOLL_CTL_MOD:修改已监控 FD 的事件类型。
      • EPOLL_CTL_DEL:从监控集合中删除 FD(此时 event 可设为 NULL)。
    • fd:需要监控的文件描述符(如 socket FD)。
    • event:事件结构体,定义如下:
      struct epoll_event {uint32_t events;  // 事件类型(位掩码)epoll_data_t data;  // 关联数据(用户自定义)
      };typedef union epoll_data {void    *ptr;  // 指针(可关联自定义数据结构)int      fd;   // 常用:关联被监控的 FD 本身uint32_t u32;uint64_t u64;
      } epoll_data_t;
      
    • events 常用类型:
      • EPOLLIN:FD 可读(如 socket 收到数据)。
      • EPOLLOUT:FD 可写(如 socket 发送缓冲区空闲)。
      • EPOLLERR:FD 发生错误(无需主动设置,内核自动触发)。
      • EPOLLET:启用边沿触发模式(默认是水平触发)。
      • EPOLLONESHOT:事件触发一次后自动取消监控(需重新添加才能再次监控)。
  • 返回值:成功返回 0,失败返回 -1(如 FD 已被监控、权限不足等)。

3. 等待就绪事件:epoll_wait
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
  • 功能:阻塞等待监控集合中就绪的事件,将结果存入 events 数组。

  • 参数

    • epfdepoll 实例句柄。
    • events:用户分配的数组,用于接收就绪事件(输出参数)。
    • maxeventsevents 数组的最大长度(必须 ≥ 1)。
    • timeout:超时时间(毫秒):
      • -1:永久阻塞,直到有事件就绪。
      • 0:立即返回(非阻塞模式)。
      • >0:最多阻塞 timeout 毫秒,超时后返回 0
  • 返回值

    • 成功:返回就绪事件的数量(0 表示超时,无就绪事件)。
    • 失败:返回 -1(如被信号中断,需检查 errno)。

五、与 select/poll 的对比

特性selectpollepoll
监控 FD 数量上限有(通常 1024)无(受系统内存限制)无(受系统内存限制)
事件存储位图(固定大小)数组(动态分配)红黑树 + 就绪链表
事件检测方式遍历所有 FD遍历所有 FD直接取就绪链表(无需遍历)
数据拷贝每次调用拷贝全部 FD每次调用拷贝全部 FD仅初始化时拷贝一次
触发模式仅水平触发仅水平触发水平触发 + 边沿触发
时间复杂度O(n)O(n)O(1)(获取就绪事件)
高并发表现差(FD 越多越慢)较差(遍历开销大)优秀(无遍历开销)

六、典型使用流程

  1. 创建 socket 并绑定端口,设为监听状态(listen)。
  2. 调用 epoll_create 创建 epoll 实例(epfd)。
  3. 调用 epoll_ctl 添加监听 socket 到 epoll 集合(关注 EPOLLIN 事件)。
  4. 循环调用 epoll_wait 等待就绪事件:
    • 若监听 socket 就绪(新连接),调用 accept 获取客户端 socket,添加到 epoll 集合。
    • 若客户端 socket 就绪(可读/可写),处理数据(读/写操作)。
  5. 断开连接时,调用 epoll_ctl 从集合中删除客户端 socket。
http://www.dtcms.com/a/354509.html

相关文章:

  • 【C++】C++11的右值引用和移动语义
  • Unity游戏打包——iOS打包基础、上传
  • 使用Docker部署ZLMediaKit流媒体服务器实现gb/t28181协议的设备
  • Day30 多线程编程 同步与互斥 任务队列调度
  • ArcGIS学习-12 实战-综合案例
  • Unity游戏打包——iOS打包pod的重装和使用
  • Flutter:ios打包ipa,证书申请,Xcode打包,完整流程
  • Intern-S1-mini模型结构
  • SpringBoot系列之实现高效批量写入数据
  • 专项智能练习(图形图像基础)
  • 文本处理与模型对比:BERT, Prompt, Regex, TF-IDF
  • 高精度惯性导航IMU价格与供应商
  • [sys-BlueChi] docs | BluechiCtl命令行工具
  • 【C#/Cpp】CLR项目搭建的内联和托管两选项
  • IPv4和IPv6的主要区别,以及常见的过渡策略有哪些
  • OpenCV计算机视觉实战(22)——图像拼接详解
  • 机器视觉学习-day07-图像镜像旋转
  • 【开题答辩全过程】以 基于Spring Boot农产品运输服务平台为例,包含答辩的问题和答案
  • MapStruct用法和实践
  • 【笔记ing】大模型算法架构
  • android studio 同步慢问题解决
  • Logstash数据迁移之mysql-to-kafka.conf两种路由决策对比
  • WebRTC音频QoS方法五(音频变速算法之Accelerate、FastAccelerate、PreemptiveExpand算法实现)
  • Kafka、RabbitMQ 与 RocketMQ 在高并发场景下的高可用与性能对比分析
  • 游戏使用云手机在线运行怎么样?
  • 小白成长之路-k8s原理(二)
  • 【在 macOS 系统上使用 Docker 启动 Kafka 的完整指南】
  • 点评项目(Redis中间件)第二部分Redis基础
  • ArtCAM 2008安装教程
  • React 业务场景使用相关封装(hooks 使用)