news 2026/9/3 2:20:08

C++集群聊天服务器(4)——网络模块与业务模块

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++集群聊天服务器(4)——网络模块与业务模块

前言

首先我对之前的目录做了一些优化,按照标准开源代码的形式(这个我在C++集群聊天服务器(2)中讲解过)进行了改善:

接下来开始讲解这些文件中的代码以及他们之间的联系。

一、按模块分开来讲解

这次主要实现了这六个文件的代码:

chatserver.h + chatserver.cpp → 网络模块(负责底层网络 IO)
chatservice.h + chatservice.cpp → 业务模块(负责具体聊天业务逻辑)
public.h → 公共协议文件(server 和 client 共享的消息类型定义)
main.cpp → 程序入口(启动服务器)

核心思想:网络模块只管“收发数据”,业务模块只管“处理数据”,通过 JSON + msgid 分发机制 实现完全解耦。

接下来也会以这六个文件进行重点讲解。

1.public.h——消息协议公共约定

这个文件的作用主要是:

  • 定义了客户端和服务端通信的消息类型枚举(EnMsgType)。
  • 当前只有两种:LOGIN_MSG = 1(登录)、REG_MSG = 2(注册)。
  • 这是一个server 和 client 共用的头文件,确保双方对消息 ID 的理解一致。
  • 实际项目中会扩展更多类型(如一对一聊天、群聊、添加好友等)。

那我们为什么需要设计这个公共文件:
它是整个消息系统的“协议规范”,客户端发送 JSON 时必须带 “msgid” 字段,服务端据此识别业务类型。

public.h的代码非常简洁:

#ifndefPUBLIC_H#definePUBLIC_H/* server和client的公共文件 */enumEnMsgType{LOGIN_MSG=1,//登录消息REG_MSG//注册消息};#endif

2. chatserver.h + chatserver.cpp —— 网络模块

我们先分别来看看这两个文件的作用:

1.chatServer.h的作用:

  • 声明聊天服务器主类。
  • 成员:muduo 的 TcpServer 和 EventLoop*;
  • 接口:构造函数、start();
  • 回调:onConnection(连接建立/断开)、onMessage(收到消息)。

2.chatserver.cpp的作用:

  • 实现构造函数:绑定 muduo 的连接/消息回调,设置 IO 线程数;
  • start():启动 TcpServer 开始监听;
  • onConnection:当前只处理客户端断开(调用 shutdown);
  • onMessage:网络模块的核心逻辑:
    1.从 Buffer 取出原始字符串。
    2.用 nlohmann::json 解析成 JSON 对象。
    3.取出 js[“msgid”],调用 ChatService::instance()->getHandler(msgid) 获取业务处理器。
    4.执行处理器:msgHandler(conn, js, time)。

他们只负责底层 TCP 连接管理、IO 事件处理、数据初步解析(转 JSON);不关心业务,代码里没有任何 login/reg 等业务词语。

ChatServer.h代码:

#ifndefCHATSERVER_H#defineCHATSERVER_H#include<muduo/net/TcpServer.h>#include<muduo/net/EventLoop.h>usingnamespacemuduo;usingnamespacemuduo::net;//聊天服务器的主类classChatServer{public://初始聊天服务器对象ChatServer(EventLoop*loop,constInetAddress&listenAddr,conststring&nameArg);//启动服务voidstart();private://上报链接相关信息的回调函数voidonConnection(constTcpConnectionPtr&);//上报读写事件相关信息的回调函数voidonMessage(constTcpConnectionPtr&,Buffer*,Timestamp);TcpServer _server;//组合的muduo库,实现服务器功能的类对象EventLoop*_loop;//指向事件循环对象的指针};#endif

chatserver.cpp代码:

#include"chatserver.hpp"#include"json.hpp"#include"chatservice.hpp"#include<functional>#include<string>usingnamespacestd;usingnamespaceplaceholders;usingjson=nlohmann::json;ChatServer::ChatServer(EventLoop*loop,constInetAddress&listenAddr,conststring&nameArg):_server(loop,listenAddr,nameArg),_loop(loop){//注册连接回调_server.setConnectionCallback(std::bind(&ChatServer::onConnection,this,_1));//注册消息回调_server.setMessageCallback(std::bind(&ChatServer::onMessage,this,_1,_2,_3));//设置线程数量_server.setThreadNum(4);}//启动服务voidChatServer::start(){_server.start();}//上报链接相关信息的回调函数voidChatServer::onConnection(constTcpConnectionPtr&conn){//客户端断开连接if(!conn->connected()){conn->shutdown();}}//上报读写事件相关信息的回调函数voidChatServer::onMessage(constTcpConnectionPtr&conn,Buffer*buffer,Timestamp time){string buf=buffer->retrieveAllAsString();//数据的反序列化json js=json::parse(buf);//达到的目的:完全解耦网络模块的代码和业务模块的代码//通过js["msgid"]获取->业务handler->conn js timeautomsgHandler=ChatService::instance()->getHandler(js["msgid"].get<int>());//回调消息绑定好的事件处理器,来执行相应的业务处理msgHandler(conn,js,time);}

3. chatservice.h + chatservice.cpp——业务模块

我们仍然先分析内部函数的作用:

1.chatservice.h的作用:

  • 声明业务主类(单例模式)。
  • 定义 MsgHandler 类型:统一的业务回调函数签名。
  • 接口:instance() 获取单例、getHandler(int msgid) 获取处理器。
  • 示例业务:login()、reg()。
  • 成员:_msgHandlerMap(msgid → 处理函数 的 map)。

2.chatservice.cpp的作用:

  • 单例实现(静态局部变量,线程安全)。
  • 构造函数:注册业务处理器(用 std::bind 绑定 login/reg)。
  • getHandler:根据 msgid 返回对应函数;若不存在,返回空操作并打错误日志。
  • login/reg:当前只是占位(打印日志),实际项目中会查数据库、验证密码、维护用户状态等。

这两个文件只负责具体业务逻辑;通过 map 实现消息分发:msgid → 具体处理函数;所有连接共享同一个单例实例,便于管理全局状态(用户表、在线列表等)。

chatservice.h的代码:

#ifndefCHATSERVICE_H#defineCHATSERVICE_H#include<muduo/net/TcpConnection.h>#include<unordered_map>#include<functional>#include<json.hpp>usingnamespacestd;usingnamespacemuduo;usingnamespacemuduo::net;usingjson=nlohmann::json;//表示处理消息的事件回调方法类型usingMsgHandler=std::function<void(constTcpConnectionPtr&conn,json&js,Timestamp)>;//聊天服务器业务类classChatService{public://获取单例对象的接口函数staticChatService*instance();//处理登录业务voidlogin(constTcpConnectionPtr&conn,json&js,Timestamp time);//处理注册业务voidreg(constTcpConnectionPtr&conn,json&js,Timestamp time);//获取消息对应的处理器MsgHandlergetHandler(intmsgid);private:ChatService();//存储消息id和其对应的业务处理方法unordered_map<int,MsgHandler>_msgHandlerMap;};#endif

chatservice.cpp的代码:

#include"chatservice.hpp"#include"public.hpp"#include<muduo/base/Logging.h>usingnamespacemuduo;ChatService*ChatService::instance(){staticChatService service;return&service;}//注册消息以及对应的Handler回调操作ChatService::ChatService(){_msgHandlerMap.insert({LOGIN_MSG,std::bind(&ChatService::login,this,_1,_2,_3)});_msgHandlerMap.insert({REG_MSG,std::bind(&ChatService::reg,this,_1,_2,_3)});}//获取消息对应的处理器MsgHandlerChatService::getHandler(intmsgid){//记录错误日志,msgid没有对应的事件处理回调autoit=_msgHandlerMap.find(msgid);if(it==_msgHandlerMap.end()){//返回一个默认的处理器,空操作return[=](constTcpConnectionPtr&conn,json&js,Timestamp){LOG_ERROR<<"msgid:"<<msgid<<"can not find handler!";};}else{return_msgHandlerMap[msgid];}}//处理登录业务voidChatService::login(constTcpConnectionPtr&conn,json&js,Timestamp time){LOG_INFO<<"do login service!!!";}//处理注册业务voidChatService::reg(constTcpConnectionPtr&conn,json&js,Timestamp time){LOG_INFO<<"do reg service!!!";}

4. main.cpp——程序入口

main.cpp的作用:

  • 创建 EventLoop(muduo 事件循环);
  • 设置监听地址(127.0.0.1:6000);
  • 实例化 ChatServer 并启动;
  • 调用 loop.loop() 进入无限事件循环,处理所有 IO。

这是典型 muduo 启动模板,非常的简洁。

main.cpp的代码:

#include"chatserver.hpp"#include<iostream>usingnamespacestd;intmain(){EventLoop loop;InetAddressaddr("127.0.0.1",6000);ChatServerserver(&loop,addr,"ChatServer");server.start();loop.loop();return0;}

二、整体联系

这些文件之间到底是如何来协作的呢?
以下是一个完整的消息处理流程:

  1. 启动流程(main.cpp → chatserver → muduo):
    main 创建 EventLoop 和 ChatServer;
    ChatServer 构造函数注册 onConnection/onMessage 回调;
    start() + loop.loop() 开始监听和事件处理。

  2. 连接建立:
    客户端连接 → muduo 调用 onConnection(网络模块处理上线/下线)。

  3. 消息处理链路(核心解耦点):
    客户端发送 JSON(如 {“msgid”:1, “id”:1001, “password”:“123456”});
    然后muduo 收到数据 → 调用 ChatServer::onMessage(网络模块);
    网络模块:先解析 JSON,再通过 msgid 从ChatService单例获取 handler(调用 getHandler);
    再执行 handler → 进入业务模块(如 login);
    业务模块处理后,最后通过 conn->send(…) 发送响应 JSON 给客户端;

关键桥梁:public.h 的 msgid(协议约定);ChatService 的 handler map(分发机制);TcpConnectionPtr(muduo 提供的连接对象,用于发送响应)。

这里运用单例模式的作用是所有连接的业务处理都通过同一个 ChatService 实例,便于共享状态。

数据流向图解:

客户端 → TCP → muduo → ChatServer::onMessage → JSON解析 → ChatService::getHandler → 业务函数(login/reg) → conn->send(响应) → 客户端

三、这种实现的好处

  1. 完全解耦(最大优点):
    网络模块和业务模块零耦合:改业务不需要动网络代码,反之亦然;
    网络代码简洁,只关心 IO;业务代码专注逻辑。

  2. 高可维护性和可扩展性:
    加新业务(如群聊)只需三步:public.h 加新 msgid;ChatService 构造函数注册新 handler;实现新业务函数。
    网络模块一行不用改!

  3. 适合集群扩展:
    当前是单机,但设计已为集群铺路:
    ChatService 单例便于注入 Redis(分布式存储用户状态、消息路由);
    连接无状态:所有用户状态集中在业务层(后续放 Redis),多台服务器可共享;
    支持负载均衡(Nginx 或其他)+ Redis Pub/Sub 实现消息跨服务器广播。

  4. 高性能:
    muduo 是高性能 reactor 库,支持多线程 IO;
    JSON 解析轻量,handler map 查询 O(1)。

  5. 健壮性好:
    msgid 不存在时有默认空处理 + 日志;
    以及单例线程安全。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 23:27:22

开源代码大模型新星:IQuest-Coder-V1多场景落地实战指南

开源代码大模型新星&#xff1a;IQuest-Coder-V1多场景落地实战指南 在当前快速演进的AI编程辅助生态中&#xff0c;一款真正能理解软件工程全生命周期、具备复杂问题求解能力的代码大模型显得尤为稀缺。而近期开源的 IQuest-Coder-V1 系列模型&#xff0c;正以令人瞩目的性能…

作者头像 李华
网站建设 2026/9/2 22:48:49

用测试镜像轻松实现服务开机自启,无需复杂命令

用测试镜像轻松实现服务开机自启&#xff0c;无需复杂命令 你是否也经历过这样的场景&#xff1a;刚部署好一个服务&#xff0c;信心满满地测试完功能&#xff0c;结果一重启服务器——服务没了。翻出教程查半天&#xff0c;又是改rc.local、又是写init.d脚本、还要手动配置sy…

作者头像 李华
网站建设 2026/9/2 23:27:23

Qwen3-4B-Instruct部署教程:支持256K上下文的完整指南

Qwen3-4B-Instruct部署教程&#xff1a;支持256K上下文的完整指南 1. 模型简介&#xff1a;Qwen3-4B-Instruct-2507 是什么&#xff1f; 1.1 阿里开源的新一代文本生成模型 Qwen3-4B-Instruct-2507 是阿里云推出的一款高性能、轻量级大语言模型&#xff0c;属于通义千问系列…

作者头像 李华
网站建设 2026/9/2 22:03:12

Qwen3-1.7B离线语音助手搭建全过程

Qwen3-1.7B离线语音助手搭建全过程 你是否想过&#xff0c;不依赖网络、不上传隐私、不调用云端API&#xff0c;就能在本地电脑上运行一个真正“听懂你说话、还能开口回答”的AI语音助手&#xff1f;不是概念演示&#xff0c;不是简化Demo&#xff0c;而是能稳定工作、响应自然…

作者头像 李华
网站建设 2026/9/2 22:04:56

Qwen_Image_Cute_Animal_For_Kids省钱实战:免费镜像+按需GPU计费

Qwen_Image_Cute_Animal_For_Kids省钱实战&#xff1a;免费镜像按需GPU计费 你是不是也经常为给孩子做手工课件、绘本插图或者生日派对素材而发愁&#xff1f;找图版权贵&#xff0c;画图又没时间。现在&#xff0c;有个好消息——Qwen_Image_Cute_Animal_For_Kids 镜像来了&a…

作者头像 李华
网站建设 2026/9/2 20:43:25

Deepseek问答:从人事物方面准备年终述职

好的&#xff0c;这是一个非常棒的述职准备思路。从 人、事、物 三个维度进行系统梳理&#xff0c;能确保总结全面、结构清晰、重点突出。 以下为您列举了尽可能详细的问题清单&#xff0c;您可以根据自己的岗位职责进行选择和深化。 第一部分&#xff1a;关于“人” &#xf…

作者头像 李华