服务器连接多客户端
一、epoll 核心函数详解
1. epoll_create
/epoll_create1
- 创建 epoll 实例
c
#include <sys/epoll.h>
int epoll_create(int size); // Linux 2.6.8前需指定size(>=1),后续版本可忽略
int epoll_create1(int flags); // 推荐使用,支持flags参数
- 功能:创建一个 epoll 实例,返回文件描述符(epfd),用于管理监视的文件描述符。
- 参数:
size
:旧版本需指定预分配大小(无实际作用,可设为 1)。flags
:0
:与epoll_create
功能相同。EPOLL_CLOEXEC
:使 epfd 在进程 fork 时自动关闭。
- 返回值:成功返回 epfd(非负整数),失败返回
-1
并置errno
。 - 示例:
c
int epfd = epoll_create1(EPOLL_CLOEXEC); // 创建带自动关闭功能的epoll实例
2. epoll_ctl
- 管理监视列表
c
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
- 功能:向 epoll 实例中添加、修改或删除监视的文件描述符及其事件。
- 参数:
epfd
:epoll 实例的文件描述符。op
:操作类型:EPOLL_CTL_ADD
:添加文件描述符fd
到监视列表。EPOLL_CTL_MOD
:修改fd
关联的事件。EPOLL_CTL_DEL
:从监视列表删除fd
(event
参数可置NULL
)。
fd
:需操作的文件描述符(如套接字)。event
:指向epoll_event
结构体的指针,包含监视事件和用户数据:c
struct epoll_event {uint32_t events; // 监视事件(如EPOLLIN、EPOLLOUT、EPOLLET)epoll_data_t data; // 用户数据(如fd、指针等) }; typedef union epoll_data {void *ptr; // 自定义指针int fd; // 监视的文件描述符uint32_t u32; // 32位整数uint64_t u64; // 64位整数 } epoll_data_t;
- 返回值:成功返回
0
,失败返回-1
并置errno
。 - 示例:
c
struct epoll_event event; event.events = EPOLLIN | EPOLLET; // 边缘触发模式 + 读事件 event.data.fd = sockfd; epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event); // 添加套接字到监视列表
3. epoll_wait
- 等待事件触发
c
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
- 功能:阻塞等待 epoll 实例中监视的文件描述符触发事件,返回激活的事件列表。
- 参数:
epfd
:epoll 实例的文件描述符。events
:用于存储激活事件的结构体数组。maxevents
:events
数组的最大长度(需小于等于创建时的预分配值)。timeout
:超时时间(ms):-1
:永久阻塞,直到事件触发。0
:非阻塞,立即返回。>0
:超时时间,到期后返回。
- 返回值:
>0
:激活的事件数量(events
中有效元素个数)。0
:超时且无事件触发。-1
:失败并置errno
。
- 示例:
c
struct epoll_event events[1024]; int n = epoll_wait(epfd, events, sizeof(events)/sizeof(events[0]), -1); // 永久阻塞等待事件 for (int i = 0; i < n; i++) {int fd = events[i].data.fd;// 处理事件... }
二、epoll 工作原理
- 数据结构:
- 监视列表:使用红黑树存储所有监视的文件描述符,支持快速增删改查(时间复杂度 O (logN))。
- 激活列表:使用链表或动态数组存储当前触发事件的文件描述符,避免遍历整个红黑树。
- 事件触发流程:
- 通过
epoll_ctl
将文件描述符添加到红黑树(监视列表)。 - 内核监听文件描述符状态,当事件(如可读、可写)发生时,将其加入激活列表。
epoll_wait
返回激活列表中的事件,用户空间处理后,激活列表清空。
- 通过
三、LT(水平触发)与 ET(边缘触发)模式对比
特性 | LT(水平触发) | ET(边缘触发) |
---|---|---|
触发条件 | 只要内核缓冲区有数据未读 / 未写,就持续触发事件。 | 仅在状态变化时触发一次事件(如数据从无到有)。 |
读操作 | 允许分多次读取,剩余数据会再次触发事件。 | 必须一次性读完所有数据(需配合非阻塞 I/O),否则剩余数据不再触发。 |
写操作 | 只要内核缓冲区有空间,就持续触发可写事件。 | 仅在缓冲区由满变空时触发一次可写事件。 |
编程复杂度 | 低,类似 select/poll,无需处理非阻塞。 | 高,必须使用非阻塞 I/O,避免阻塞导致事件丢失。 |
适用场景 | 简单场景、低速设备或不确定数据量的场景。 | 高并发、高速数据传输场景(如 Web 服务器、实时通信)。 |
- 示例配置:
c
// LT模式(默认,无需指定EPOLLET) event.events = EPOLLIN; // ET模式(需显式指定EPOLLET) event.events = EPOLLIN | EPOLLET;
四、select/poll/epoll 对比(面试重点)
特性 | select | poll | epoll |
---|---|---|---|
数据结构 | 位图(数组),最大连接数受限于FD_SETSIZE (默认 1024)。 | 结构体数组,理论无连接数限制(仅受内存限制)。 | 红黑树 + 激活列表,支持上万级连接(如 10,000+)。 |
内核遍历方式 | 每次调用遍历所有监视的文件描述符(O (n))。 | 每次调用遍历所有监视的文件描述符(O (n))。 | 仅遍历激活列表中的文件描述符(O (1)~O (k),k 为激活数)。 |
用户态 / 内核态数据拷贝 | 每次select 需拷贝全量文件描述符到内核。 | 每次poll 需拷贝全量文件描述符到内核。 | 仅在epoll_ctl 时更新红黑树,epoll_wait 无需拷贝。 |
触发模式 | 仅支持 LT 模式。 | 仅支持 LT 模式。 | 支持 LT 和 ET 模式。 |
跨平台性 | 支持(Linux/Windows/macOS)。 | 支持(Linux/UNIX)。 | 仅 Linux 支持。 |
适用场景 | 低并发、跨平台场景(如嵌入式)。 | 中等并发场景。 | 高并发、Linux 服务器场景(如 Nginx、Redis)。 |
五、epoll 服务器示例代码关键点(C 语言)
c
// 1. 创建epoll实例并设置监听套接字为非阻塞
int epfd = epoll_create1(EPOLL_CLOEXEC);
set_nonblocking(listen_fd); // 自定义函数,通过fcntl设置O_NONBLOCK// 2. 注册监听套接字到epoll(ET模式)
struct epoll_event event = {.events = EPOLLIN | EPOLLET,.data = {.fd = listen_fd}
};
epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &event);// 3. 处理新连接(ET模式下需循环accept直到EAGAIN)
if (fd == listen_fd) {while (1) {int connfd = accept(listen_fd, &cliaddr, &addrlen);if (connfd == -1) {if (errno == EAGAIN || errno == EWOULDBLOCK) break; // 无新连接perror("accept");exit(EXIT_FAILURE);}set_nonblocking(connfd); // 客户端套接字也需设为非阻塞epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &event); // 注册读事件(ET模式)}
}// 4. 处理读事件(ET模式下需循环recv直到EAGAIN)
else {char buf[BUFFER_SIZE];while (1) {ssize_t n = recv(fd, buf, sizeof(buf), 0);if (n == -1) {if (errno == EAGAIN || errno == EWOULDBLOCK) break; // 数据读完perror("recv");close(fd);epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);break;} else if (n == 0) { // 客户端关闭连接close(fd);epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);break;}// 处理数据...}
}
六、总结
- epoll 优势:
- 高并发:基于红黑树和激活列表,适合管理上万级连接。
- 高性能:事件通知复杂度 O (1),减少 CPU 消耗。
- 灵活性:支持 LT/ET 模式,适配不同场景。
- 使用建议:
- 高并发服务器首选 epoll,配合 ET 模式和非阻塞 I/O。
- 简单场景或跨平台需求使用 select/poll。
- 注意设置文件描述符非阻塞,避免 ET 模式下的数据丢失。
相关文章:
服务器连接多客户端
一、epoll 核心函数详解 1. epoll_create/epoll_create1 - 创建 epoll 实例 c #include <sys/epoll.h> int epoll_create(int size); // Linux 2.6.8前需指定size(>1),后续版本可忽略 int epoll_create1(int flags); // 推荐使用…...

基于QT和FFmpeg实现自己的视频播放器FFMediaPlayer(一)——项目总览
在音视频开发的学习过程中,开发一款视频播放器是FFmpeg进阶的最好实战方法。本文将基于 QT 和 FFmpeg 着手实现自定义视频播放器 FFMediaPlayer,作为系列文章的开篇,我们先来整体了解项目的设计思路、架构与配置。 一、软件设计五大原则 …...
服务器死机了需要检查哪些问题
在这个数字化的时代,服务器就像是我们信息世界的“大管家”,可要是它突然死机了,那可真是让人头疼。今天咱们就来聊聊,服务器死机了,到底需要检查哪些问题。 一、硬件问题 电源供应:检查电源是否稳定&…...

【HCIA】浮动路由
前言 我们通常会在出口路由器配置静态路由去规定流量进入互联网默认应该去往哪里。那么,如果有两个运营商的路由器都能为我们提供上网服务,我们应该如何配置默认路由呢?浮动路由又是怎么一回事呢? 文章目录 前言1. 网络拓扑图2. …...

使用instance着色
本节我们学习使用instance着色器进行着色 //拾取var handler new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);handler.setInputAction(function(movement){console.log(movement);var pickedObject viewer.scene.pick(movement.position);if(Cesium.defined(picke…...

【NLP 72、Prompt、Agent、MCP、function calling】
命运把我们带到哪里,就是哪里 —— 25.5.13 一、Prompt 1.User Prompt 用户提示词 当我们与大模型进行对话时,我们向大模型发送的消息,称作User Prompt,也就是用户提示词,一般就是我们提出的问题或者想说的话 但是我们…...

Mysql数据库之集群进阶
一、日志管理 5.7版本自定义路径时的文件需要自己提前创建好文件,不会自动创建,否则启动mysql会报错 错误日志 rpm包(yum) /var/log/mysql.log 默认错误日志 ###查询日志路径 [rootdb01 ~]# mysqladmin -uroot -pEgon123 variables | grep -w log_e…...

临床决策支持系统的提示工程优化路径深度解析
引言 随着人工智能技术在医疗领域的迅猛发展,临床决策支持系统(CDSS)正经历从传统规则引擎向智能提示工程的范式转变。在这一背景下,如何构建既符合循证医学原则又能适应个体化医疗需求的CDSS成为医学人工智能领域的核心挑战。本报告深入剖析了临床决策支持系统中提示工程的…...
精益数据分析(64/126):移情阶段的用户触达策略——从社交平台到精准访谈
精益数据分析(64/126):移情阶段的用户触达策略——从社交平台到精准访谈 在创业的移情阶段,精准找到目标用户并开展深度访谈是验证需求的关键。今天,我们结合《精益数据分析》中的方法论,探讨如何利用Twit…...

苹果新一代车载系统CarPlay Ultra来袭,全屏接管+ChatGPT助力,智能驾驶要“起飞”
AITOP100获悉,苹果又搞出大动作啦!正式推出了新一代车载系统——CarPlay Ultra。这次,苹果可是下了狠功夫,把iPhone和汽车的所有显示屏深度整合到了一起,还首次把ChatGPT引入到了驾驶体验当中。这系统可不简单…...

无线信道的噪声与干扰
目录 1. 无线信道(wireless channel)与电磁波 2.1 电磁波的传输(无线信道传输) 2.2 视线(line of sight)传播与天线高度 2. 信道的数学模型 2.1 调制信道模型 2.1.1 加性噪声/加性干扰 2.1.2 乘性噪声/乘性干扰 2.1.3 随参信道/恒参信道 2.2 编码信道模型 2.3 小结 …...

MySQL 8.0 OCP 1Z0-908 101-110题
Q101.which two queries are examples of successful SQL injection attacks? A.SELECT id, name FROM backup_before WHERE name‘; DROP TABLE injection; --’; B. SELECT id, name FROM user WHERE id23 oR id32 OR 11; C. SELECT id, name FROM user WHERE user.id (SEL…...

BBR 的 buffer 动力学观感
这周很忙,今天还加了一天班,但还是抽空实现了五一在安徽泾县山区喝着一壶酒写的 BBR ProbeRTT 的想法,没多少行代码,它真就消除了带宽锯齿,皮了个鞋👞,昨天我还在群里说了今天再说说 BBR 的&…...

Spring之Bean的初始化 Bean的生命周期 全站式解析
目录 导图 步骤 第一步 实例化 第二步 属性赋值 第三步 初始化 aware 接口 BeanPostProcessor 接口 InitializingBean 和 init-method 第四步使用 第五步使用后销毁 描述一下 Bean 的 生命周期 导图 步骤 总体上可以分为五步 首先是 Bean 的实例化Bean 在进行实例…...

FreeCAD源码分析: Transaction实现原理
本文阐述FreeCAD中Transaction的实现原理。 注1:限于研究水平,分析难免不当,欢迎批评指正。 注2:文章内容会不定期更新。 一、概念 Ref. from What is a Transaction? A transaction is a group of operations that have the f…...

flutter缓存网络视频到本地,可离线观看
记录一下解决问题的过程,希望自己以后可以参考看看,解决更多的问题。 需求:flutter 缓存网络视频文件,可离线观看。 解决: 1,flutter APP视频播放组件调整; 2,找到视频播放组件&a…...

Kotlin 中 infix 关键字的原理和使用场景
在 Kotlin 中,使用 infix 关键字修饰的函数称为中缀函数,使用是可以省略 . 和 (),允许以更自然(类似自然语言)的语法调用函数,这种特性可以使代码更具可读性。 1 infix 的原理 中缀函数必须满足以下条件&…...

c++从入门到精通(五)--异常处理,命名空间,多继承与虚继承
异常处理 栈展开过程: 栈展开过程沿着嵌套函数的调用链不断查找,直到找到了与异常匹配的catch子句为止;也可能一直没找到匹配的catch,则退出主函数后查找过程终止。栈展开过程中的对象被自动销毁。 在栈展开的过程中,…...
mock 数据( json-server )
json-server 实现数据 mock 实现步骤: 1. 在项目中安装 json-server npm install -D json-server 2. 准备一个 json 文件 server/data.json {"posts": [{ "id": "1", "title": "a title", "views"…...
Java多线程编程中的常见问题与陷阱汇总
线程安全问题 多线程环境下,多个线程同时访问共享资源时,可能会导致数据不一致或程序行为异常。常见的线程安全问题包括竞态条件、死锁、活锁等。 public class Counter {private int count 0;public void increment() {count;}public int getCount()…...
ARP Detection MAC-Address Static
一、ARP Detection(ARP检测) ✅ 定义: ARP检测是一种防止ARP欺骗攻击的安全机制。它通过监控或验证网络中的ARP报文,来判断是否存在伪造的ARP信息。 🔍 工作原理: 网络设备(如交换机…...

gcc/g++常用参数
1.介绍 gcc用于编译c语言,g用于编译c 源代码生成可执行文件过程,预处理-编译-汇编-链接。https://zhuanlan.zhihu.com/p/476697014 2.常用参数说明 2.1编译过程控制 参数作用-oOutput,指定输出名字-cCompile,编译源文件生成对…...

nginx配置之负载均衡
版权声明:原创作品,请勿转载! 1.实验环境准备 准备3台linux服务器(ubuntu和centos均可,本文使用centos7.9),两台web和一台负载均衡服务器,均安装nginx服务 主机名IP软件lb0110.0.0…...
相机Camera日志分析之十一:高通相机Camx hal预览1帧logcat日志process_capture_result详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:高通相机Camx 日志分析之五:camx hal预览1帧logcat日志process_capture_request详解 这一篇我们开始讲: 高通相机Camx 日志分析之十一:camx hal预览1帧logcat日志process_capture_result详解,这里我…...
Python函数库调用实战:以数据分析为例
一、引言 Python之所以在编程领域广受欢迎,很大程度上得益于其丰富且强大的函数库。这些函数库涵盖了从数据分析、科学计算到Web开发、机器学习等众多领域,极大地提高了开发效率。本文将以数据分析为例,介绍如何调用Python的一些常用函数库。…...

去年开发一款鸿蒙Next Os的window工具箱
持拖载多个鸿蒙应用 批量签名安装 运行 http://dl.lozn.top/lozn/HarmonySignAndFileManagerTool_2024-11-26.zip 同类型安卓工具箱以及其他软件下载地址汇总 http://dl.lozn.top/lozn/ 怎么个玩法呢,比如要启动某app, 拖载识别到包名 点启动他能主动读取包名 然后…...
顶层设计-IM系统架构
一、系统总体架构概览 即时通讯(IM)系统的核心目标,是让用户可以随时随地稳定地发送和接收消息。为了支撑成千上万用户同时在线交流,我们需要将整个系统划分成多个专职模块,每个模块只负责一件事情,彼此协同…...
信任的进阶:LEI与vLEI协同推进跨境支付体系变革
在全球经济版图加速重构的背景下,跨境支付体系正经历着前所未有的变革。2022年全球跨境支付规模突破150万亿美元,但平均交易成本仍高达6.04%,支付延迟超过2.7天。 这种低效率背后,隐藏着复杂的身份识别困境:超过40%的…...
安全性(三):信息安全的五要素及其含义
五要素及其含义 序号要素英文缩写含义说明1保密性Confidentiality仅授权用户才能访问信息,防止信息被非法获取或泄露(例如:加密、访问控制)2完整性Integrity信息在传输、存储和处理过程中保持准确、完整、未被篡改(例…...
PHP 与 面向对象编程(OOP)
PHP 是一种支持面向对象编程(OOP)的多范式语言,但其面向对象特性是逐步演进而非原生设计。以下是关键分析: 1. PHP 对面向对象编程的支持 核心 OOP 特性: 类和对象: PHP 支持通过 class 关键字定义类&…...