C++项目 | 集群聊天服务器 | 业务模块
要达到的目的:完全解耦网络模块的代码和业务模块的代码
通过js[“msgid”]绑定一个回调函数,对应获得一个业务处理器handler(handler就是回调函数)
只要解析出来msgid就可以回调对应的函数,而不用写什么if(msgid==1)就怎么样怎么样这样的代码
1.头文件
使用单例模式实现聊天服务器业务类
用函数对象表示回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #ifndef PUBLIC_H #define PUBLIC_H
enum EnMsgType { LOGIN_MSG=1, REG_MSG };
#endif
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #ifndef CHATSERVICE_H #define CHATSERVICE_H
#include<muduo/net/TcpConnection.h> #include<unordered_map> #include<functional> #include"json.hpp"
using namespace std; using namespace muduo; using namespace muduo::net; using json=nlohmann::json;
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();
unordered_map<int,MsgHandler> _msgHandlerMap; };
#endif
|
2.具体实现的cpp文件
用Map来存储msgid和msgid对应的回调函数(handler)
我们解析出来是哪个msgid就可以直接返回对应的函数对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include"chatservice.hpp" #include"public.hpp" #include<muduo/base/Logging.h>
using namespace muduo;
ChatService* ChatService::instance() { static ChatService service; return &service; }
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)}); }
MsgHandler ChatService::getHandler(int msgid) { auto it=_msgHandlerMap.find(msgid); if(it==_msgHandlerMap.end()) { return [=](const TcpConnectionPtr& conn,json &js,Timestamp){ LOG_ERROR<<"msgid: "<<msgid<<" can not find handler"; }; } else { return _msgHandlerMap[msgid]; } }
void ChatService::login(const TcpConnectionPtr& conn,json &js,Timestamp time) { LOG_INFO<<"do login service!!!"; }
void ChatService::reg(const TcpConnectionPtr& conn,json &js,Timestamp time) { LOG_INFO<<"do reg service!!!"; }
|
3.测试文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include"chatserver.hpp" #include<iostream> using namespace std;
int main() { EventLoop loop; InetAddress addr("127.0.0.1",6000); ChatServer server(&loop,addr,"ChatServer");
server.start(); loop.loop(); return 0; }
|
4.ChatServer中的改动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| #include"chatserver.hpp" #include"json.hpp" #include"chatservice.hpp"
#include<string> using namespace std; using namespace placeholders; using json = nlohmann::json;
ChatServer::ChatServer(EventLoop* loop, const InetAddress& listenAddr, const string& 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); }
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) { string buf=buffer->retrieveAllAsString(); json js=json::parse(buf);
auto msgHandler=ChatService::instance()->getHandler(js["msgid"].get<int>()); msgHandler(conn,js,time); }
|
可以看到在最后的onMessage中,只需要
1 2
| auto msgHandler=ChatService::instance()->getHandler(js["msgid"].get<int>()); msgHandler(conn,js,time);
|
这两行代码,就可以完成对应的回调函数(处理器handler)的调用了
而不需要在网络模块写什么类似于这样的代码,需要调用到业务模块的具体函数,这样写网络模块和业务模块耦合度就很高了,对修改(比如增删改业务)很不方便
1 2 3 4 5
| if(msgid==1) { login(...); .... }
|
5.测试结果

可以看到,Chatserver可以对应的返回登录信息,注册信息,并且没有的业务也有报错。
6.这次过程中要在顶级CMake中的头文件路径中加入thirdparty
1
| include_directories(${PROJECT_SOURCE_DIR}/thirdparty)
|