先给出整个项目的结构图:
一、环境搭建
施磊的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];
}
}
五、公共模块
目前就只有消息枚举
过两天继续跟进。
标签:ChatServer,const,ChatService,C++,json,集群,using,服务器,include From: https://www.cnblogs.com/dwinternet/p/17856747.html