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

Muduo网络库大总结

Muduo网络库大总结

目录

  • 目的
  • 知识储备
  • IO模型
    • 阻塞与非阻塞
    • 五种IO模型
  • epoll原理
    • select/poll的缺点
    • epoll的优势
    • LT与ET模式
  • Reactor模型
  • muduo核心模块
  • 扩展功能

目的

  1. 理解阻塞、非阻塞、同步、异步的概念
  2. 掌握Unix/Linux五种IO模型
  3. 深入理解epoll原理及优势
  4. 掌握Reactor模型设计
  5. 学习C++网络库的代码设计范式
  6. 实现基于事件驱动和线程池的面向对象编程
  7. 通过重构muduo库,用C++11替代Boost依赖

知识储备

关键点说明
TCP/UDP协议理解传输层协议特性
IO复用编程掌握select/poll/epoll接口的使用
多线程编程熟悉pthread、C++20协程等并发模型
推荐书籍《Linux高性能服务器编程》《UNIX环境高级编程》《鸟哥的Linux私房菜》

IO模型

阻塞与非阻塞

阶段行为描述
数据准备阻塞:线程挂起等待数据
非阻塞:立即返回状态(EAGAIN)
数据读写同步:用户线程自行读写
异步:内核完成读写后通过回调/信号通知用户线程

陈硕观点:阻塞/非阻塞均为同步IO,只有使用特定API(如aio_read)才是异步IO。

五种IO模型

  1. 阻塞IO

    • 进程全程阻塞,直到数据完成内核到用户空间的拷贝
  2. 非阻塞IO

    while (recv(fd, buf, size, 0) == EAGAIN); // 轮询直到数据就绪
  3. IO复用

    • 通过select/poll/epoll监听多个fd,核心流程:

      应用阻塞于epoll_wait -> 就绪事件触发 -> 同步处理数据
      
  4. 信号驱动

    • 注册SIGIO信号处理函数,数据就绪时通过信号通知应用层
    • 内核异步通知,数据读写仍需同步完成
  5. 异步IO

    struct aiocb {int aio_fildes;        // 文件描述符void *aio_buf;         // 缓冲区指针// ...其他字段
    };
    aio_read(&aiocb);          // 内核完成数据准备和拷贝后通知应用
    

epoll原理

select/poll的缺点

问题描述
FD数量限制select默认支持1024个fd
内存拷贝开销每次调用需复制fd集合到内核
遍历时间复杂度O(n)轮询所有fd
触发方式仅支持水平触发(LT)

epoll的优势

  1. 高效数据结构
    • 使用红黑树存储监控的fd,插入/删除时间复杂度为O(log n)
    • 就绪事件通过双向链表返回,无需遍历所有fd
  2. 内核-用户共享
    • 通过epoll_create创建上下文,避免重复拷贝fd集合
  3. 触发模式支持
    • LT模式:数据未读完持续通知
    • ET模式:仅通知一次(需一次read处理完)

LT与ET模式对比

特性LT模式ET模式
数据完整性保证数据完全处理可能需多次调用read
系统调用次数较多(每次处理部分数据)较少(一次处理全部数据)
公平性更好(均衡处理所有连接)可能饿死小数据量连接
跨平台支持仅Linux支持

muduo选择LT的原因:避免数据丢失、简化编程模型、更好的跨平台兼容性。


Reactor模型

核心组件

组件功能描述
Event封装文件描述符和关注的事件(读/写/错误)
Reactor事件循环调度中心,调用epoll_wait监听事件
Demultiplex事件分发器(如EPollPoller
EventHandler事件处理器(如Channel中的回调函数)

muduo的多Reactor架构

MainReactor(单线程)└─ 监听新连接(Acceptor)
SubReactors(线程池)└─ 处理已建立连接的IO事件
  • 优势
    • 主从线程分工明确,避免单线程瓶颈
    • 每个SubReactor绑定独立线程,实现负载均衡

muduo核心模块

模块功能描述
Channel封装fd与事件回调(读/写/关闭)
Poller基于epoll的事件监听(EPollPoller实现)
EventLoopReactor核心,驱动事件循环(loop.loop()
EventLoopThread将EventLoop与线程绑定(one loop per thread)
Buffer应用层读写缓冲区(支持自动扩容)
TcpConnection管理TCP连接生命周期(数据收发、状态转换)
TcpServer组合Acceptor和EventLoopThreadPool,提供服务器接口

扩展功能

  1. 定时器

    • 实现方案:时间轮(高效)、红黑树(精确)
  2. 协议支持

    • HTTP/RPC:基于Buffer解析协议
    • DNS:集成第三方库(如c-ares)
  3. 性能优化

    • 调整TCP参数(SO_REUSEPORTTCP_NODELAY
    • 使用wrk/Jmeter进行压测
  4. 代码重构

    • std::shared_ptr替代Boost智能指针

    • 基于C++11特性简化异步逻辑



muduo库核心模块交互关系图示

Acceptor
TcpConnection
EventLoop
EventLoopThread
EventLoopThreadPool
TcpServer
1. 启动监听
2. 新连接到来
3. 分配连接
4. 选择EventLoop
5. 注册Channel
6. 返回活跃事件
7. 处理回调
8. 数据读写
9. 应用处理
Channel
Socket
Channel
TcpConnection
Buffer
Socket
Poller
ChannelList
Poller
ChannelList
EventLoop1
EventLoop2
EventLoopThread1
EventLoopThread2
...
Acceptor
TcpServer
EventLoopThreadPool
E1/E2
F1/F2
I/L


muduo库核心模块解析

1. TcpServer

  • 核心职责:整个服务器的核心类,负责管理监听端口和处理新连接
  • 子模块
    • Acceptor:负责监听新连接并接受新连接
    • EventLoopThreadPool:管理多个线程,每个线程运行一个 EventLoop

2. EventLoopThreadPool

  • 核心职责:管理多个事件循环线程池
  • 子模块
    • EventLoopThread:每个线程包含一个 EventLoop,负责处理分配给它的事件

3. EventLoopThread

  • 核心职责:将事件循环与线程绑定
  • 子模块
    • EventLoop:每个线程运行一个 EventLoop,负责处理事件循环

4. EventLoop

  • 核心职责:驱动事件循环的核心单元
  • 子模块
    • Poller:负责监听和分发事件(如 epoll 实现)
    • ChannelList:存储所有注册的 Channel 对象

5. TcpConnection

  • 核心职责:管理单个TCP连接的生命周期
  • 子模块
    • Channel:封装了 Socket 的事件处理逻辑(如读写回调)
    • Buffer:用于存储读取和发送的数据(应用层缓冲区)
    • Socket:封装了底层的套接字操作(如 bind/listen

6. Acceptor

  • 核心职责:专门处理新连接建立
  • 子模块
    • Channel:封装监听套接字(listenfd)的事件处理逻辑
    • Socket:封装底层的监听套接字操作(如 accept


muduo库服务端启动与事件处理流程

  1. 启动监听
    • 「TcpServer」调用「Acceptor」的方法启动监听端口。

  2. 新连接到来
    • 「Acceptor」通过监听套接字(listenfd)接收到新连接后,通知「TcpServer」。

  3. 分配连接
    • 「TcpServer」将新连接分配给「EventLoopThreadPool」(事件循环线程池)。

  4. 选择 EventLoop
    • 「EventLoopThreadPool」通过轮询算法选择一个「EventLoop」来处理该连接的后续事件。

  5. 注册 Channel
    • 被选中的「EventLoop」将新连接对应的「Channel」注册到其管理的「Poller」中。

  6. 返回活跃事件
    • 「Poller」通过epoll_wait检测到活跃事件后,将就绪的「Channel」列表返回给「EventLoop」。

  7. 处理回调
    • 「EventLoop」遍历活跃的「Channel」,调用其绑定的读/写/关闭事件回调函数。

  8. 数据读写
    • 「Channel」的回调函数通过「Buffer」进行数据读写操作:

    • 读操作:从内核接收缓冲区拷贝数据到应用层「Buffer
    • 写操作:将「Buffer」中的数据写入内核发送缓冲区
  9. 应用处理
    • 读取的数据通过「TcpConnection」传递给上层应用逻辑(如HTTP解析、业务计算等)。



关键设计特点

  1. 主从Reactor模式
    • Main Reactor(主EventLoop):仅处理新连接建立(Acceptor
    • Sub Reactors(子EventLoop池):处理已建立连接的I/O事件
  2. 线程模型
    • one loop per thread:每个EventLoop绑定到一个独立线程
    • 通过 EventLoopThreadPool 实现负载均衡
  3. 资源管理
    • TcpConnection 生命周期由 shared_ptr 管理
    • Channel 在所属EventLoop线程内操作,避免竞态条件
  4. 高效事件分发
    • Poller 使用epoll的LT模式,确保数据完整性
    • 活跃事件通过 ChannelList 直接传递,减少中间拷贝

模块职责表

模块核心职责依赖关系
TcpServer组合管理Acceptor和线程池Acceptor, EventLoopPool
Acceptor监听新连接并创建TcpConnectionSocket, Channel
EventLoopThread将EventLoop与线程绑定EventLoop, Thread
Poller监听fd事件并返回活跃ChannelChannel
TcpConnection管理TCP连接的数据读写和状态转换Channel, Buffer, Socket
Buffer提供应用层读写缓冲区

相关文章:

  • C语言练手磨时间
  • 用算术右移实现逻辑右移及用逻辑右移实现算术右移
  • C++编程起步项目
  • golang 安装gin包、创建路由基本总结
  • 【架构美学】Java 访问者模式:解构数据与操作的双重分发哲学
  • tauri2项目使用sidcar嵌入可执行文件并使用命令行调用
  • [SpringBoot]Spring MVC(4.0)
  • elementUI 单选框存在多个互斥的选项中选择的场景
  • mongodb管理工具的使用
  • Selenium-Java版(css表达式)
  • 整理了 2009 - 2025 年的【199 管综真题 + 解析】PDF,全套共 34 份文件
  • Linux 安装 Unreal Engine
  • npm与pnpm--为什么推荐pnpm
  • DeepSeek系列大语言模型推理优化技术深度解析
  • 字符串相乘(43)
  • 程序代码篇---python向http界面发送数据
  • el-dialog鼠标在遮罩层松开会意外关闭,教程图文并茂
  • 【技海登峰】Kafka漫谈系列(十一)SpringBoot整合Kafka之消费者Consumer
  • 【自然语言处理与大模型】向量数据库:Chroma使用指南
  • 医疗信息系统安全防护体系的深度构建与理论实践融合
  • 不赚“快钱”的佳沛:蒋时杰解密新西兰国果如何在中国“慢养”出43亿生意
  • 西浦国际教育创新论坛举行,聚焦AI时代教育本质的前沿探讨
  • 南京艺术学院博导、雕塑家尹悟铭病逝,年仅45岁
  • 广西北流出现强降雨,1人被洪水冲走已无生命体征
  • 福州一宋代古墓被指沦为露天厕所,仓山区博物馆:已设置围挡
  • 澎湃与七猫联合启动百万奖金征文,赋能非虚构与现实题材创作