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

Reactor模型和类图设计

单线程Reactor模型

 单线程 Reactor 模型的工作流程

Reactor 是一种 “事件驱动” 的设计模式,单线程版本的执行逻辑分为 4 步:

  • 步骤 1:Reactor 监控与分发事件Reactor 对象通过 select 监控所有客户端的请求事件(如 “建立连接”“数据可读”);当 select 检测到事件后,Reactor 通过 Dispatch(分发)机制,将事件交给对应的处理逻辑。

  • 步骤 2:处理 “建立连接” 事件如果是建立连接的请求事件,由 Acceptor(负责 “接受连接” 的组件)调用 Accept 处理连接请求;连接建立后,创建一个 Handler 对象,后续该连接的所有业务都由这个 Handler 处理。

  • 步骤 3:处理 “非连接” 事件如果是非连接事件(如已连接的客户端发送了数据,触发 “数据可读”),Reactor 会分发调用该连接对应的 Handler,由 Handler 响应事件(如读数据、处理业务)。

  • 步骤 4:Handler 完成业务闭环Handler 会执行 “Read(读数据)→ 业务处理(如计算、逻辑操作)→ Send(发响应)” 的完整流程,负责一个连接的全生命周期业务。

3. 优点:模型简单

所有操作都在一个线程内完成,因此没有 “多线程竞争”“进程间通信” 等复杂问题,代码逻辑容易理解和实现。

4. 缺点:性能与阻塞问题突出

  • 多核 CPU 性能浪费:单线程串行执行,无法利用多核 CPU 的并行能力,性能上限低。
  • 业务阻塞导致全局阻塞:如果某个 Handler 处理业务时阻塞(比如业务逻辑耗时久,或 Read/Send 操作本身阻塞),整个进程会卡住,其他连接的 Handler 都无法执行。
  • Acceptor 也被阻塞:更严重的是,Handler 的阻塞会导致 “新连接请求” 也无法被接受 —— 因为 Acceptor 和所有 Handler 都在同一个线程,select 也会因线程阻塞而无法监控新事件。

这些缺陷导致单线程 Reactor 模型实际使用很少,通常作为 “Reactor 模式” 的基础概念,后续会演化出 “多线程 Reactor”“主从 Reactor” 等更高效的版本。

单Reactor多线程

一、核心组件与角色

  1. Client:客户端,发起网络请求(如建立连接、发送数据)。
  2. Reactor 主线程
    • 核心能力:通过 select(IO 复用 API)监控多路客户端事件(连接请求、数据读写等),并通过 dispatch(分发)将事件交给对应组件处理。
    • 子组件:
      • Acceptor:专门处理 **“建立连接” 事件 **,调用 accept 完成 TCP 三次握手。
      • Handler:响应 **“非连接事件”(如数据可读),负责 read(读数据)和 send(发响应),但不做业务逻辑处理 **(业务逻辑交给 Worker 线程池)。
  3. Worker 线程池:由多个 Worker 线程组成,负责真正的业务逻辑处理(如数据计算、数据库操作等),与 Reactor 主线程解耦,避免主线程因业务阻塞。

二、工作流程(结合 “说明” 文字与箭头)

  1. 步骤 1:Reactor 监控并分发事件Reactor 通过 select 持续监控所有客户端的事件(连接、数据读写等);当 select 检测到事件后,Reactor 用 dispatch 机制将事件分发给对应处理逻辑。

  2. 步骤 2:处理 “建立连接” 事件若事件是 **“建立连接请求”**,则由 Acceptor 调用 accept 处理连接;连接建立后,创建对应的 Handler 对象,后续该连接的 IO 事件由这个 Handler 响应。

  3. 步骤 3:处理 “非连接” 事件若事件是 **“非连接事件”**(如已连接客户端发送数据,触发 “数据可读”),Reactor 会分发到该连接对应的 Handler 进行响应。

  4. 步骤 4:Handler 转发任务到 Worker 线程池Handler 仅负责IO 层响应:通过 read 读取客户端数据后,不直接处理业务,而是将 “数据 + 业务任务” 分发给 Worker 线程池

  5. 步骤 5:Worker 线程处理业务逻辑Worker 线程池 分配独立线程,对收到的任务执行业务逻辑计算(如解码、业务逻辑处理、编码等);处理完成后,将结果返回给对应的 Handler

  6. 步骤 6:Handler 将结果返回给 ClientHandler 收到 Worker 线程的处理结果后,通过 send 操作将响应数据返回给客户端(Client)。

三、设计意图与优势

  • 解决单线程 Reactor 的缺陷:单线程 Reactor 中,Handler 处理业务会阻塞主线程,导致 “其他连接无法响应、新连接无法建立”。多线程版本将 **“业务逻辑” 剥离到 Worker 线程池 **,让 Reactor 主线程仅负责 “事件监控、IO 操作、分发”,避免阻塞。
  • 性能与分工优化
    • Reactor 主线程专注 IO 和事件分发,效率高,可同时处理大量连接的事件。
    • 业务逻辑由线程池并行执行,充分利用多核 CPU,提升整体吞吐量。
    • 连接建立、IO 响应、业务处理职责解耦,代码模块化更清晰。

这种模型是 “单线程 Reactor” 的进化版,在高性能网络编程(如 Redis、Netty 早期设计)中被广泛借鉴,平衡了 “事件驱动的高效 IO” 与 “并行业务处理” 的需求。

主从Reactor多线程模型

一、背景:单 Reactor 多线程的瓶颈

在 “单 Reactor 多线程模型” 中,Reactor 主线程既要处理 “建立连接” 事件,又要分发所有 IO 事件。高并发场景下,Reactor 主线程会因 “事件监控 + 分发” 的压力成为性能瓶颈。

二、主从 Reactor 多线程的工作流程(方案说明)

模型将 Reactor 拆分为 MainReactor(主 Reactor) 和 SubReactor(从 Reactor),分工处理不同环节:

  1. MainReactor 监控 “建立连接” 事件MainReactor(Reactor 主线程)通过 select 只监控 **“建立连接” 的事件 **(如客户端 TCP 三次握手请求)。当检测到这类事件时,由 Acceptor 处理连接建立(执行 accept 操作)。

  2. MainReactor 分配连接给 SubReactor连接建立后,MainReactor 会把新连接分配给某一个 SubReactor(Reactor 子线程)。

  3. SubReactor 监控连接的 IO 事件SubReactor 将新连接加入自己的 “监控队列”,后续负责监听该连接上的所有 IO 事件(如数据可读、可写),并为该连接创建 Handler(处理事件的组件)。

  4. SubReactor 分发事件给 Handler当连接上有 IO 事件(如客户端发数据),SubReactor 调用该连接对应的 Handler 响应事件。

  5. Handler 转发业务给 Worker 线程池Handler 通过 Read 读取数据后,不直接处理业务,而是将 “数据 + 业务任务” 分发给 Worker 线程池

  6. Worker 线程池处理业务并返回结果Worker 线程池 分配独立线程执行业务逻辑(如计算、数据库操作),处理完成后将结果返回给 Handler

  7. Handler 返回响应给 ClientHandler 收到结果后,通过 Send 将响应发回客户端。

三、优点

  • 职责明确,数据交互简单

    • MainReactor 仅负责 “接收新连接”,然后将连接交给 SubReactor;
    • SubReactor 负责 “管理连接的 IO 事件”,再将业务交给 Worker 线程池;
    • Worker 线程池仅负责 “业务逻辑”。各组件分工单一,数据交互(连接传递、任务分发、结果返回)逻辑清晰。
  • 广泛应用于知名项目:该模型在工业界被广泛采用,例如:

    • Nginx(主从 Reactor 多进程模型,用 “进程” 替代 “线程”,核心思路一致);
    • Memcached(主从多线程模型);
    • Netty(支持主从多线程模型)。

核心设计意图

通过拆分 Reactor 为 “主 - 从” 结构,让 “新连接接入” 和 “已有连接的 IO 事件处理” 由不同 Reactor 线程负责,进一步提升高并发性能;同时保留 “Worker 线程池处理业务” 的设计,解耦 IO 与业务逻辑。

https://gitee.com/prawn-playfully/thread-pool/tree/master/Reactor  可通过这个网站查看代码

代码设计类图V1

类的说明

1. InetAddress 类

  • 职责:封装 ** 网络地址(IP + 端口)** 的操作(TCP 通信必须依赖网络地址)。
  • 核心成员与方法
    • _addr: struct sockaddr_in:存储 IPv4 地址结构体(包含 IP、端口等信息)。
    • 构造函数:支持 “端口 + IP” 或 “直接传入 sockaddr_in” 创建地址对象。
    • ip()/port():获取 IP 字符串、端口号;getInetAddressPtr():返回 sockaddr_in* 指针,供底层 socket 调用(如 bindconnect 等)。

2. Socket 类

  • 职责:管理套接字文件描述符(fd),利用 RAII 特性(资源获取即初始化)自动管理套接字生命周期(构造时创建、析构时关闭,避免资源泄漏)。
  • 核心成员与方法
    • _fd: int:套接字的文件描述符。
    • 构造函数:支持 “默认创建 socket” 或 “用已有 fd 包装”。
    • fd():获取文件描述符;shutdownWrite():主动断开写连接(内部调用 shutdown(_fd, SHUT_WR),表示后续不再发送数据,但仍可接收)。

3. SocketIO 类

  • 职责:封装套接字的 IO 操作(底层数据收发的具体实现)。
  • 核心成员与方法
    • _fd: int:关联要操作的套接字 fd。
    • readn:接收固定字节数的数据;readline:按接收数据(读取一行);sendn:发送固定字节数的数据 —— 这些方法封装了 read/write 等系统调用,处理了 “部分读写” 等细节。

4. Acceptor 类

  • 职责:作为新连接的 “接收器”,负责服务器端 “监听端口、接受 TCP 连接” 的流程。
  • 核心成员与方法
    • _addr: InetAddress:服务器要绑定的地址;_sock: Socket:用于 “监听” 的套接字。
    • 构造函数:指定端口 / IP,初始化监听配置。
    • ready():整合 “绑定(bind)、监听(listen)” 等操作,让服务器进入 “可接受连接” 状态;setReuseAddr/setReusePort:设置 “地址 / 端口复用”(避免端口占用问题);accept():接受客户端连接,返回新连接的 fd。

5. TcpConnection 类

  • 职责:代表一个已建立的 TCP 连接,提供 “接收 / 发送数据、管理连接生命周期” 的能力(支持多种收发方式,因此有函数重载)。
  • 核心成员与方法
    • _sock: Socket:管理连接的 fd;_socketIO: SocketIO:实际执行数据读写;_localAddr/_peerAddr:本地(服务器)和对端(客户端)的地址;_isShutdownWrite:标记是否已关闭写端。
    • receive():接收数据;send():发送数据(重载版本支持不同参数);shutdown():断开连接;toString():获取连接的 “元信息”(如两端 IP / 端口),用于调试。
  • 依赖与协作Acceptor 依赖 InetAddress(获取地址)和 Socket(创建监听套接字)完成 “接受连接”;TcpConnection 依赖 Socket(fd 管理)、SocketIO(IO 操作)、InetAddress(地址信息)完成 “连接收发数据”。

执行步骤

这套 TCP 网络编程类结构的执行流程,可分为服务器初始化、接受连接、数据收发、连接关闭四个核心阶段,各阶段由不同类协作完成:

一、服务器初始化阶段(InetAddress + Socket + Acceptor

  1. InetAddress 封装网络地址:创建 InetAddress 对象,指定服务器要监听的端口IP(如 InetAddress(8080, "0.0.0.0"))。它内部将端口、IP 转换为 struct sockaddr_in 结构体,并提供 ip()port() 等方法获取地址信息,getInetAddressPtr() 则返回地址结构体指针,供底层 socket 调用。

  2. Socket 与 Acceptor 初始化监听

    • Acceptor 构造时,传入 InetAddress(确定监听地址),并创建 Socket 对象(管理监听用的套接字 fd)。
    • Acceptor 调用 ready() 方法,依次执行:
      • setReuseAddr(true)/setReusePort(true):设置地址 / 端口复用(避免端口占用、快速重启服务器)。
      • bind():将 InetAddress 封装的地址,绑定到 Socket 的文件描述符(_fd)。
      • listen():将 Socket 设为监听状态,准备接受客户端连接。

二、接受客户端连接阶段(Acceptor → TcpConnection

  1. Acceptor 接受客户端连接:当客户端发起 connect 请求时,Acceptor 的 accept() 方法被触发(通常由事件循环如 epoll 检测到 “监听套接字有连接请求”)。accept() 调用系统 accept 接口,获取客户端的套接字 fdclientFd)。

  2. 创建 TcpConnection 管理连接:用 clientFd 实例化 TcpConnection 对象。TcpConnection 内部:

    • 保存 Socket(封装 clientFd,管理连接的生命周期)。
    • 初始化 SocketIO(后续数据读写的工具类)。
    • 获取并保存本地地址(服务器的 InetAddress)和对端地址(客户端的 InetAddress)。

三、数据收发阶段(TcpConnection + SocketIO

  1. 接收客户端数据:调用 TcpConnection::receive(),内部通过 SocketIO 读取数据:

    • SocketIO::readn(buf, len):读取固定长度len 字节)的数据到 buf
    • SocketIO::readline(buf, max):读取一行数据(遇到换行符为止)到 buf,最多读 max 字节(避免缓冲区溢出)。
  2. 发送数据到客户端:调用 TcpConnection::send(const string& msg),内部通过 SocketIO::sendn(buf, len) 发送数据:SocketIO::sendn(buf, len) 会将 buf 中前 len 字节的数据写入套接字,并处理 “部分写” 问题(确保数据完整发送)。

四、连接关闭阶段(TcpConnection + Socket

  1. 主动断开连接:调用 TcpConnection::shutdown(),内部触发 Socket::shutdownWrite()Socket::shutdownWrite() 调用系统 shutdown(_fd, SHUT_WR)主动关闭连接的 “写端”(表示服务器不再向客户端发数据,但仍可接收)。

  2. 资源自动释放(RAII 机制):当 TcpConnection 对象析构时,其内部的 Socket 也会析构。Socket 的析构函数会调用 close(_fd),利用 RAII(资源获取即初始化) 特性,自动关闭套接字 fd,避免资源泄漏。

辅助:调试与信息获取

  • TcpConnection::toString():用于调试,获取连接的 “五元组信息”(源 IP、源端口、目的 IP、目的端口、协议),方便排查网络问题。

这套结构通过分层封装,将 TCP 通信的底层细节(地址、套接字、IO 操作)隐藏在类中,上层只需通过简洁的接口(如 TcpConnection::send/receive)即可完成复杂通信,同时利用 RAII 保证资源安全,函数重载支持多种收发场景,提升了代码的可维护性。

类图V2

核心类的职责与协作

1. 基础工具类
  • InetAddress:封装网络地址(struct sockaddr_in),提供 IP、端口的访问方法,让上层无需直接操作底层地址结构体。
  • Noncopyable:“不可拷贝” 基类(通过私有拷贝构造 / 赋值),让 Socket 等类继承后禁止拷贝,避免套接字 fd 等资源因拷贝导致的管理混乱(如重复关闭同一 fd)。
  • Socket:继承 Noncopyable,利用 RAII(资源获取即初始化) 管理套接字 fd(构造时创建、析构时关闭),提供 shutdownWrite(主动关闭写端)等操作。
  • SocketIO:封装套接字的 IO 细节(readn 读固定字节、readline 按行读、writen 写固定字节),简化上层数据收发。
2. 服务器连接管理类
  • Acceptor:服务器 “新连接接收器”,依赖 InetAddress 和 Socket,完成 ** 绑定(bind)、监听(listen)、接受(accept)** 新连接的流程,生成客户端套接字 fd 后交给 TcpConnection 管理。
  • TcpConnection:代表一条已建立的 TCP 连接,包含连接的套接字(Socket)、IO 工具(SocketIO)、地址信息(localAddr/peerAddr),并通过 回调函数onConnection 连接建立、onMessage 收到消息、onClose 连接关闭)向业务层通知事件。使用 TcpConnectionPtrshared_ptr<TcpConnection>)管理生命周期,避免野指针。
3. 事件循环核心类
  • EventLoop:基于 epoll 的事件循环核心,管理所有需要监控的文件描述符(Acceptor 的监听 fd、各 TcpConnection 的 fd)。当事件触发时(如新连接、数据可读),调用对应处理函数(handleNewConnection 处理新连接、handleMessage 处理已有连接消息),并触发 TcpConnection 的回调,完成业务逻辑分发。内部用 _connsmap)存储活跃连接,方便管理。

二、关键设计特性

  1. RAII 保障资源安全Socket 构造时获取 fd,析构时关闭 fd,确保套接字资源不泄漏。
  2. 禁止拷贝避免混乱Noncopyable 让 Socket 等类无法被拷贝,防止多个对象竞争同一 fd 导致的错误(如重复关闭)。
  3. 智能指针管理连接生命周期TcpConnectionPtrshared_ptr)确保连接被多个组件(EventLoop、业务回调)引用时,能自动释放资源,避免野指针。
  4. 回调机制解耦业务与网络TcpConnection 和 EventLoop 通过回调函数(如 onConnection),让 “网络事件发生” 与 “业务逻辑处理” 解耦 —— 业务层只需注册回调,无需修改网络层代码。
  5. IO 多路复用提升效率EventLoop 基于 epoll 实现 “单线程监控多 fd 事件”,在高并发场景下仍能高效分发事件。

三、流程示例(新连接建立)

  1. Acceptor 初始化:绑定端口、启动监听,EventLoop 将 Acceptor 的 fd 加入 epoll 监控。
  2. 客户端发起 TCP 连接,epoll 检测到 Acceptor 的 fd 有 “新连接请求” 事件。
  3. EventLoop 调用 handleNewConnectionAcceptor 执行 accept 得到客户端 fd
  4. 创建 TcpConnection 对象(用 TcpConnectionPtr 管理),并将客户端 fd 加入 epoll 监控。
  5. 触发 TcpConnection 的 onConnection 回调,业务层执行 “连接建立后逻辑”(如记录连接、发送欢迎消息)。

总结

该框架通过面向对象封装(隐藏底层 socket 细节)、回调机制(解耦业务与网络)、C++ 资源管理特性(RAII、智能指针),实现了 “高效事件驱动 + 安全资源管理”,适合构建高性能 TCP 服务(如服务器、网关等)。

类图V3

TcpServer:服务器的「门面类」,封装 Acceptor 和 EventLoop,对外提供简洁接口(start 启动服务、stop 停止、setAllCallbacks 设置业务回调)。用户无需关心底层 Acceptor/EventLoop 细节,只需通过 TcpServer 即可快速搭建 TCP 服务。

类图V4

新增方法

1. TcpServer:服务器的 “门面封装”

它是对外的统一接口类,内部组合了 Acceptor(负责接受连接)和 EventLoop(负责事件循环)。开发者无需关注 Acceptor 如何监听、EventLoop 如何处理事件,只需通过 TcpServer 的 start()setAllCallbacks() 等方法,就能快速启动 TCP 服务并绑定业务回调,极大简化了服务器的使用复杂度

2. EventLoop 的 “多线程安全与异步任务” 能力

  • MutexLock(互斥锁):用于保护 _pendingFunctors(待执行的回调队列)。因为 runInLoop 可能被其他线程(如线程池)调用,需要通过锁保证 “回调入队” 操作的原子性,避免多线程竞争。
  • PendingFunctors(待执行回调队列)EventLoop 不仅处理网络 IO 事件,还支持异步执行任务。其他线程可通过 runInLoop 将回调放入该队列,由 EventLoop 所在的 IO 线程在合适时机(如 epoll_wait 间隙)执行,实现 “跨线程任务调度”。
  • runInLoop + wakeup 配合:若当前线程不是 EventLoop 的 IO 线程,runInLoop 会将回调入队后,通过 wakeup(通常用 eventfd 或 pipe 实现)主动唤醒 epoll_wait,让 IO 线程及时处理新加入的回调,解决 “其他线程如何通知 IO 线程执行任务” 的问题。

3. TcpConnection 的 “细化方法与线程安全逻辑”

新增 sendInLoophandleReadCallback 等方法,强调:

  • 线程内安全发送数据sendInLoop 确保 “数据发送操作” 在 EventLoop 所在的 IO 线程执行(避免多线程直接操作套接字导致竞争)。
  • 回调的具体执行handleReadCallback 等方法是对 onMessage 等业务回调的 “封装执行”,保证回调在正确的线程上下文(IO 线程)中触发。

这些新增部分,让框架支持多线程协作(如线程池处理业务,IO 线程处理网络事件),同时通过封装和锁机制,保证了多线程场景下网络操作的安全性。

执行步骤

以下是该框架从服务器启动到处理客户端请求并响应的完整执行步骤,重点突出多线程协作、异步任务调度等核心流程(结合之前未详细展开的细节):

阶段 1:服务器初始化与启动

1. TcpServer 初始化(主线程执行)

  • 开发者创建 TcpServer 对象(如 TcpServer server(8080)),TcpServer 内部完成:
    • 初始化 Acceptor:绑定端口(8080)、设置监听套接字(Socket),并配置地址复用(SO_REUSEADDR)等参数。
    • 初始化 EventLoop:创建 epoll 实例,将 Acceptor 的监听套接字 fd 加入 epoll 监控(关注 EPOLLIN 事件,即 “新连接请求”)。
    • 注册业务回调:通过 server.setAllCallback(onConnection, onMessage, onClose),将用户定义的 “连接建立 / 消息到达 / 连接关闭” 回调函数保存到 TcpServer 中,后续传递给 TcpConnection

2. 启动服务器(主线程执行)

  • 调用 server.start()TcpServer 触发 EventLoop::loop(),启动事件循环:
    • EventLoop 进入 while (_isLooping) 循环,通过 epoll_wait 阻塞监听所有被监控的 fd(此时只有 Acceptor 的监听 fd)。

阶段 2:客户端连接建立(IO 线程执行)

3. 监听新连接事件(EventLoop 线程,即 IO 线程)

  • 客户端通过 connect 发起 TCP 连接,服务器监听套接字触发 EPOLLIN 事件,epoll_wait 返回就绪事件。
  • EventLoop 遍历就绪事件,发现是 Acceptor 的 fd,调用 handleNewConnection()

4. 接受连接并创建 TcpConnection(IO 线程执行)

  • Acceptor::accept() 调用系统调用 accept,获取客户端套接字 fd(peerfd)。
  • 创建 TcpConnection 对象(通过 TcpConnectionPtr conn(new TcpConnection(peerfd, this))this 指向当前 EventLoop):
    • TcpConnection 初始化:保存客户端 fd、本地地址(服务器)、对端地址(客户端),并关联 SocketIO(用于数据收发)。
    • 绑定回调:将 TcpServer 传递的 onConnection/onMessage/onClose 回调保存到 TcpConnection 的 _onConnection/_onMessage/_onClose 成员。
  • EventLoop 将客户端 fd 加入 epoll 监控(关注 EPOLLIN 事件,即 “数据可读”),并将 conn 存入 _conns 映射表(fd -> TcpConnectionPtr)。

5. 触发 “连接建立” 回调(IO 线程执行)

  • TcpConnection::handleNewConnectionCallback() 被调用,执行 _onConnection(conn)(用户注册的业务回调,如打印 “客户端已连接”)。

阶段 3:客户端发送数据与业务处理(多线程协作)

6. 检测数据可读事件(IO 线程执行)

  • 客户端通过 send 发送数据,客户端 fd 触发 EPOLLIN 事件,epoll_wait 返回就绪事件。
  • EventLoop 遍历就绪事件,找到对应客户端 fd 的 TcpConnection(通过 _conns 映射表),调用 handleMessage(fd)

7. 读取数据并触发 “消息到达” 回调(IO 线程执行)

  • TcpConnection::handleMesssageCallback() 被调用,内部通过 SocketIO::readline 读取客户端数据(如 “hello server”)。
  • 执行 _onMessage(conn)(用户注册的回调,如 onMessage 函数):
    • 在 onMessage 中,将读取到的数据封装为任务(如 Mytask),通过 gThreadpool.addtask(...) 提交到线程池。

8. 线程池处理业务逻辑(线程池线程执行)

  • 线程池的工作线程从任务队列中取出 Mytask,执行 Mytask::process()
    • 处理业务(如拼接响应字符串 “xia hello server”)。
    • 调用 _conn->sendInLoop(response),希望将响应发送给客户端(关键:此时在非 IO 线程,不能直接操作套接字,需通过 EventLoop 异步执行)。

9. 异步发送响应(跨线程协作)

  • TcpConnection::sendInLoop(response) 调用 _loop->runInLoop(...),将 “发送数据” 的 lambda 函数([this, msg]() { this->send(msg); })提交到 EventLoop
    • runInLoop 逻辑(线程池线程执行):
      1. 加锁(MutexLock),将 lambda 加入 EventLoop 的 _pendingFunctors 队列(待执行任务队列)。
      2. 调用 EventLoop::wakeup(),通过 eventfd 唤醒阻塞的 epoll_wait
        • wakeup() 向 eventfd 写入 8 字节数据(uint64_t one = 1),触发 eventfd 的 EPOLLIN 事件。

阶段 4:IO 线程执行异步任务(IO 线程执行)

10. 唤醒 EventLoop 并处理异步任务

  • eventfd 的 EPOLLIN 事件被 epoll_wait 检测到,EventLoop 调用 handleRead() 读取 eventfd 数据(清空计数器,避免重复唤醒)。
  • 调用 doPendingFunctors() 执行队列中的任务:
    • 加锁,将 _pendingFunctors 与局部 functors 交换(减少锁持有时间,避免阻塞其他线程提交任务)。
    • 遍历 functors,执行 lambda 函数:this->send(msg)TcpConnection::send)。

11. 发送响应数据(IO 线程执行)

  • TcpConnection::send 通过 SocketIO::writen 将响应数据(“xia hello server”)写入客户端 fd,完成数据发送。

阶段 5:客户端断开连接(IO 线程执行)

12. 检测连接关闭事件

  • 客户端调用 close 断开连接,服务器端 read 会返回 0,TcpConnection::isClosed() 检测到连接关闭。
  • EventLoop::handleClose(fd) 被调用:
    • 将客户端 fd 从 epoll 监控中移除(delEpollReadFd)。
    • 从 _conns 映射表中删除 TcpConnectionshared_ptr 引用计数减为 0,自动析构)。
    • 触发 TcpConnection::handleCloseCallback(),执行 _onClose(conn)(用户注册的回调,如打印 “客户端已断开”)。

核心设计亮点的执行体现

  1. 线程安全的异步任务runInLoop 通过互斥锁保护 _pendingFunctors,确保多线程提交任务安全;wakeup 机制保证 IO 线程及时处理任务。
  2. IO 与业务解耦:IO 操作(读写)在 IO 线程执行,业务逻辑(Mytask::process)在线程池执行,避免业务阻塞 IO。
  3. 资源自动管理Socket 析构关闭 fd,TcpConnection 用 shared_ptr 自动释放,避免资源泄漏。

整个流程通过 “事件驱动” 和 “多线程协作”,既保证了 IO 效率,又支持业务并行处理,是高性能网络框架的典型实现

V5

V5是全封装

http://www.dtcms.com/a/461992.html

相关文章:

  • 包头网站建设易通null wordpress theme
  • 项目外包公司可以去吗九江市seo
  • 专题四:前缀和~
  • C++八股 —— 线程本地存储技术
  • 位运算题5:出现k次与出现1次
  • 我们为什么需要Agent?
  • MLMs之Sora:Sora 2(开启真实物理与创意融合的新一代视频生成平台)的简介、安装和使用方法、案例应用之详细攻略
  • (1)100天python从入门到拿捏
  • 昆明网站定制制作logo网站
  • 个人做哪方面的网站网站续费怎么做
  • Differential evolution with collective ensemble learning
  • 东莞网站推广策划wordpress怎么改标题和meta
  • jquery mvvm框架
  • 做外贸的几个网站如何添加网站白名单
  • 统一 IT 服务台平台:让企业服务运转更高效
  • 在线做c语言题目的网站免费自助在线公司起名
  • 70行代码展现我的“毕生”编程能力
  • C++ List
  • 从指令到智能:大型语言模型提示词工程与上下文工程的综合分析
  • wordpress清理过期文件夹电商seo
  • html网站尺寸成立公司需要哪些资料
  • 物联网边缘节点中的MEMS传感器低功耗设计实战
  • 当工业生产遇上RFID:智能追溯让制造全流程“透明可见”
  • LeetCode 刷题【109. 有序链表转换二叉搜索树】
  • 建设企业网站模板下载黑龙江省建设工程质量安全协会网站
  • VMware 安装 Ubuntu 24.04(稳定版本) 母胎教学
  • 巴城镇建设网站微信微网站制作公司
  • Linux 系统配置 NTP 服务:轻松同步阿里云时间服务器
  • 网站建设公司列表网加强网站建设工作
  • 深度学习之模型的部署、web框架 服务端及客户端案例