C++项目推荐,QT项目推荐-仿微信聊天,QT客户端+Linux C++后端
1 项目简介
采用QT6制作客户端,Linux C++实现后端。为用户提供了一个即时聊天平台。
项目地址:https://gitee.com/voice-of-sentiment/chat-forge.git
视频讲解:C++项目推荐,QT项目推荐-仿微信聊天,QT客户端+Linux C++后端
2 Linux C++后端编译和运行
git clone https://gitee.com/voice-of-sentiment/chat-forge.git cd chat-forge/server/thirdparty git clone https://gitee.com/NEU-lab/SQLiteCpp.git #回到chat-forge/server目录 cd .. cd build rm -rf * #重新cmake 编译debug方式 cmake -DCMAKE_BUILD_TYPE=Debug .. make -j4
编译成功后产生server执行文件。
运行:
./server
默认监听端口为:8888
3 QT客户端编译和运行
编译环境:QT6.5 MinGW 64-bit
运行代码前修改服务器地址的ip和端口。
注册账号要用数字:
4 Linux后端框架快速分析
在以下函数断点:
- main
- accept
- recv
- send
main函数位置
main函数入口位置
(gdb) b main Note: breakpoint 1 also set at pc 0x5555555782a2. Breakpoint 4 at 0x5555555782a2: file /home/lqf/linux/reactor/chat-forge/server/main.cpp, line 13.
accept监听位置
#0 __libc_accept (fd=4, addr=..., len=0x7fffffffde78) at ../sysdeps/unix/sysv/linux/accept.c:24 #1 0x00005555555784f1 in main (argc=1, argv=0x7fffffffdfe8) at /home/lqf/linux/reactor/chat-forge/server/main.cpp:88
recv调用位置
#0 __libc_recv (fd=6, buf=0x7ffff71a0be4, len=4, flags=0) at ../sysdeps/unix/sysv/linux/recv.c:24 #1 in Session::recvMsg[abi:cxx11]() (this=) at /home/lqf/linux/reactor/chat-forge/server/session.cpp:301 #2 in taskThread (clientFd=6) at /home/lqf/linux/reactor/chat-forge/server/chatTask.cpp:13 #3 in std::__invoke_impl<void, void (*)(int), int> (__f=@0x55555570cd80: <taskThread(int)>) at /usr/include/c++/10/bits/invoke.h:60 #4 in std::__invoke<void (*)(int), int> (__fn=@0x55555570cd80: 0x55555557455f <taskThread(int)>) at /usr/include/c++/10/bits/invoke.h:95 #5 in std::thread::_Invoker<std::tuple<void (*)(int), int> >::_M_invoke<0ul, 1ul> (this=) at /usr/include/c++/10/thread:264 #6 in std::thread::_Invoker<std::tuple<void (*)(int), int> >::operator() (this=) at /usr/include/c++/10/thread:271 #7 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(int), int> > >::_M_run (this=) at /usr/include/c++/10/thread:215 #8 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6 #9 in start_thread (arg=<optimized out>) at pthread_create.c:477 #10 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
核心:
taskThread
-> Session::recvMsg 后续重点看Session类。
Session::handleMsg核心函数
通过分析recvMsg 找到调用 Session::handleMsg,从名字上看他就是用来处理消息的。
```
int Session::handleMsg(json msg) { usleep(1000); int cmd = msg.at("cmd"); //LOGINFO("handleMsg command:%s\n", cmd.c_str()); switch (cmd) { case cmd_regist: //注册消息 { ... break; } case cmd_login: //登录消息 { ... break; } case cmd_friend_search: //好友查找消息 { ... break; } case cmd_add_friend_request: //添加好友请求 { ... } break; case cmd_add_friend_response: //添加好友响应 { ... break; } break; case cmd_friend_list: //好友列表 { ... break; } case cmd_friend_chat: //好友聊天 {... break; } case cmd_group_create: //群创建 { ... break; } case cmd_group_search: //群搜索 { ... break; } case cmd_group_join_request: //加入群 { ... break; } case cmd_group_join_response: //加群响应 { ... break; } case cmd_group_list: //群列表 { int account = msg.at("account"); CommandHandler::GroupList(account, this); break; } case cmd_group_chat: //群聊天 { ... break; } case cmd_group_member_list: //群成员 { ... break; } case cmd_group_member_add: //群增加成员 { ... break; } case cmd_group_member_del: //群删除成员 { ... break; } case cmd_set_icon: //设置头像 { ... break; } } return 0; }
send函数位置
send函数调用,在处理完消息后应答客户端时调用
#0 __libc_send (fd=6, buf=0x7fffe8001180, len=78, flags=0) at ../sysdeps/unix/sysv/linux/send.c:24 #1 0x000055555557c66a in Session::sendMsg (this=, j=...) at /home/lqf/linux/reactor/chat-forge/server/session.cpp:244 #2 0x0000555555562e49 in CommandHandler::Login (account=110, password="1234", session=) at /home/lqf/linux/reactor/chat-forge/server/CommandHandler.cpp:65 #3 0x000055555557b088 in Session::handleMsg (this=, msg=...) at /home/lqf/linux/reactor/chat-forge/server/session.cpp:58 #4 0x000055555557ccb9 in Session::recvMsg[abi:cxx11]() (this=) at /home/lqf/linux/reactor/chat-forge/server/session.cpp:334 #5 0x00005555555745d6 in taskThread (clientFd=6) at /home/lqf/linux/reactor/chat-forge/server/chatTask.cpp:13
消息协议设计
消息格式:
- [0, 3] 前4个字节封装了后续json字符串的长度length
- [4, length+4-1].
命令类型
// 命令枚举 enum commands { cmd_regist = 0, cmd_login, cmd_logout, cmd_friend_search, cmd_add_friend_request, cmd_add_friend_response, cmd_friend_list, cmd_friend_chat, cmd_group_create, cmd_group_search, cmd_group_join_request, cmd_group_join_response, cmd_group_list, cmd_group_chat, cmd_group_member_list, cmd_group_member_add, cmd_group_member_del, cmd_set_icon };
消息是通过json做序列化:
通过观察: rsvmsg = 分析服务器接收数据的信息,比如:
- {"account":"120","cmd":1,"password":"1234"} ,对应为cmd_login,登录请求
- {"account":120,"cmd":6},对应为cmd_friend_list,请求获取好友列表
- {"cmd":1,"info":["lys","hello",":/Icons/src/QQIcon/icon.jpg"],"res":"yes"} ,对应cmd_login的响应
- {"cmd":6,"count":1,"msglist":[{"account":110,"icon":":/Icons/src/QQIcon/icon.jpg","name":"lqf","online":1,"sig":"hello"}]},对应cmd_friend_list请求获取好友列表的响应,好友在msglist里。
通过观察 send: 分析服务器发送数据的信息,比如:
核心类Session
每个客户端绑定一个session,绑定了socket fd.