(一)使用muduo编写网络模块ChatServer

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

muduo介绍

我们会使用 muduo 完成网络模块的代码,在这之前我们需要了解 muduo 的基本使用。muduo 的线程模型为「one loop per thread + threadPool」模型。一个线程对应一个事件循环(EventLoop),也对应着一个 Reactor 模型。EventLoop 负责 IO 和定时器事件的分派。

其中有 mainReactorsubReactormainReactor通过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 解析数据时得到数据类型,然后直接调用对应的函数(这些回调函数最开始已经被注册过了)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值