Chat cluster project based on muduo Library (C + +)

Posted by maxonon on Mon, 03 Jan 2022 10:26:35 +0100


Author: Borage
Time: 17:27, August 9, 2021
Development environment: Ubuntu VSCode
Compiler: g++
Database: MySQL
Programming language: C++
GitHub link

Project overview

Complete a project similar to QQ. The main functions are registration, login, adding friends, creating groups, joining groups, one-to-one chat, group chat, etc.
We need server and client. In order to reduce the coupling between network module and business module, we use MVC architecture here.

Data module

Table design

As a chat project, we certainly need many tables to store some information. For example, when the client logs in, the server needs to match the corresponding account and password information in the library to verify identity. When the user registers, we also need to write the corresponding account number and password to the table.

user table

It is used to store user account, password, nickname, online status and other information

friend table

Used to store the user's friend information

allGroup table

It is used to manage all group information created by the server user

groupUser table

It stores the information of all group members in the group, including the roles of members, such as creator and normal

offlineMessage table

In addition to receiving information from other users online, users can also receive offline information. Offline information is stored in the offline message table and pushed to users after users log in.

Communication format

The communication between server and client uses JSON to complete the standard transmission of data in the network.
For different data, different formats are adopted, as follows:

1.Sign in
json["msgid"] = LOGIN_MSG;
json["id"]			//User id
json["password"]	//password

2.Login feedback
json["msgid"] = LOGIN_MSG_ACK;
json["id"]			//Login user id
json["name"]		//Login user password
json["offlinemsg"]	//offline message 
json["friends"]		//Friend information, which has three fields: id, name and state
json["groups"]		//Group information, which contains three fields: id, groupname, groupdesc and users
					//users has four fields: id, name, state and role
json["errno"]		//The error field is set to 1 in case of error and 2 when the user is not online
json["errmsg"]		//error message

3.register
json["msgid"] = REG_MSG;
json["name"]		//User name
json["password"]	//User name

4.Registration feedback
json["msgid"] = REG_MSG_ACK;
json["id"]			//Return his id number to the user
json["errno"]		//Error message, failure will be set to 1

5.add friends
json["msgid"] = ADD_FRIEND_MSG;
json["id"]			//Current user id
json["friendid"]	//id of the friend to add

6.One on one chat
json["msgid"] = ONE_CHAT_MSG;
json["id"]			//Sender id
json["name"]		//Sender name
json["to"]			//Recipient id
json["msg"]			//Message content
json["time"]		//Sending time

7.Create group
json["msgid"] = CREATE_GROUP_MSG;
json["id"]			//Group creator id
json["groupname"]	//Group name
json["groupdesc"]	//Group description

8.Join group
json["msgid"] = ADD_GROUP_MSG;
json["id"]			//User id
json["groupid"]		//Group id

9.Group chat
json["msgid"] = GROUP_CHAT_MSG;
json["id"]			//Sender id
json["name"]		//Sender name
json["groupid"]		//Sender name
json["msg"]			//Message content
json["time"]		//Sending time

10.cancellation
json["msgid"] = LOGINOUT_MSG;
json["id"]			//id to log off

After specifying the communication format, we can start!

Network and service module

Network module

Here we use the interface provided by muduo library

When the user connects or disconnects, the preset callback function about connection will be called, and its execution object should be main reactor.
When a read-write event occurs, the onMessage method will be called, and the execution object is sub reactor. It is very important to decouple its content from the network module and business module!!!

There is a msgid field in the communication module, which represents the message type between communications

    LOGIN_MSG = 1,  //Login message, binding login
    LOGIN_MSG_ACK,  //Login response message
    REG_MSG,        //Register message, bind regist er
    REG_MSG_ACK,    //Registration response message
    ONE_CHAT_MSG,   //One to one chat message
    ADD_FRIEND_MSG, //Add friend message

    CREATE_GROUP_MSG, //Create group chat
    ADD_GROUP_MSG,    //Join group chat
    GROUP_CHAT_MSG,   //Group chat message

    LOGINOUT_MSG,   //Logoff message

According to these message types, we can create a container for performing callback operations and bind the corresponding callback operations.

msg_handler_map_.insert({LOGIN_MSG, bind(&ChatService::login, this, _1, _2, _3)});
msg_handler_map_.insert({LOGINOUT_MSG, bind(&ChatService::loginout, this, _1, _2, _3)});
msg_handler_map_.insert({REG_MSG, bind(&ChatService::regist, this, _1, _2, _3)});
msg_handler_map_.insert({ONE_CHAT_MSG, bind(&ChatService::one_chat, this, _1, _2, _3)});
msg_handler_map_.insert({ADD_FRIEND_MSG, bind(&ChatService::add_friend, this, _1, _2, _3)});
msg_handler_map_.insert({CREATE_GROUP_MSG, bind(&ChatService::create_group, this, _1, _2, _3)});
msg_handler_map_.insert({ADD_GROUP_MSG, bind(&ChatService::add_group, this, _1, _2, _3)});
msg_handler_map_.insert({GROUP_CHAT_MSG, bind(&ChatService::group_chat, this, _1, _2, _3)});

Business module

//Store the connection of online users, so that the server can send messages to users and pay attention to thread safety
unordered_map<int, TcpConnectionPtr> user_connection_map_;

mutex conn_mutex_;

UserModel user_model_;
OfflineMessageModel offline_message_model_;
FriendModel friend_model_;
GroupModel group_model_;

Registered business

After obtaining JSON, the server executes the callback function of the registration business to query the user table. If the name is repeated, set errno to 1, set 0 successfully, package JSON and return it to the client.

Login service

After receiving the JSON, the server queries the user table. The account and password match fails. Set errno to 1. Check whether the user is online after success. If the current user's online status in the user table is offline, set errno2. If not, log in. Set errno to 0. At this time, push the offline information and user / group information to the client.

Add friends

After getting the deserialized string, insert the information directly into the friend table

One on one chat

After the server receives the client information, it first performs maintenance on the_ connectonMap to query. If it exists, it means that the target user is already in the server and can be forwarded directly.
If it does not exist, query the online status of the target user in the user table. If it is not online, store it in the offline message table (send offline information). If it is online, publish the information to the message queue middleware of redis.

Create group chat

After receiving the information, the server writes the group information into the allgroup table, and writes the Creator into the groupuser table as "creator".

Join group chat

After receiving the client information, the server writes the user into the groupuser table as "normal";

Group chat service

After receiving the information from the client, the server first goes to GroupUser to query the IDs of all group members, and then goes to the user of the server one by one_ connection_ map_ Whether the user receiving the information is online on this server. If online, it can be forwarded directly. If not, check whether the information in the database is online. If online, it means that the receiving user logs in to other servers and forwards the message through redis m id dleware.
If they are not online, send offline messages.

Cancellation business

After receiving the information, the server changes the user's online state to offline state.

Server cluster

There will be an obvious problem when we deal with this at present. Generally speaking, a server intelligently supports 1-2w concurrency, which is far from enough for a chat system. We use nginx load balancing here. Users still access the same port and nginx connects different customers to servers that do not work

Cross server communication

There is a problem after the cluster. How do two clients hanging on different servers communicate? We use redis's Message Queuing Middleware here.

When the client logs in, the server subscribe s its id number to the redis middleware, which indicates that the server is interested in the events of this id. when redis receives the message sent to this id, it will forward the message to this server.

reflection

This server also has some design defects:

  • If the number of users is large, you need to pull offline information and user / group status information from the data table of the server after each login, which will cause large access. How to save these information to the local client? When should this operation be completed

  • When the server suddenly goes down, what should the connected users do with this information?

  • Friends added in this project can be added successfully without the consent of the added user, which needs to be improved in the later stage.

reference

Shi Lei.Tencent classroom

Topics: network