Epoll模型
Epoll模型一、底层核心原理每一个epoll模型内部都维护了一棵红黑树当调用epoll_ctl并执行EPOLL_CTL_ADD操作时会将新增的文件描述符fd及关联数据构造成一个新结点存入这棵红黑树中。此外epoll模型中还维护了一个就绪队列当文件描述符上有事件就绪时底层会触发中断操作系统会将该文件描述符对应的红黑树结点放入就绪队列中。当执行epoll_wait时就能直接拿到所有已经就绪的事件对应的fd由程序员自行处理。二、为什么用红黑树存储 fd 数据因为epoll模型可监测的 fd 数量没有硬上限当存在大量 fd 时使用红黑树既可以对 fd 进行高效管理也能实现快速查找与增删操作。三、事件结点如何加入就绪队列红黑树的每一个结点中存储的不只有 fd还包含其他指针字段。当某个结点有事件就绪时不需要重新拷贝整个结点再添加到就绪队列只需要通过结点内的就绪队列指针将结点链入就绪队列即可头插或尾插方式全程无需拷贝结点数据。四、epoll IO 多路转接的整体使用逻辑epoll 是 IO 多路转接模型的一种实现相比 select/poll 效率更高。使用 epoll 的大致流程为调用epoll_create创建一个 epoll 模型获取该模型的句柄本质也是一个文件描述符调用epoll_ctl将需要监听的文件描述符添加到 epoll 模型中进行事件检测在事件循环中调用epoll_wait接口等待就绪的文件描述符五、核心接口详细介绍1.epoll_create功能创建一个 epoll 模型实例返回该实例的句柄文件描述符。说明该函数的参数在新版本内核中已被弃用传入一个大于 0 的数字即可。函数原型#include sys/epoll.h int epoll_create(int size);使用样例// 1.创建epoll模型 _epfd epoll_create(128); if(_epfd 0) { std::cout epoll create error, strerror(errno) std::endl; exit(-1); }2.epoll_ctl功能通过 epoll 句柄对被监听的文件描述符执行增、删、改操作。成功返回 0失败返回 - 1。函数原型#include sys/epoll.h int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);参数说明epfdepoll 模型的句柄op操作类型EPOLL_CTL_ADD将 fd 添加到 epoll 模型中进行监听EPOLL_CTL_MOD修改 fd 对应的监听事件EPOLL_CTL_DEL将 fd 从 epoll 模型中移除fd目标文件描述符event需要监听的事件结构体其中epoll_event结构体定义如下events字段用于设置需要监听的事件常用的有EPOLLIN可读事件、EPOLLOUT可写事件data字段用户自定义数据一般将 fd 存入该字段的fd成员中struct epoll_event { uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ }; typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64; }epoll_data_t;使用样例// 2.将listen套接字加入到epoll模型中 // 先构建一个事件结构体 struct epoll_event ev; ev.events | EPOLLIN; ev.data.fd _socket-GetSockfd(); int n epoll_ctl(_epfd, EPOLL_CTL_ADD, _socket-GetSockfd(), ev); // 成功返回0 if(n ! 0) { std::cout epoll control error, strerror(errno) std::endl; exit(-1); }3.epoll_wait功能检查 epoll 模型中是否有文件描述符的事件就绪。如果有就绪事件会将这些就绪的 epoll 事件放到events缓冲区中成功时返回就绪事件的个数超时返回 0出错返回 - 1。函数原型#include sys/epoll.h int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);参数说明epfdepoll 模型的句柄events存放就绪事件的输出缓冲区maxevents缓冲区最多能容纳的事件个数timeout超时时间单位是毫秒使用样例// 定义常量表示就绪事件缓冲区的最大容量 const static int gnum 64; // 定义存放就绪事件的缓冲区 struct epoll_event _events[gnum]; // 调用epoll_wait进行等待超过1秒就会返回继续向下执行 int n epoll_wait(_epfd, _events, gnum, 1000); if(n 0) { // 没有事件就绪超时返回 std::cout time out... std::endl; } else if(n 0) { // 有n个事件就绪开始处理事件 HandlerEvents(n); } else { if(errno EINTR) continue; std::cout epoll wait fail, strerror(errno) std::endl; exit(-1); }代码样例——EpollServerDemoEpollServer.hpp#pragma once #include iostream #include memory #include TcpSocket.hpp #include unordered_map #include unistd.h #include sys/epoll.h class EpollServer { private: const static int Nsizeof(fd_set)*8; const static int defaultfd-1; const static int gnum64; public: EpollServer(uint16_t port) :_port(port) ,_socket(std::make_uniqueTcpSocket(port)) ,_epfd(defaultfd) { // 1.创建epoll模型 _epfdepoll_create(128); if(_epfd0) { std::coutepoll create error, strerror(errno)std::endl; exit(-1); } // 2.将listen套接字加入到epoll模型中 // 先构建一个事件结构体 struct epoll_event ev; ev.events|EPOLLIN; ev.data.fd_socket-GetSockfd(); int n epoll_ctl(_epfd, EPOLL_CTL_ADD, _socket-GetSockfd(), ev); // 成功返回0 if(n!0) { std::coutepoll control error, strerror(errno)std::endl; exit(-1); } } void HandlerEvents(int num) { std::cout有Numnum个事件就绪了std::endl; } void Loop() { while(true) { int nepoll_wait(_epfd, _events, gnum, 1000); if(n0) { // 事件没有就绪 std::couttime out...std::endl; } else if(n0) { // 有n个事件就绪了 HandlerEvents(n); } else { if(errnoEINTR) continue; std::coutepoll wait fail, strerror(errno)std::endl; exit(-1); } } } private: int _epfd; uint16_t _port; std::unique_ptrTcpSocket _socket; struct epoll_event _events[gnum]; };TcpSocket.hpp#pragma once #include iostream #include sys/socket.h #include arpa/inet.h #include netinet/in.h #include cstring class InetAddr { public: InetAddr() {} InetAddr(const std::stringip, uint16_t port) :_ip(ip) ,_port(port) { memset(_sockaddr, 0, sizeof(_sockaddr)); _sockaddr.sin_familyAF_INET; _sockaddr.sin_porthtons(port); _sockaddr.sin_addr.s_addrinet_addr(_ip.c_str()); } std::string Ip() { return _ip; } uint16_t Port() { return _port; } // 将addr里面的数据拷贝给自己 void GetInetAddr(sockaddr_in*addr) { memcpy(_sockaddr, addr, sizeof(*addr)); _portntohs(addr-sin_port); _ipinet_ntoa(addr-sin_addr); } private: struct sockaddr_in _sockaddr; std::string _ip; uint16_t _port; }; class TcpSocket { public: TcpSocket(uint16_t port) :_port(port) { _listensocketsocket(AF_INET, SOCK_STREAM, 0); if(_listensocket0) { std::cout监听套接字失败std::endl; exit(-1); } // 设置地址复用 int opt1; setsockopt(_listensocket, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt)); // bind struct sockaddr_in local; memset(local, 0, sizeof(local)); local.sin_familyAF_INET; local.sin_porthtons(port); local.sin_addr.s_addrINADDR_ANY; int nbind(_listensocket, (struct sockaddr*)local, sizeof(local)); if(n0) { std::cout绑定失败std::endl; exit(-1); } // 开启监听 n::listen(_listensocket, _defaultBacklog); if(n0) { std::coutTCP监听失败std::endl; exit(-1); } } int Accept(InetAddr*addr) { struct sockaddr_in peer; socklen_t lensizeof(peer); int sockfdaccept(_listensocket, (struct sockaddr*)peer, len); addr-GetInetAddr(peer); return sockfd; } int GetSockfd() { return _listensocket; } private: uint16_t _port; int _listensocket; // 类内常量所有类对象共享一份 const static int _defaultBacklog16; };Main.cc#include iostream #include EpollServer.hpp int main() { std::unique_ptrEpollServer serverstd::make_uniqueEpollServer(8080); server-Loop(); return 0; }makefiletest_server:Main.cc g -g -o $ $^ -stdc14 .PHONY:clean clean: rm -f test_server

相关新闻

Ansible Playbook使用案例

Ansible Playbook使用案例

Ansible Loop 循环Ansible 的 loop 循环功能允许您对一组数据项重复执行同一任务,从而简化批量操作。本节将通过创建用户账户的实例,演示 loop 的基本用法及其进阶应用。1. 1 基础循环:创建用户以下 Playbook 使用 loop 在目标主机组 db 上创…

2026/10/14 9:49:26 阅读更多 →
从OpenClaw到Hermes Agent:AI Agent开发框架的开发者体验演进

从OpenClaw到Hermes Agent:AI Agent开发框架的开发者体验演进

1. 项目概述:一场开发者工具的“静默迁徙”最近在AI Agent开发圈里,我观察到一个挺有意思的现象:身边不少老伙计,包括一些之前对OpenClaw推崇备至的朋友,都开始默默地转向了另一个工具——Hermes Agent。这不像是一场轰…

2026/10/14 9:48:23 阅读更多 →
LeetCode刷题的本质:从应试技巧到工程能力的深度转化策略

LeetCode刷题的本质:从应试技巧到工程能力的深度转化策略

1. 这篇文章真正要解决的问题如果你是一名正在准备技术面试的开发者,或者是一名计算机专业的学生,那么“刷LeetCode”这个词对你来说一定不陌生。它几乎是通往大厂Offer的必经之路,是无数人投入数百小时甚至上千小时去重复练习的“标准动作”…

2026/10/11 8:33:18 阅读更多 →

最新新闻

稳定细胞系构建与高表达克隆筛选:从瞬时转染到稳定株的完整指南

稳定细胞系构建与高表达克隆筛选:从瞬时转染到稳定株的完整指南

上个月接了一个蛋白药物早期研发的需求。对方上来就问:稳定细胞系构建怎么收费,能不能顺便帮筛几个高表达克隆。多聊了几句我才搞清楚,他们刚用瞬时转染跑完一轮预实验,分泌量看着不错,团队内部已经把预算和排期都排到…

2026/10/14 10:11:49 阅读更多 →
PTA C++编程题解题攻略:常见题型与踩坑经验总结

PTA C++编程题解题攻略:常见题型与踩坑经验总结

1. 拿到PTA编程题,先别急着敲代码这些年我在某高校带过好几轮C上机课,也帮着学弟学妹们辅导过不少PTA的作业题,发现大多数人卡住的原因其实不是代码能力不够,而是打心底里没把“编程题”当成一道需要审题、拆解的工程题来做。大一…

2026/10/14 10:11:49 阅读更多 →
自托管PS5游戏库与硬件维护:一个极简Web面板的设计实践

自托管PS5游戏库与硬件维护:一个极简Web面板的设计实践

任何一台PS5,玩久了都会攒出一堆散乱的数字资产:买过的游戏、还没补的DLC、借给朋友的光盘、上次清灰的时间、某个账号里卡在80%的奖杯列表。身边不少人用Excel或者手机备忘录在记,但一旦跨设备、跨主机、跨朋友借还,很快就乱成一…

2026/10/14 10:11:49 阅读更多 →
LiteLLM实战:统一大模型API接入与代理网关部署指南

LiteLLM实战:统一大模型API接入与代理网关部署指南

如果你手上同时要接好几家大模型的 API,估计你早就被“每家一套请求格式、鉴权方式、限流策略”磨到没脾气。litellm就是干这个的:一个 Python 库,也是一个可以独立部署的代理网关,把各家大模型接口统一成一套调用方式&#xff0c…

2026/10/14 10:11:49 阅读更多 →
Excel SUMIFS函数详解:多条件求和高阶技巧

Excel SUMIFS函数详解:多条件求和高阶技巧

1. 为什么需要SUMIFS函数? 刚接触Excel那会儿,我经常被各种销售报表折磨得焦头烂额。记得有次老板让我统计"华东地区手机品类在Q2的销售额",我硬是用了三个辅助列才勉强算出来。直到后来发现了SUMIFS这个神器,才发现原来…

2026/10/14 10:11:49 阅读更多 →
Django+Flask智能营销系统:银行数字化转型实战

Django+Flask智能营销系统:银行数字化转型实战

1. 项目背景与核心价值在金融数字化转型浪潮中,银行业务营销正从传统人工经验驱动转向数据智能驱动。这个基于DjangoFlask的智能营销系统,正是利用爬虫技术获取多维金融数据,通过大数据分析生成客户画像,最终以可视化大屏呈现营销…

2026/10/14 10:10:46 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →