【从零实现JsonRpc框架#2】Muduo库介绍

1.基本概念

Muduo 由陈硕大佬开发,是一个基于非阻塞IO事件驱动 的C++高并发TCP网络编程库 。它是一款基于主从Reactor 模型的网络库,其使用的线程模型是 one loop per thread

1.1 主从 Reactor 模型

  • 主 ReactorMainReactor,通常由 EventLoop 实现):
    • 负责监听新连接(accept 事件),通过 Acceptor 类实现。
    • 使用 epoll/poll 等多路复用机制监控监听套接字。
  • 从 ReactorSubReactor,多个 EventLoop 线程):
    • 每个 EventLoop 管理一组已建立的 TCP 连接(TcpConnection)。
    • 处理连接的读写事件、定时任务和用户回调。

1.2 One Loop Per Thread

  • 线程绑定 :每个 EventLoop 对象严格绑定到一个线程(通过 EventLoop::loop() 在所属线程运行)。
  • 资源隔离 :TCP 连接的生命周期由所属 EventLoop 管理,避免跨线程竞争。
  • 性能优化 :通过线程局部存储(ThreadLocal)实现高效的事件循环访问。

2.常见接口

2.1TcpServer 类基础介绍

Kotlin 复制代码
typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;
typedef std::function<void (const TcpConnectionPtr&)> ConnectionCallback;
typedef std::function<void (const TcpConnectionPtr&, Buffer*, Timestamp)> MessageCallback;

class InetAddress : public muduo::copyable
{
public:
 	InetAddress(StringArg ip, uint16_t port, bool ipv6 = false);
};

class TcpServer : noncopyable
{
public:
    enum Option
    {
        kNoReusePort,
        kReusePort,
    };
    TcpServer(EventLoop* loop, const InetAddress& listenAddr, const string& nameArg, Option option = kNoReusePort);

    void setThreadNum(int numThreads);
    void start();
    
    // 当⼀个新连接建⽴成功的时候被调用 
    void setConnectionCallback(const ConnectionCallback& cb)
    { connectionCallback_ = cb; }
    
    // 消息的业务处理回调函数---这是收到新连接消息的时候被调用的函数 
    void setMessageCallback(const MessageCallback& cb)
    { messageCallback_ = cb; }
};
  • 职责:服务端入口,管理监听套接字和连接池。

  • 关键流程

    1. 构造时绑定 EventLoop(主 Reactor)。
    2. start() 启动监听,注册 Acceptor 到主 Reactor。
    3. 新连接到达时,通过轮询算法分配从 Reactor 管理。
  • TcpServer(EventLoop* loop, const InetAddress& listenAddr, const string& nameArg) :构造函数,loop 是事件循环对象,listenAddr 是监听地址,nameArg 是服务器名称。
  • void setThreadNum(int numThreads):设置服务器的工作线程数。默认为 1,即单线程模式。
  • void start():启动服务器,开始监听端口。
  • void setConnectionCallback(const ConnectionCallback& cb):设置连接回调函数,当有新连接或连接断开时调用。
  • void setMessageCallback(const MessageCallback& cb):设置消息回调函数,当有数据到达时调用。
  • void setWriteCompleteCallback(const WriteCompleteCallback& cb):设置写完成回调函数,当所有数据写入完成后调用。
Kotlin 复制代码
void setConnectionCallback(ConnectionCallback cb); // 连接建立/关闭回调
void setMessageCallback(MessageCallback cb);       // 消息到达回调

示例代码:

Kotlin 复制代码
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <iostream>

void onConnection(const muduo::net::TcpConnectionPtr& conn) {
    if (conn->connected()) {
        std::cout << "New connection: " << conn->name() << std::endl;
    } else {
        std::cout << "Connection closed: " << conn->name() << std::endl;
    }
}

void onMessage(const muduo::net::TcpConnectionPtr& conn, muduo::net::Buffer* buf, muduo::Timestamp receiveTime) {
    std::string msg(buf->retrieveAllAsString());
    std::cout << "Received message: " << msg << std::endl;
    conn->send(msg);  // 回显消息
}

int main() {
    muduo::net::EventLoop loop;
    muduo::net::InetAddress listenAddr(8080);
    muduo::net::TcpServer server(&loop, listenAddr, "EchoServer");

    server.setConnectionCallback(onConnection);
    server.setMessageCallback(onMessage);

    server.setThreadNum(4);  // 使用 4 个工作线程
    server.start();

    loop.loop();
    return 0;
}

2.2EventLoop 类基础介绍

EventLoop 是 Muduo 库的核心类之一,负责事件循环(event loop)。每个线程只能有一个 EventLoop 实例,它负责监听和分发事件(如 I/O 事件、定时器事件等)。

常用接口:

  • void loop():启动事件循环,进入事件监听状态。
  • void quit():退出事件循环。
  • void runInLoop(const Functor& cb) :在当前 EventLoop 线程中执行回调函数 cb。如果调用者不在该线程中,则将回调函数加入队列,稍后执行。
  • void queueInLoop(const Functor& cb) :将回调函数 cb 加入队列,稍后在 EventLoop 线程中执行。
  • TimerId runAt(const Timestamp& time, const TimerCallback& cb) :在指定的时间点 time 执行回调函数 cb
  • TimerId runAfter(double delay, const TimerCallback& cb) :在指定的延迟时间 delay 后执行回调函数 cb
  • TimerId runEvery(double interval, const TimerCallback& cb) :每隔 interval 秒执行一次回调函数 cb

成员:

Kotlin 复制代码
std::unique_ptr<Poller> poller_;   // 底层 IO 多路复用(epoll/poll)
std::vector<Functor> pendingFunctors_; // 跨线程任务队列

核心方法

Kotlin 复制代码
void loop();          // 启动事件循环(必须在本线程调用)
void quit();		 // 停止循环
void runInLoop(Functor cb); // 跨线程安全的任务提交
TimerId runAfter(double delay, TimerCallback cb); // 定时器

代码示例:

Kotlin 复制代码
#include <muduo/net/EventLoop.h>
#include <iostream>

void print() {
    std::cout << "Hello, EventLoop!" << std::endl;
}

int main() {
    muduo::net::EventLoop loop;
    loop.runAfter(1.0, print);  // 1秒后执行 print 函数
    loop.loop();  // 启动事件循环
    return 0;
}

2.3TcpConnection 基础介绍

TcpConnection 表示一个 TCP 连接。它是 TcpServer 的内部类,用于管理客户端与服务器之间的连接。每个连接都有一个唯一的 TcpConnection 对象。

  • void send(const void* data, int len):发送数据到客户端。
  • void send(const StringPiece& message):发送字符串数据到客户端。
  • void shutdown():关闭连接(半关闭,停止发送数据,但仍然可以接收数据)。
  • void forceClose():强制关闭连接。
  • bool connected() const:判断连接是否处于连接状态。
  • std::string name() const:返回连接的名称(唯一标识符)。
  • EventLoop* getLoop() const :返回该连接所属的 EventLoop

特性:

  • 继承 std::enable_shared_from_this,依赖智能指针管理生命周期。
  • 通过 Channel 类注册到所属 EventLoopPoller
Kotlin 复制代码
void send(const void* data, size_t len);  // 线程安全的发送接口
void shutdown();                          // 半关闭连接(写端)
bool connected();						  // 判断当前连接是否正常

示例代码:

Kotlin 复制代码
void onMessage(const muduo::net::TcpConnectionPtr& conn, muduo::net::Buffer* buf, muduo::Timestamp receiveTime) {
    std::string msg(buf->retrieveAllAsString());
    std::cout << "Received message: " << msg << std::endl;
    if (msg == "quit\n") {
        conn->shutdown();  // 如果收到 "quit",关闭连接
    } else {
        conn->send(msg);  // 回显消息
    }
}

2.4TcpClient 类基础介绍

TcpClient 用于创建 TCP 客户端。它可以连接到远程服务器并与之通信。

常用接口

  • TcpClient(EventLoop* loop, const InetAddress& serverAddr, const string& nameArg) :构造函数,loop 是事件循环对象,serverAddr 是服务器地址,nameArg 是客户端名称。
  • void connect():发起连接请求。
  • void disconnect():断开连接。
  • void setConnectionCallback(const ConnectionCallback& cb):设置连接回调函数。
  • void setMessageCallback(const MessageCallback& cb):设置消息回调函数。

同步控制:

  • 使用 CountDownLatch 等待连接建立完成后再发送数据:
Kotlin 复制代码
CountDownLatch latch(1);
client.setConnectionCallback([&](const TcpConnectionPtr& conn) {
    if (conn->connected()) latch.countDown();
});
client.connect();
latch.wait();  // 等待连接成功

示例代码:

Kotlin 复制代码
#include <muduo/net/TcpClient.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <iostream>

void onConnection(const muduo::net::TcpConnectionPtr& conn) {
    if (conn->connected()) {
        std::cout << "Connected to server." << std::endl;
        conn->send("Hello, server!\n");
    } else {
        std::cout << "Disconnected from server." << std::endl;
    }
}

void onMessage(const muduo::net::TcpConnectionPtr& conn, muduo::net::Buffer* buf, muduo::Timestamp receiveTime) {
    std::string msg(buf->retrieveAllAsString());
    std::cout << "Received from server: " << msg << std::endl;
}

int main() {
    muduo::net::EventLoop loop;
    muduo::net::InetAddress serverAddr("127.0.0.1", 8080);
    muduo::net::TcpClient client(&loop, serverAddr, "EchoClient");

    client.setConnectionCallback(onConnection);
    client.setMessageCallback(onMessage);

    client.connect();
    loop.loop();
    return 0;
}

2.5.Buffer 类基础介绍

Buffer 是 Muduo 中用于处理网络数据缓冲区的类。它实现了动态缓冲区的功能,支持高效的读写操作。

常用接口

  • void append(const char* data, size_t len):向缓冲区追加数据。
  • size_t readableBytes() const:返回可读字节数。
  • size_t writableBytes() const:返回可写字节数。
  • const char* peek() const:返回缓冲区中可读数据的起始位置。
  • void retrieve(size_t len):从缓冲区中移除已读取的数据。
  • std::string retrieveAllAsString():将缓冲区中的所有数据取出并转换为字符串。
  • void prepend(const void* data, size_t len):在缓冲区前面插入数据。

示例代码:

Kotlin 复制代码
void onMessage(const muduo::net::TcpConnectionPtr& conn, muduo::net::Buffer* buf, muduo::Timestamp receiveTime) {
    while (buf->readableBytes() >= sizeof(int)) {
        const char* data = buf->peek();
        int be32 = *reinterpret_cast<const int*>(data);
        int host32 = muduo::net::sockets::networkToHost32(be32);  // 转换为本地字节序
        buf->retrieve(sizeof(int));
        std::cout << "Received integer: " << host32 << std::endl;
    }
}

3.总结

  • EventLoop:负责事件循环,监听 I/O 事件和定时器事件。
  • TcpServer:用于创建 TCP 服务器,监听客户端连接。
  • TcpConnection:表示一个 TCP 连接,负责管理客户端与服务器之间的通信。
  • TcpClient:用于创建 TCP 客户端,连接到远程服务器。
  • Buffer:用于处理网络数据缓冲区,支持高效的读写操作。

这些类是 Muduo 库的核心组件,通过它们可以轻松构建高性能的 TCP 网络应用

相关推荐
sdm07042720 分钟前
yum和开发工具vim/gcc
linux·服务器·centos
zhaoyufei13321 分钟前
RK3568-11.0 设置WiFi p2p静态IP
服务器·tcp/ip·p2p
Leinwin6 小时前
OpenClaw 多 Agent 协作框架的并发限制与企业化规避方案痛点直击
java·运维·数据库
2401_865382506 小时前
信息化项目运维与运营的区别
运维·运营·信息化项目·政务信息化
漠北的哈士奇6 小时前
VMware Workstation导入ova文件时出现闪退但是没有报错信息
运维·vmware·虚拟机·闪退·ova
如意.7596 小时前
【Linux开发工具实战】Git、GDB与CGDB从入门到精通
linux·运维·git
运维小欣6 小时前
智能体选型实战指南
运维·人工智能
yy55276 小时前
Nginx 性能优化与监控
运维·nginx·性能优化
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ7 小时前
Linux 查询某进程文件所在路径 命令
linux·运维·服务器
05大叔9 小时前
网络基础知识 域名,JSON格式,AI基础
运维·服务器·网络