C++聊天集群服务器1

​ 先给出整个项目的结构图:
image-20231126122841767

一、环境搭建

​ 施磊的c++聊天项目。相信已经到了这部分内容就已经能够自行搭建环境了,这里主要给出搭建的具体内容,方法自行百度。下面给出环境要求。

​ 1.json-cpp

​ 2.muduo库

​ 3.cmake

​ 4.mysql

二、CMake编写

​ 主目录下的cmake

cmake_minimum_required(VERSION 3.0)
project(chat)


#配置编译选项
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -g)

#配置最终的可执行文件输出的路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

#配置头文件搜索路径
include_directories(${PROJECT_SOURCE_DIR}/include)
include_directories(${PROJECT_SOURCE_DIR}/include/server)
include_directories(${PROJECT_SOURCE_DIR}/thirdparty)
include_directories(${PROJECT_SOURCE_DIR}/include/server/db)
#加载子目录
add_subdirectory(src)

​ src下的:

add_subdirectory(server)

​ server目录下:

#定义一个SRC_LIST,包含了该目录下的所有源文件
aux_source_directory(. SRC_LIST)
aux_source_directory(./db DB_LIST)

#指定生成可执行文件
add_executable(ChatServer ${SRC_LIST} ${DB_LIST})

#指定需要的连接时依赖库文件
target_link_libraries(ChatServer muduo_net muduo_base mysqlclient pthread)

三、网络模块

​ 网络模块主要负责处理客户端的请求数据,主要用到了陈硕大佬的muduo库,创建了一个服务器对象,并且把相应的事件注册在epoll的树上,代码及注释如下:

#ifndef  CHATSERVER_H
#define CHATSERVER_H

#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
using namespace muduo;
using namespace muduo::net;

//聊天服务器的主类
class ChatServer
{
    public:
    //初始化聊天服务器对象
    ChatServer(EventLoop* loop,
            const InetAddress& listenAddr,
            const string& nameArg);
    //启动服务
    void start();

    private:
    
    //上报连接相关的回调函数
    void onConnection(const TcpConnectionPtr&);
    //上报读写事件相关的回调函数
    void onMessage(const TcpConnectionPtr&,
                            Buffer*,
                            Timestamp);

    TcpServer _server;   //服务器类对象
    EventLoop *_loop;    //事件循环
};

#endif

​ chatserver.cpp:

#include "chatserver.hpp"
#include "json.hpp"

#include "chatservice.hpp"

// 函数对象绑定器
#include <functional>
#include <string>

using namespace std;
// 参数占位符
using namespace placeholders;
//json库
using json = nlohmann::json;


// 初始化聊天服务器
ChatServer::ChatServer(EventLoop *loop,
                       const InetAddress &listenAddr,
                       const string &nameArg)
    : _server(loop, listenAddr, nameArg), _loop(loop)
{
    // 注册回调连接
    _server.setConnectionCallback(bind(&ChatServer::onConnection, this, _1));

    // 注册消息回调
    _server.setMessageCallback(bind(&ChatServer::onMessage, this, _1, _2, _3));

    // 设置线程数量
    //一个I/O主Reactor线程3个逻辑工作线程
    _server.setThreadNum(4);
}

// 启动服务
void ChatServer::start()
{
    _server.start();
}

// 上报连接相关的回调函数
void ChatServer::onConnection(const TcpConnectionPtr &conn)
{

    //客户端断开连接
    if(!conn->connected())
    {
        conn->shutdown();
    }

}
// 上报读写事件相关的回调函数
void ChatServer::onMessage(const TcpConnectionPtr &conn,
                           Buffer *buffer,
                           Timestamp time)
{
    //接收json
    string buf = buffer->retrieveAllAsString();
    //数据的反序列化
    json js = json::parse(buf);
    //通过js["msgid"] 获取-》业务处理handler-》conn   js    time
    //达到的目的:完全解耦网络模块的代码和业务模块的代码
    auto msgHandler = ChatService::instance()->getHandler(js["msgid"].get<int>());
    //回调消息绑定好的事件处理器,执行业务执行。
    msgHandler(conn,js,time);
}

四、业务模块

​ 这部分处理客户端的业务逻辑

#ifndef CHATSERVICE_H
#define CHATSERVICE_H

#include <unordered_map>
#include <functional>
#include <muduo/net/TcpConnection.h>

#include "json.hpp"
using json = nlohmann::json;

//using c++11语法
using namespace std;   
using namespace muduo::net;
using namespace muduo;

//表示处理消息的事件回调类型
using MsgHandler = std::function<void(const TcpConnectionPtr &conn,json &js,Timestamp)>;

// 聊天服务器业务类
class ChatService
{
public:
    //获取单例对象的接口函数
    static ChatService* instance();

    //处理登录业务
    void login(const TcpConnectionPtr &conn,json &js,Timestamp time);
    //处理注册业务
    void reg(const TcpConnectionPtr &conn,json &js,Timestamp time);
    //获取消息对应的处理器
    MsgHandler getHandler(int msgid);
private:
    //单例模式构造函数私有化
    ChatService();

    //存储消息id和其对应的事件处理方法
    unordered_map<int,MsgHandler> _msgHandlerMap;
};

#endif

​ chatservice.cpp:

#include "chatservice.hpp"
#include "public.hpp"
#include <muduo/base/Logging.h>

using namespace muduo;

ChatService *ChatService::instance()
{
    static ChatService 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)});
}

// 处理登录业务
void ChatService::login(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    LOG_INFO << "login ok!";
}
// 处理注册业务
void ChatService::reg(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    LOG_INFO << "reg ok!";
}

// 获取消息对应的处理器
MsgHandler ChatService::getHandler(int msgid)
{
    //记录错误日志,msgid没有对应的事件处理回调
    auto it = _msgHandlerMap.find(msgid);
    if(it == _msgHandlerMap.end())
    {
        //返回一个默认的处理器,空操作
        //LOG_ERROR << "msgid:" << msgid << "can not find handler!";
        return [=](const TcpConnectionPtr &conn,json &js,Timestamp)
        {
            LOG_ERROR << "msgid:" << msgid << "can not find handler!";
        };
    }
    else
    {
        return _msgHandlerMap[msgid];   
    }
}

五、公共模块

​ 目前就只有消息枚举

image-20231126123423982

​ 过两天继续跟进。

posted @   桂洛克船长  阅读(105)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示