文章目录
- 1. 什么是 Muduo 网络库?
- 2. Muduo 的核心架构
- 2.1 EventLoop
- 2.2 Channel
- 2.3 Poller
- 2.4 TimerQueue
- 2.5 TcpServer 和 TcpConnection
- 架构图
 
- 3. Muduo 的工作原理
- 4. 部分组件介绍
- 4.1 ProtobufCodec
- 4.2 ProtobufDispatcher
- 4.3 muduo::net::EventLoop
- 4.4 muduo::net::TcpServer
- 4.5 总结
 
- 4. 快速上手:从简单服务器开始
- 4.1 创建一个简单的 Echo 服务器
- 4.2 定时器使用示例
 
- 5. Muduo 的多线程支持
- 6. muduo 库的安装
- 6.2 如何编译和安装 Muduo?
 
 
1. 什么是 Muduo 网络库?
Muduo 是一个现代化、高性能的 开源 C++ 网络库。
- 主要目标:帮助开发者快速构建高性能的网络服务器。
- 设计理念:基于事件驱动(Reactor 模式),充分利用 C++11 的特性(如智能指针、多线程)。
- 应用场景:高并发场景,如聊天服务器、Web 服务、RPC 系统、实时通信等。
Muduo 的优势包括:
- 高性能:采用多线程和 epoll 技术优化 I/O 性能。
- 易用性:屏蔽底层细节,提供简单直观的 API。
- 模块化:核心模块职责清晰,方便扩展和维护。
2. Muduo 的核心架构
Muduo 的核心是事件驱动的多线程服务器框架,它主要由以下几个模块组成:
2.1 EventLoop
- 功能:事件循环的核心,负责监听和分发 I/O 事件、定时器事件。
- 特点:每个线程有一个独立的 EventLoop,保证线程安全。
2.2 Channel
- 功能:Channel是文件描述符(fd)和EventLoop的桥梁。它负责:- 监视 fd 上的事件(读、写、关闭等)。
- 在事件发生时,调用用户提供的回调函数。
 
2.3 Poller
- 功能:Poller是EventLoop的底层组件,封装了 I/O 多路复用机制(如epoll)。
- 扩展性:支持不同操作系统的事件机制(epoll/kqueue)。
2.4 TimerQueue
- 功能:高效管理定时任务。
- 特点:基于小顶堆或时间轮的数据结构,实现高性能的定时器。
2.5 TcpServer 和 TcpConnection
- TcpServer:封装服务器端操作(监听端口、接受连接等),是构建服务器的核心组件。
- TcpConnection:代表一个客户端连接,提供接口用于数据收发和生命周期管理。
架构图

3. Muduo 的工作原理
Muduo 基于 Reactor 模式,核心是事件驱动。以下是其工作流程:
-  启动服务器: - 创建一个 EventLoop实例作为主循环。
- 创建一个 TcpServer实例,设置回调函数(连接、消息处理)。
- 调用 loop.loop()开始事件循环。
 
- 创建一个 
-  事件监听: - 主线程监听新连接。
- 每当有新连接到来,将其分配到工作线程处理。
 
-  事件分发与处理: - EventLoop监听事件,通过- Poller检测就绪的文件描述符。
- 调用 Channel的回调函数处理事件。
 
-  数据收发与连接管理: - 使用 TcpConnection提供的接口收发数据。
- 在连接断开时,自动清理资源。
 
- 使用 
4. 部分组件介绍
上面我们已经简单的介绍了muduo的核心架构,这里介绍一些其重要组件:
4.1 ProtobufCodec
ProtobufCodec 是 Muduo 库中用于处理 Protobuf 序列化和反序列化的组件,它主要负责将 Protobuf 消息与字节流之间进行转换,通常用于网络通信中通过 TCP 发送 Protobuf 编码的消息。
作用:
- 序列化和反序列化:ProtobufCodec将 Protobuf 消息转换成字节流(序列化)以及将字节流解析回 Protobuf 消息(反序列化)。
- 网络传输:它的主要功能是使 Muduo 能够在网络中发送和接收 Protobuf 格式的数据。网络数据往往以字节流的形式传输,而 Protobuf 消息是结构化的数据。ProtobufCodec实现了字节流与 Protobuf 消息之间的转换。
使用场景:
- 在使用 Muduo 进行网络通信时,可能需要将应用层的数据(如结构化的 Protobuf 消息)进行传输。这时 ProtobufCodec便用来进行编码和解码。
示例代码
class ProtobufCodec : public muduo::net::Codec {
public:
    using ProtobufMessagePtr = std::shared_ptr<google::protobuf::Message>;
    ProtobufCodec() {}
    
    // 编码:Protobuf消息 -> 字节流
    void encode(muduo::net::Buffer* buf, const ProtobufMessagePtr& message) {
        std::string data;
        message->SerializeToString(&data);
        buf->append(data);
    }
    // 解码:字节流 -> Protobuf消息
    bool decode(muduo::net::Buffer* buf, ProtobufMessagePtr* message) {
        std::string data = buf->retrieveAllAsString();
        *message = std::make_shared<MyProtoMessage>();
        return (*message)->ParseFromString(data);
    }
};
4.2 ProtobufDispatcher
ProtobufDispatcher 负责将接收到的 Protobuf 消息根据类型分发到相应的回调函数。
作用:
- 消息分发:它根据 Protobuf 消息的类型将消息分发给不同的处理器。通常,我们会为每种类型的 Protobuf 消息注册一个处理函数,当接收到对应类型的消息时,ProtobufDispatcher会调用相应的处理器函数。
- 动态路由:ProtobufDispatcher实现了一种基于消息类型的动态路由机制,使得不同类型的消息能够被正确地处理。
使用场景:
- 在需要处理多种类型 Protobuf 消息的应用中,ProtobufDispatcher可以帮助根据不同的消息类型来选择不同的处理逻辑。
示例:
class ProtobufDispatcher {
public:
    template <typename T>
    void registerHandler(const std::function<void(const T&)>& handler) {
        handlers_[typeid(T).name()] = [handler](const google::protobuf::Message& msg) {
            handler(static_cast<const T&>(msg));
        };
    }
    void dispatch(const google::protobuf::Message& msg) {
        auto it = handlers_.find(typeid(msg).name());
        if (it != handlers_.end()) {
            it->second(msg);  // 调用对应的处理器
        }
    }
private:
    std::unordered_map<std::string, std::function<void(const google::protobuf::Message&)>> handlers_;
};
4.3 muduo::net::EventLoop
EventLoop 是 Muduo 库中核心的事件处理循环,它负责处理 I/O 事件、定时事件等,并且是整个事件驱动框架的核心。每个线程通常会有一个 EventLoop 实例,负责管理该线程的事件。
作用:
- 事件循环:EventLoop主要负责在一个单独的线程中运行事件循环,监听 I/O 事件、定时器事件等。当这些事件发生时,它会调用相应的回调函数。
- 异步 I/O 操作:通过 EventLoop,Muduo 实现了非阻塞的异步 I/O 操作,可以高效地处理多个并发连接。
- 管理定时器:EventLoop可以注册定时器,定时器到期时会触发回调。
使用场景
- 作为 Muduo 库的核心组件,EventLoop用于管理网络连接、事件处理、定时任务等。
示例
void onConnection(const muduo::net::TcpConnectionPtr& conn) {
    if (conn->connected()) {
        conn->send("Hello, client!");
    }
}
int main() {
    muduo::net::EventLoop loop;
    muduo::net::TcpServer server(&loop, muduo::net::InetAddress(12345), "EchoServer");
    server.setConnectionCallback(onConnection);
    server.start();
    loop.loop();  // 启动事件循环
}
4.4 muduo::net::TcpServer
TcpServer 是 Muduo 中用于创建和管理 TCP 服务器的类。它负责接收来自客户端的连接请求,创建 TcpConnection 对象,并在连接建立后处理客户端的请求。
作用:
- 监听和接受连接:TcpServer会在指定端口上监听客户端的连接请求。
- 管理连接:每当有客户端连接到服务器时,TcpServer会创建一个TcpConnection对象,并为该连接注册回调函数。
- 设置回调函数:你可以为连接、消息接收、消息发送等事件注册回调函数,处理业务逻辑。
使用场景
- TcpServer用于构建高效的服务器程序,处理多个客户端的连接和请求。
示例
class EchoServer {
public:
    EchoServer(muduo::net::EventLoop* loop, const muduo::net::InetAddress& listenAddr)
        : server_(loop, listenAddr, "EchoServer") {
        server_.setConnectionCallback(std::bind(&EchoServer::onConnection, this, _1));
        server_.setMessageCallback(std::bind(&EchoServer::onMessage, this, _1, _2, _3));
    }
    void start() {
        server_.start();
    }
private:
    void onConnection(const muduo::net::TcpConnectionPtr& conn) {
        if (conn->connected()) {
            std::cout << "New connection: " << conn->peerAddress().toIpPort() << std::endl;
        } else {
            std::cout << "Connection closed: " << conn->peerAddress().toIpPort() << std::endl;
        }
    }
    void onMessage(const muduo::net::TcpConnectionPtr& conn, muduo::net::Buffer* buf, muduo::Timestamp time) {
        std::string msg = buf->retrieveAllAsString();
        conn->send(msg);  // Echo the message back to the client
    }
    muduo::net::TcpServer server_;
};
int main() {
    muduo::net::EventLoop loop;
    muduo::net::InetAddress listenAddr(12345);
    EchoServer server(&loop, listenAddr);
    server.start();
    loop.loop();  // 启动事件循环
}
4.5 总结
- ProtobufCodec:负责 Protobuf 消息的序列化和反序列化,通常用于网络消息的处理。
- ProtobufDispatcher:根据 Protobuf 消息的类型,将其分发给不同的回调函数进行处理。
- EventLoop:管理事件循环,处理 I/O 事件和定时事件,是 Muduo 的核心组件之一。
- TcpServer:提供 TCP 服务功能,监听端口并处理客户端连接,支持注册多种事件回调。
4. 快速上手:从简单服务器开始
4.1 创建一个简单的 Echo 服务器
下面是一个完整的 Echo 服务器代码:
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/base/Logging.h>
using namespace muduo;
using namespace muduo::net;
// 当有新连接时调用
void onConnection(const TcpConnectionPtr& conn) {
    if (conn->connected()) {
        LOG_INFO << "New connection from " << conn->peerAddress().toIpPort();
    } else {
        LOG_INFO << "Connection " << conn->name() << " closed";
    }
}
// 当收到消息时调用
void onMessage(const TcpConnectionPtr& conn, Buffer* buffer, Timestamp receiveTime) {
    string msg = buffer->retrieveAllAsString();
    LOG_INFO << "Received: " << msg;
    conn->send(msg); // Echo 回去
}
int main() {
    Logger::setLogLevel(Logger::INFO);
    EventLoop loop;  // 创建事件循环
    InetAddress listenAddr(8080);  // 监听端口
    TcpServer server(&loop, listenAddr, "EchoServer"); // 创建服务器
    server.setConnectionCallback(onConnection);  // 设置连接回调
    server.setMessageCallback(onMessage);        // 设置消息回调
    server.start();  // 启动服务器
    loop.loop();     // 开始事件循环
    return 0;
}
运行流程
- 启动程序后,服务器监听 8080端口。
- 当客户端连接时,onConnection被触发。
- 收到消息后,onMessage被触发,并将消息回显给客户端。
4.2 定时器使用示例
Muduo库 提供了简单高效的定时器功能:
#include <muduo/net/EventLoop.h>
#include <muduo/base/Logging.h>
using namespace muduo::net;
void onTimer() {
    LOG_INFO << "Timer triggered!";
}
int main() {
    EventLoop loop;  
    loop.runEvery(1.0, onTimer);  // 每秒执行一次 onTimer
    loop.loop();
    return 0;
}
5. Muduo 的多线程支持
Muduo 默认是单线程的,但通过线程池可以轻松扩展为多线程模式:
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/EventLoopThreadPool.h>
using namespace muduo;
using namespace muduo::net;
void onConnection(const TcpConnectionPtr& conn) {
    if (conn->connected()) {
        LOG_INFO << "Connected from " << conn->peerAddress().toIpPort();
    } else {
        LOG_INFO << "Disconnected.";
    }
}
void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp) {
    conn->send(buf->retrieveAllAsString());
}
int main() {
    EventLoop loop;
    InetAddress listenAddr(8080);
    TcpServer server(&loop, listenAddr, "MultiThreadedServer");
    server.setThreadNum(4);  // 设置 4 个工作线程
    server.setConnectionCallback(onConnection);
    server.setMessageCallback(onMessage);
    server.start();
    loop.loop();
    return 0;
}
6. muduo 库的安装
6.2 如何编译和安装 Muduo?
- 下载源码:git clone https://github.com/chenshuo/muduo.git
- 编译安装:cd muduo mkdir build && cd build cmake .. && make && sudo make install



















