C++项目 | 集群聊天服务器 | 群组功能业务 实现三个功能:
1.相关的数据库表
2.消息类型 1 2 3 4 5 6 7 8 9 10 11 12 13 enum EnMsgType { LOGIN_MSG=1 , LOGIN_MSG_ACK, REG_MSG, REG_MSG_ACK, ONE_CHAT_MSG, ADD_FRIEND_MSG, CREATE_GROUP_MSG, ADD_GROUP_MSG, GROUP_CHAT_MSG, };
3.groupuser.hpp 用来存储群组成员信息的
对比user多了一个role,表明是管理员还是普通成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #ifndef GROUPUSER_H #define GROUPUSER_H #include "user.hpp" class GroupUser :public User{ public : void setRole (string role) {this ->role=role;} string getRole () {return this ->role;} private : string role; }; #endif
4.group.hpp 封装群的相关信息
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 #ifndef GROUP_H #define GROUP_H #include "groupuser.hpp" #include <string> #include <vector> using namespace std;class Group { public : Group (int id=-1 ,string name="" ,string desc="" ) { this ->id=id; this ->name=name; this ->desc=desc; } void setId (int id) {this ->id=id;} void setName (string name) {this ->name=name;} void setDesc (string desc) {this ->desc=desc;} int getId () {return this ->id;} string getName () {return this ->name;} string getDesc () {return this ->desc;} vector<GroupUser> &getUsers () {return this ->users;} private : int id; string name; string desc; vector<GroupUser> users; }; #endif
5.groupmodel.hpp 对群的操作的封装
主要包含四个操作
1.创建群组
2.加入群组
3.查询用户所在群组信息
4.发送群聊消息,在这个群的所有成员都可以收到,不在线的成员的消息要存储到离线消息表
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 #ifndef GROUPMODEL_H #define GROUPMODEL_H #include "group.hpp" #include <string> #include <vector> using namespace std;class GroupModel { public : bool createGroup (Group &group) ; void addGrooup (int userid,int groupid,string role) ; vector<Group> queryGroups (int userid) ; vector<int > queryGroupUsers (int userid,int groupid) ; }; #endif
6.groupmodel.cpp 对上面四个方法的具体实现
创建和加入群组
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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 #include "groupmodel.hpp" #include "db.h" bool GroupModel::createGroup (Group &group) { char sql[1024 ]={0 }; sprintf (sql,"insert into allgroup(groupname,groupdesc) values('%s','%s')" , group.getName ().c_str (),group.getDesc ().c_str ()); MySQL mysql; if (mysql.connect ()) { if (mysql.update (sql)) { group.setId (mysql_insert_id (mysql.getConnection ())); return true ; } } return false ; } void GroupModel::addGrooup (int userid,int groupid,string role) { char sql[1024 ]={0 }; sprintf (sql,"insert into groupuservalues(%d,%d,'%s')" , groupid,userid,role.c_str ()); MySQL mysql; if (mysql.connect ()) { mysql.update (sql); } } vector<Group> GroupModel::queryGroups (int userid) { char sql[1024 ]={0 }; sprintf (sql,"select a.id,a.groupname,a.groupdesc from allGroup a inner join groupUser b on a.id=b.groupid where b.userid=%d" , userid); vector<Group> groupVec; MySQL mysql; if (mysql.connect ()) { MYSQL_RES *res=mysql.query (sql); if (res!=nullptr ) { MYSQL_ROW row=mysql_fetch_row (res); if (row!=nullptr ) { Group group; group.setId (atoi (row[0 ])); group.setName (row[1 ]); group.setDesc (row[2 ]); groupVec.push_back (group); mysql_free_result (res); } } } for (Group &group:groupVec) { sprintf (sql,"select a.id,a.name,a.state,b.grouprole from user a inner join groupUser b on a.id=b.userid where b.groupid=%d" , group.getId ()); MYSQL_RES * res=mysql.query (sql); if (res!=nullptr ) { MYSQL_ROW row; while ((row=mysql_fetch_row (res))!=nullptr ) { GroupUser user; user.setId (atoi (row[0 ])); user.setName (row[1 ]); user.setState (row[2 ]); user.setRole (row[3 ]); group.getUsers ().push_back (user); } mysql_free_result (res); } } return groupVec; } vector<int > GroupModel::queryGroupUsers (int userid,int groupid) { char sql[1024 ]={0 }; sprintf (sql,"select userid from groupUser where groupid=%d and userid !=%d" ,groupid,userid); vector<int > idVec; MySQL mysql; if (mysql.connect ()) { MYSQL_RES *res=mysql.query (sql); if (res!=nullptr ) { MYSQL_ROW row; while ((row = mysql_fetch_row (res))!=nullptr ) { idVec.push_back (atoi (row[0 ])); } mysql_free_result (res); } } return idVec; }
7.群组业务代码实现 记得注册绑定到Map上面,不然对应的消息类型发过来不会调用对应的函数的
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 void ChatService::createGroup (const TcpConnectionPtr& conn,json &js,Timestamp time) { int userid=js["id" ].get <int >(); string name=js["groupname" ]; string desc=js["groupdesc" ]; Group group (-1 ,name,desc) ; if (_groupModel.createGroup (group)) { _groupModel.addGrooup (userid,group.getId (),"creator" ); } } void ChatService::addGroup (const TcpConnectionPtr& conn,json &js,Timestamp time) { int userid=js["id" ].get <int >(); int groupid=js["groupid" ].get <int >(); _groupModel.addGrooup (userid,groupid,"normal" ); } void ChatService::groupChat (const TcpConnectionPtr& conn,json &js,Timestamp time) { int userid=js["id" ].get <int >(); int groupid=js["groupid" ].get <int >(); vector<int > useridVec=_groupModel.queryGroupUsers (userid,groupid); lock_guard<mutex> lock (_connMutex) ; for (int id:useridVec) { auto it=_userConnMap.find (id); if (it!=_userConnMap.end ()) { it->second->send (js.dump ()); } else { _offlineMsgModel.insert (id,js.dump ()); } } }
8.项目工作目录结构
9.CMake改动 工作目录下的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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} /include /server/db)include_directories (${PROJECT_SOURCE_DIR} /include /server/model)include_directories (${PROJECT_SOURCE_DIR} /include /client)include_directories (${PROJECT_SOURCE_DIR} /thirdparty)add_subdirectory (src)
./src下的
1 add_subdirectory (server)
./src/server下的
1 2 3 4 5 6 7 8 9 10 11 aux_source_directory (. SRC_LIST)aux_source_directory (./db DB_LIST)aux_source_directory (./model MODEL_LIST)add_executable (ChatServer ${SRC_LIST} ${DB_LIST} ${MODEL_LIST} )target_link_libraries (ChatServer muduo_net muduo_base mysqlclient pthread)