news 2026/4/3 3:35:10

C++:实现多路复用epoll模型实例(附带源码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++:实现多路复用epoll模型实例(附带源码)

一、项目背景详细介绍

在传统的网络编程中,最直观的服务器模型通常是:

  • 一个客户端,一个线程

  • 或者阻塞式顺序处理

这种模型在客户端数量较少时尚可接受,但一旦并发连接数上升,就会暴露出严重问题:

  • 线程数量爆炸

  • 上下文切换频繁

  • 内存消耗巨大

  • 系统吞吐能力急剧下降

为了解决高并发 I/O 场景下的性能问题,操作系统提供了I/O 多路复用机制

在 Linux 平台中,I/O 多路复用经历了三个重要阶段:

  1. select

  2. poll

  3. epoll(当前主流、高性能方案)

epoll具有以下显著优势:

  • 支持海量文件描述符

  • 事件驱动,不需要反复遍历

  • O(1) 级别的事件通知效率

  • 广泛应用于 Nginx、Redis、Muduo 等高性能网络框架

因此,掌握 epoll 模型是 C++ 后端 / 网络开发的必修技能

本项目目标是:

使用 C++ 从零实现一个基于 epoll 的多路复用服务器示例,完整展示其工作流程


二、项目需求详细介绍

2.1 功能需求

  1. 基于TCP 协议

  2. 使用epoll 模型实现 I/O 多路复用

  3. 支持多个客户端同时连接

  4. 服务端能够:

    • 接收客户端数据

    • 原样回显(Echo)

  5. 客户端断开时正确清理资源


2.2 技术要求

  • 平台:Linux

  • 使用系统原生:

    • epoll_create

    • epoll_ctl

    • epoll_wait

  • 使用非阻塞 socket

  • 单线程事件循环(Reactor 雏形)

  • 教学友好、逻辑清晰、注释详细


2.3 设计要求

  • 使用 C++ 封装流程

  • 所有代码集中在一个代码块

  • 使用注释模拟文件划分

  • 每个关键步骤有清晰中文说明


三、相关技术详细介绍

3.1 什么是 I/O 多路复用

I/O 多路复用的本质是:

一个线程同时监听多个文件描述符的 I/O 状态变化

当某个描述符就绪时,内核主动通知用户程序。


3.2 epoll 的核心思想

epoll 与 select / poll 的最大不同在于:

  • select / poll:用户态轮询

  • epoll:内核态事件通知

epoll 的工作流程:

  1. 创建 epoll 实例

  2. 向 epoll 注册关心的事件

  3. 等待事件发生

  4. 处理就绪事件


3.3 epoll 的三大核心 API

1️⃣ epoll_create

int epoll_create(int size);

  • 创建 epoll 实例

  • 返回 epoll 文件描述符


2️⃣ epoll_ctl

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

  • 向 epoll 添加 / 修改 / 删除监听的 fd


3️⃣ epoll_wait

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

  • 等待事件发生

  • 返回就绪事件数量


3.4 LT 与 ET 模式

  • LT(Level Trigger,水平触发)

    • 默认模式

    • 简单、安全

  • ET(Edge Trigger,边缘触发)

    • 性能更高

    • 编程复杂

本示例采用LT 模式,便于教学。


四、实现思路详细介绍

4.1 整体架构思路

  1. 创建监听 socket

  2. 设置 socket 为非阻塞

  3. 创建 epoll 实例

  4. 将监听 socket 加入 epoll

  5. 进入事件循环:

    • 等待事件

    • 判断事件类型

    • 分别处理监听 fd 和客户端 fd


4.2 事件处理逻辑

  • 监听 socket 就绪

    • 接收新客户端连接

    • 将新 socket 加入 epoll

  • 客户端 socket 就绪

    • 读取数据

    • 回显数据

    • 客户端断开则移除 fd


4.3 非阻塞 I/O 设计

  • 所有 socket 设置为非阻塞

  • 防止单个客户端阻塞整个事件循环

  • 符合高性能服务器设计原则


五、完整实现代码

/**************************************************** * 文件名:EpollServer.cpp * 描述:C++ epoll 多路复用模型示例(Echo Server) ****************************************************/ #include <iostream> #include <cstring> #include <unistd.h> #include <fcntl.h> #include <arpa/inet.h> #include <sys/epoll.h> using namespace std; const int PORT = 9000; const int MAX_EVENTS = 1024; const int BUFFER_SIZE = 1024; /**************************************************** * 设置文件描述符为非阻塞 ****************************************************/ int setNonBlocking(int fd) { int flags = fcntl(fd, F_GETFL, 0); return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } /**************************************************** * 主函数 ****************************************************/ int main() { // 1. 创建监听 socket int listenFd = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in serverAddr{}; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(PORT); serverAddr.sin_addr.s_addr = INADDR_ANY; bind(listenFd, (sockaddr*)&serverAddr, sizeof(serverAddr)); listen(listenFd, 5); // 设置监听 socket 非阻塞 setNonBlocking(listenFd); // 2. 创建 epoll 实例 int epollFd = epoll_create(1); // 3. 将监听 socket 加入 epoll epoll_event ev{}; ev.events = EPOLLIN; ev.data.fd = listenFd; epoll_ctl(epollFd, EPOLL_CTL_ADD, listenFd, &ev); epoll_event events[MAX_EVENTS]; cout << "epoll Echo 服务器启动,端口:" << PORT << endl; // 4. 事件循环 while (true) { int ready = epoll_wait(epollFd, events, MAX_EVENTS, -1); for (int i = 0; i < ready; ++i) { int fd = events[i].data.fd; // 监听 socket 事件 if (fd == listenFd) { sockaddr_in clientAddr{}; socklen_t len = sizeof(clientAddr); int clientFd = accept(listenFd, (sockaddr*)&clientAddr, &len); setNonBlocking(clientFd); epoll_event clientEv{}; clientEv.events = EPOLLIN; clientEv.data.fd = clientFd; epoll_ctl(epollFd, EPOLL_CTL_ADD, clientFd, &clientEv); cout << "新客户端连接:" << clientFd << endl; } // 客户端 socket 事件 else { char buffer[BUFFER_SIZE]; memset(buffer, 0, BUFFER_SIZE); int bytes = recv(fd, buffer, BUFFER_SIZE, 0); if (bytes <= 0) { cout << "客户端断开:" << fd << endl; epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, nullptr); close(fd); } else { cout << "收到数据:" << buffer << endl; // Echo 回显 send(fd, buffer, bytes, 0); } } } } close(listenFd); close(epollFd); return 0; }

六、代码详细解读(仅解读方法作用)

  • setNonBlocking:将 socket 设置为非阻塞模式

  • epoll_create:创建 epoll 实例

  • epoll_ctl:向 epoll 注册 / 删除监听事件

  • epoll_wait:等待 I/O 事件发生

  • 主循环:典型Reactor 事件分发模型


七、项目详细总结

通过该项目,你已经系统掌握:

  • epoll 的设计思想与使用流程

  • I/O 多路复用与阻塞模型的本质差异

  • 非阻塞 socket 的必要性

  • Reactor 模型的基本雏形

  • 高并发服务器的基础结构

这是从:

网络编程入门 → 高性能服务器开发

关键分水岭项目


八、项目常见问题及解答

Q1:为什么要用非阻塞 socket?
A:防止单个客户端 I/O 阻塞整个 epoll 事件循环。

Q2:为什么 epoll 比 select 快?
A:epoll 采用事件通知机制,不做全量轮询。

Q3:ET 模式为什么复杂?
A:必须一次性读空缓冲区,否则可能丢事件。


九、扩展方向与性能优化

  1. 支持ET 模式

  2. 引入线程池

  3. 封装为 Reactor 类

  4. 支持 HTTP 协议

  5. 参考 Muduo 进行架构升级

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/22 15:10:14

4G 显存即可运行!免环境搭建的 AI 电商换装工具实操指南

在电商视觉内容制作场景中&#xff0c;服装展示素材的生成常面临诸多痛点&#xff1a;专业模特拍摄成本高、后期换款修图耗时久、传统工具操作门槛高且对硬件配置要求苛刻。而一款支持免环境搭建、仅需 4G 显存即可流畅运行的 AI 换装工具&#xff0c;为这类需求提供了高效解决…

作者头像 李华
网站建设 2026/3/15 13:29:16

Python-文件拷贝+文件重命名+shutil+记录

import shutil复制文件复制文件&#xff08;保留权限信息&#xff09;shutil.copy(sourceFile, targetFile)复制文件&#xff08;保留所有元数据&#xff0c;如创建时间、修改时间等&#xff09;shutil.copy2(sourceFile, targetFile)仅复制文件内容&#xff08;不保留元数据&a…

作者头像 李华
网站建设 2026/4/2 7:52:54

Rembg高阶用法:云端GPU批量处理视频去背景

Rembg高阶用法&#xff1a;云端GPU批量处理视频去背景 你有没有遇到过这样的情况&#xff1a;团队做了几十条口播视频&#xff0c;准备上线&#xff0c;结果客户说“背景太乱了&#xff0c;得换个干净的”&#xff1f;这时候你只能一条条手动抠人像、换背景&#xff0c;一整天…

作者头像 李华
网站建设 2026/3/26 12:00:25

实测MinerU镜像:450万页PDF转Markdown效果惊艳,表格公式全保留

实测MinerU镜像&#xff1a;450万页PDF转Markdown效果惊艳&#xff0c;表格公式全保留 1. 引言 在科研、工程和教育领域&#xff0c;处理大量包含复杂排版的PDF文档是日常工作中不可避免的挑战。这些文档往往包含多栏布局、数学公式、表格和图像等元素&#xff0c;传统OCR工具…

作者头像 李华
网站建设 2026/4/1 20:58:13

YOLOv8模型集成方案:云端GPU多模型投票系统

YOLOv8模型集成方案&#xff1a;云端GPU多模型投票系统 在金融风控场景中&#xff0c;证件识别是核心环节之一。无论是身份证、护照还是营业执照&#xff0c;准确、快速地检测和定位证件信息&#xff0c;直接影响到后续的身份验证、反欺诈判断等关键流程。然而&#xff0c;现实…

作者头像 李华
网站建设 2026/3/26 11:15:54

一站式语音分析利器|SenseVoice Small中文情感与事件检测应用

一站式语音分析利器&#xff5c;SenseVoice Small中文情感与事件检测应用 1. 技术背景与核心价值 1.1 多模态语音理解的技术演进 传统语音识别&#xff08;ASR&#xff09;系统主要聚焦于将声音信号转换为文本&#xff0c;但随着智能交互场景的不断深化&#xff0c;单一的文…

作者头像 李华