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/8/16 5:11:27 阅读更多 →
从OpenClaw到Hermes Agent:AI Agent开发框架的开发者体验演进

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

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

2026/8/16 5:11:27 阅读更多 →
LeetCode刷题的本质:从应试技巧到工程能力的深度转化策略

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

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

2026/8/16 5:11:27 阅读更多 →

最新新闻

【环境配置】Windows 配置 SSH 免密登录 Ubuntu服务器

【环境配置】Windows 配置 SSH 免密登录 Ubuntu服务器

本文记录如何在 Windows 10/11 上使用 OpenSSH,通过密钥免密登录 Ubuntu 服务器。 文中统一使用 192.0.2.10 作为服务器示例地址。该地址属于文档示例专用地址,实际操作时应替换为自己的服务器 IP。一、准备条件 开始之前,需要具备&#xff1…

2026/8/16 5:55:49 阅读更多 →
Thrust 编译时算法选择:让编译器帮你选最快的路

Thrust 编译时算法选择:让编译器帮你选最快的路

编译时算法选择&#xff1a;让编译器帮你选最快的路 代码解析 template<typename T> struct optimal_reduce_algorithm {using type typename thrust::detail::if_<thrust::detail::is_arithmetic<T>::value,cub::DeviceReduce::Sum,thrust::system::cuda::d…

2026/8/16 5:55:49 阅读更多 →
Windows鼠标异常唤醒电脑的排查与解决全攻略

Windows鼠标异常唤醒电脑的排查与解决全攻略

1. 问题现象与根源剖析你有没有遇到过这种让人抓狂的情况&#xff1f;明明在设备管理器里&#xff0c;把鼠标的“允许此设备唤醒计算机”选项给关掉了&#xff0c;心想着这下可以高枕无忧&#xff0c;让电脑安安静静地睡个觉。结果&#xff0c;刚合上盖子或者点了睡眠&#xff…

2026/8/16 5:55:49 阅读更多 →
基于Arduino与OpenCV的仿生眼球人脸跟踪系统实现

基于Arduino与OpenCV的仿生眼球人脸跟踪系统实现

这次我们来看一个基于 Arduino 的仿生眼球交互装置&#xff0c;重点是它实现了视觉人脸跟踪功能。这是一个非常适合学生、创客和硬件爱好者的 DIY 科创项目&#xff0c;它将人工智能中的计算机视觉技术&#xff0c;通过 Arduino 微控制器和舵机等硬件实体化&#xff0c;制作出一…

2026/8/16 5:55:49 阅读更多 →
Cursor AI编辑器免费额度用尽?合法续杯与第三方API接入全攻略

Cursor AI编辑器免费额度用尽?合法续杯与第三方API接入全攻略

如果你最近在关注 AI 编程工具&#xff0c;大概率听说过 Cursor。这款基于 VSCode 内核、深度集成 AI 能力的编辑器&#xff0c;凭借其“对话式编程”和“智能补全”功能&#xff0c;迅速成为开发者社区的热门话题。然而&#xff0c;一个现实问题也随之浮出水面&#xff1a;免费…

2026/8/16 5:55:49 阅读更多 →
Minecraft版本全解析:Java版与基岩版核心差异、版本号逻辑与实战选择指南

Minecraft版本全解析:Java版与基岩版核心差异、版本号逻辑与实战选择指南

1. 项目概述&#xff1a;为什么我们需要理清Minecraft的版本脉络&#xff1f;如果你是一名Minecraft玩家&#xff0c;无论是刚入坑的新手&#xff0c;还是玩了多年的老鸟&#xff0c;大概率都曾对它的版本号感到过困惑。打开启动器&#xff0c;你可能会看到“Java版”、“基岩版…

2026/8/16 5:54:49 阅读更多 →

日新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者&#xff0c;最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent&#xff0c;从本地部署到云端API&#xff0c;我们正处在一个技术栈快速重构的节点。然而&#xff0c;面对层出不穷的模型、框架和工具&#xf…

2026/8/16 0:00:54 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/16 0:00:55 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和…

2026/8/16 0:03:55 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者&#xff0c;最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent&#xff0c;从本地部署到云端API&#xff0c;我们正处在一个技术栈快速重构的节点。然而&#xff0c;面对层出不穷的模型、框架和工具&#xf…

2026/8/16 0:00:54 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/16 0:00:55 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和…

2026/8/16 0:03:55 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速&#xff1a;macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/14 13:40:53 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南&#xff1a;3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗&#xff1f;ncmdump解密工具帮你轻松解决这个困…

2026/8/14 14:06:45 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片&#xff1a;为英语学习 App 打造桌面级学习助手适用平台&#xff1a;HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0&#xff08;API 26 Beta&#xff09;新增了 AgentCard 智能体卡片能力&#xff0c;这是继 HMAF&#xff08;鸿蒙智能体框架&#x…

2026/8/15 2:35:29 阅读更多 →