muduo介绍
我们会使用 muduo 完成网络模块的代码,在这之前我们需要了解 muduo 的基本使用。muduo 的线程模型为「one loop per thread + threadPool」模型。一个线程对应一个事件循环(EventLoop),也对应着一个 Reactor 模型。EventLoop 负责 IO 和定时器事件的分派。
其中有 mainReactor 和 subReactor。mainReactor通过Acceptor接收新连接,然后将新连接派发到subReactor上进行连接的维护。这样mainReactor可以只专注于监听新连接的到来,而从维护旧连接的业务中得到解放。同时多个Reactor可以并行运行在多核 CPU 中,增加服务效率。因此我们可以通过 muduo 快速完成网络模块。

Reactor 内部实现是 epoll/poll + 非阻塞I/O,epoll 采用 LT 模式。
注册事件发生时的回调函数
muduo 使用 TcpConnection 封装一次 TCP 连接,这也是我们用户编程会直接交互的类。而 TcpServer 用于编写网络服务器,接收客户端发起连接。我们将利用 TcpServer 这个类来构造我们的聊天服务器 ChatServer。
muduo 认为 TCP 网络编程只处理「三个半」事件
- 连接的建立:包括服务端接收新连接和客户端成功发起连接
- 连接的断开:包括主动断开(close、shutdown)和被动断开(read(2) 返回 0)
- 消息到达:文件描述符可读
- 消息发送完毕:有时候会用到,在这个项目中不必须
针对不同的事件,TcpServer 保存着不同事件发生时要调用的「回调函数」。我们就要通过向 TcpServer 注册不同的回调函数来完成我们的业务逻辑。比如:
// 连接事件相关信息的回调函数
void ChatServer::onConnection(const TcpConnectionPtr &conn)
{
// 客户端断开连接
if (!conn->connected())
{
// 处理客户端异常退出事件
ChatService::instance()->clientCloseExceptionHandler(conn);
// 半关闭
conn->shutdown();
}
}
当 ChatServer 接收到连接相关事件时,会调用我们写的ChatServer::onConnection函数。如果是客户端连接断开的事件,我们会关闭连接。
将业务模块和网络模块解耦
我们还需要处理消息到来的事件,放到项目中可能是不同类型的消息。比如,好友之间的个人聊天消息,群组之间的广播消息,登录信息和注册信息。
针对不同的信息,我们会用不同的字段来标识,而我们在 muduo 中接收到了不同的信息,肯定也会调用不同的处理函数。那么我们要这么写吗?
if (message == Login) {
LoginHandler();
} else if (message == Register) {
RegisterHandler();
} else if (...)
这显然不行,这相当于在网络模块中写上了业务模块的代码,这样显得代码逻辑混乱。网络模块就应该是正常收发数据,其他的业务逻辑写在业务模块内。
我们希望实现一个统一的调用,对于任何业务都只用调用一个方法即可,然后这个函数会有着不同的实现。
因此,我们还会创建一个 ChatService 类来专门提供不同的「服务」,ChatService使用function容易保存不同的回调函数,我们使用 Json 解析数据时得到数据类型,然后直接调用对应的函数(这些回调函数最开始已经被注册过了)。

本文介绍使用muduo库构建聊天服务器的过程,包括线程模型、事件处理机制及如何解耦网络模块与业务模块。通过注册不同回调函数实现连接管理和消息处理。
最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



