Original: www.bluefoxah.org/teamtalk/server_flow.html
Preface
In the previous article, we simply analyzed the configuration of each server. In this article, we simply analyzed the whole operation process of TeamTalk server.
Server-side process
There is no strict sequential process for the start-up of the server, because each end will actively connect to the server on which it depends after the start-up. However, in this case, if it is an online environment, it is recommended to start in the following order (not the only order):
1. Start db_proxy.
2. Start route_server, file_server, msfs
3. Start login_server
4. Start msg_server
Then I will explain a process overview of the server according to the start-up sequence of the server.
Step 1: After starting db_proxy, db_proxy will connect to the corresponding configuration file. MySQL Examples, and Redis Example.
Step 2: After starting route_server, file_server and msfs, each server will start to listen on the corresponding ports.
Step 3: Start login_server,login_server starts to listen on the corresponding port, waiting for the client to connect, and assign a relatively small load msg_server to the client.
Step 4: Start the msg_server. When the msg_server is started, it will actively connect route_server, login_server, db_proxy. It will register the port information it monitors to login_server. At the same time, when the user is online and offline, it will report its load to login_server.
Next, I will analyze some logic of route_server, login_server and msg_server. Here is a simple analysis, followed by specific analysis for each end.
Firstly, the structure of each end is explained.
route_server
The role of route_server in the whole tt is a place for message forwarding, which maintains global user information in memory. When there are multiple msg_servers, route_server is used to transfer messages between multiple msg_servers.
In RouteConn.cpp, the following structure is defined to save user status:
- typedef map<CRouteConn*, uint32_t> RouteConnMap_t;
- typedef struct {
- uint32_t status;
- RouteConnMap_t conns;
- } UserStat_t;
- typedef hash_map<uint32_t, UserStat_t> UserStatMap_t;
- static UserStatMap_t g_rs_user_map;
typedef map<CRouteConn*, uint32_t> RouteConnMap_t; typedef struct { uint32_t status; RouteConnMap_t conns; } UserStat_t; typedef hash_map<uint32_t, UserStat_t> UserStatMap_t; static UserStatMap_t g_rs_user_map;
g_rs_user_map is a hash_map that stores global user information. It is defined as follows: key is a user id, value is a structure:
- typedef struct {
- uint32_t status;
- RouteConnMap_t conns;
- } UserStat_t;
typedef struct { uint32_t status; RouteConnMap_t conns; } UserStat_t;
In this structure, status identifies the user's status, and conns is also a map, which stores the corresponding msg_server connection and whether the user is on the pc or mobile side of the connection.
When a user is online again, msg_server sends the user's status to route_server, and route_server inserts a record in g_rs_user_map.
login_server
login_server in the entire TT Framework In login_server, the address of all msg_server s and their current load situation are also maintained in memory.
In LoginConn.cpp, the following structure is defined to save the state machine load of msg_server:
- typedef hash_map<uint32_t, uint32_t> UserConnCntMap_t;
- typedef struct {
- string ip_addr1; //Netcom IP
- string ip_addr2; //Telecom IP
- uint16_t port;
- uint32_t max_conn_cnt;
- uint32_t cur_conn_cnt;
- uint32_t cur_user_cnt; //Current number of users - cur_user_cnt!= cur_conn_cnt because users are allowed to log in at multiple points
- string hostname; //Host name of message server
- uint32_t server_type;
- UserConnCntMap_t user_cnt_map;
- } msg_serv_info_t;
- static map<uint32_t, msg_serv_info_t*> g_msg_serv_info;
typedef hash_map<uint32_t, uint32_t> UserConnCntMap_t; typedef struct { string ip_addr1; // Netcom IP string ip_addr2; // Telecom IP uint16_t port; uint32_t max_conn_cnt; uint32_t cur_conn_cnt; uint32_t cur_user_cnt; // Current User Number - cur_user_cnt!= cur_conn_cnt because users are allowed to log in at multiple points string hostname; // Host name of message server uint32_t server_type; UserConnCntMap_t user_cnt_map; } msg_serv_info_t; static map<uint32_t, msg_serv_info_t*> g_msg_serv_info;
g_msg_serv_info is a hash_map used to save msg_server. The key is a socket descriptor and the value is a structure that contains specific information about the corresponding msg_server:
- typedef struct {
- string ip_addr1; //Netcom IP
- string ip_addr2; //Telecom IP
- uint16_t port;
- uint32_t max_conn_cnt;
- uint32_t cur_conn_cnt;
- uint32_t cur_user_cnt; //Current number of users - cur_user_cnt!= cur_conn_cnt because users are allowed to log in at multiple points
- string hostname; //Host name of message server
- uint32_t server_type;
- UserConnCntMap_t user_cnt_map;
- } msg_serv_info_t;
typedef struct { string ip_addr1; // Netcom IP string ip_addr2; // Telecom IP uint16_t port; uint32_t max_conn_cnt; uint32_t cur_conn_cnt; uint32_t cur_user_cnt; // Current User Number - cur_user_cnt!= cur_conn_cnt because users are allowed to log in at multiple points string hostname; // Host name of message server uint32_t server_type; UserConnCntMap_t user_cnt_map; } msg_serv_info_t;
ip_addr1 and ip_addr2 respectively store the IP of communication and telecommunication corresponding to msg_server (which is designed here because our server is two-wire). Port saves the port corresponding to msg_server. max_conn_cnt stores the maximum number of connections configured in msg_server. When the number of connections exceeds this value, msg_server does not score. In the past, cur_conn_cnt corresponded to the current number of connections of msg_server. cur_user_cnt saved the number of users corresponding to msg_server login. As the commentary said, the current number of users <= the current number of connections, hostname saved the hostname of msg_server, server_type labeled msg_server. Network type, currently only one definition of Tcp Server, defined in ImPduServer.h:
- enum {
- MSG_SERVER_TYPE_TCP = 1,
- };
enum { MSG_SERVER_TYPE_TCP = 1, };
user_cnt_map is a hash_map used to save the user id and the corresponding number of users:
- hash_map<uint32_t, uint32_t> UserConnCntMap_t;
hash_map<uint32_t, uint32_t> UserConnCntMap_t;
msg_server
Er... msg_server is really too complex, let's leave it for later code analysis.
start-up
msg_server<----->login_server
msg_server will actively connect to login_server when it is started, and register its information with login_server through the data package CImPduMsgServInfo. Its processing logic is in LoginServConn.cpp:
- void CLoginServConn::OnConfirm()
- {
- log("connect to login server success\n");
- m_bOpen = true;
- g_login_server_list[m_serv_idx].reconnect_cnt = MIN_RECONNECT_CNT / 2;
- uint32_t cur_conn_cnt = 0;
- list<user_conn_t> user_conn_list;
- CImUserManager::GetInstance()->GetUserConnCnt(&user_conn_list, cur_conn_cnt);
- char hostname[256] = {0};
- gethostname(hostname, 256);
- CImPduMsgServInfo pdu(g_msg_server_ip_addr1.c_str(), g_msg_server_ip_addr2.c_str(),
- g_msg_server_port, g_max_conn_cnt, cur_conn_cnt, hostname, MSG_SERVER_TYPE_TCP);
- SendPdu(&pdu);
- if (!user_conn_list.empty()) {
- CImPduUserConnInfo pdu2(&user_conn_list);
- SendPdu(&pdu2);
- }
- }
void CLoginServConn::OnConfirm() { log("connect to login server success\n"); m_bOpen = true; g_login_server_list[m_serv_idx].reconnect_cnt = MIN_RECONNECT_CNT / 2; uint32_t cur_conn_cnt = 0; list<user_conn_t> user_conn_list; CImUserManager::GetInstance()->GetUserConnCnt(&user_conn_list, cur_conn_cnt); char hostname[256] = {0}; gethostname(hostname, 256); CImPduMsgServInfo pdu(g_msg_server_ip_addr1.c_str(), g_msg_server_ip_addr2.c_str(), g_msg_server_port, g_max_conn_cnt, cur_conn_cnt, hostname, MSG_SERVER_TYPE_TCP); SendPdu(&pdu); if (!user_conn_list.empty()) { CImPduUserConnInfo pdu2(&user_conn_list); SendPdu(&pdu2); } }
When a user connects to msg_server and logs in successfully or the user disconnects, a CImPduUserCntUpdate packet is sent to login_server to notify login_server. Its processing logic is in LoginServConn.cpp:
- void send_to_all_login_server(CImPdu* pPdu)
- {
- CLoginServConn* pConn = NULL;
- for (uint32_t i = 0; i < g_login_server_count; i++) {
- pConn = (CLoginServConn*)g_login_server_list[i].serv_conn;
- if (pConn && pConn->IsOpen()) {
- pConn->SendPdu(pPdu);
- }
- }
- }
void send_to_all_login_server(CImPdu* pPdu) { CLoginServConn* pConn = NULL; for (uint32_t i = 0; i < g_login_server_count; i++) { pConn = (CLoginServConn*)g_login_server_list[i].serv_conn; if (pConn && pConn->IsOpen()) { pConn->SendPdu(pPdu); } } }
msg_server<---->route_server
msg_server will actively connect route_server after starting, and report its current online user status to route_server through the data package CImPduOnlineUserInfo. Its processing logic is in LoginServConn.cpp:
- void CRouteServConn::OnConfirm()
- {
- log("connect to route server success\n");
- m_bOpen = true;
- m_connect_time = get_tick_count();
- g_route_server_list[m_serv_idx].reconnect_cnt = MIN_RECONNECT_CNT / 2;
- if (g_master_rs_conn == NULL) {
- update_master_route_serv_conn();
- }
- list<user_conn_stat_t> online_user_list;
- CImUserManager::GetInstance()->GetOnlineUserInfo(&online_user_list);
- CImPduOnlineUserInfo pdu(&online_user_list);
- SendPdu(&pdu);
- }
void CRouteServConn::OnConfirm() { log("connect to route server success\n"); m_bOpen = true; m_connect_time = get_tick_count(); g_route_server_list[m_serv_idx].reconnect_cnt = MIN_RECONNECT_CNT / 2; if (g_master_rs_conn == NULL) { update_master_route_serv_conn(); } list<user_conn_stat_t> online_user_list; CImUserManager::GetInstance()->GetOnlineUserInfo(&online_user_list); CImPduOnlineUserInfo pdu(&online_user_list); SendPdu(&pdu); }
When a user connects to msg_server and logs in successfully or the user disconnects, a CImPduUserStatusUpdate packet is sent to route_server to notify route_server. Its processing logic is in RouteServConn.cpp:
- void send_to_all_route_server(CImPdu* pPdu)
- {
- CRouteServConn* pConn = NULL;
- for (uint32_t i = 0; i < g_route_server_count; i++) {
- pConn = (CRouteServConn*)g_route_server_list[i].serv_conn;
- if (pConn && pConn->IsOpen()) {
- pConn->SendPdu(pPdu);
- }
- }
- }
void send_to_all_route_server(CImPdu* pPdu) { CRouteServConn* pConn = NULL; for (uint32_t i = 0; i < g_route_server_count; i++) { pConn = (CRouteServConn*)g_route_server_list[i].serv_conn; if (pConn && pConn->IsOpen()) { pConn->SendPdu(pPdu); } } }
Call place
Calls that report local conditions to route_server and login_server are called in MsgConn.cpp when the user is online or offline:
- void CMsgConn::SendUserStatusUpdate(uint32_t user_status)
- {
- if (!m_bOpen) {
- return;
- }
- CImUser* pImUser = CImUserManager::GetInstance()->GetImUserByName(m_user_name);
- if (!pImUser) {
- return;
- }
- //LoginServer is notified only by an offline notification
- if (user_status == USER_STATUS_ONLINE) {
- CImPduUserCntUpdate pdu(USER_CNT_INC, pImUser->GetUserId());
- send_to_all_login_server(&pdu);
- //if (pImUser->IsMsgConnEmpty()) {
- CImPduUserStatusUpdate pdu2(USER_STATUS_ONLINE, pImUser->GetUserId(), GetClientTypeFlag());
- send_to_all_route_server(&pdu2);
- //}
- } else if (user_status == USER_STATUS_OFFLINE) {
- CImPduUserCntUpdate pdu(USER_CNT_DEC, pImUser->GetUserId());
- send_to_all_login_server(&pdu);
- //if (pImUser->IsMsgConnEmpty()) {
- CImPduUserStatusUpdate pdu2(USER_STATUS_OFFLINE, pImUser->GetUserId(), GetClientTypeFlag());
- send_to_all_route_server(&pdu2);
- //}
- }
- }
void CMsgConn::SendUserStatusUpdate(uint32_t user_status) { if (!m_bOpen) { return; } CImUser* pImUser = CImUserManager::GetInstance()->GetImUserByName(m_user_name); if (!pImUser) { return; } // LoginServer is notified only by an offline notification if (user_status == USER_STATUS_ONLINE) { CImPduUserCntUpdate pdu(USER_CNT_INC, pImUser->GetUserId()); send_to_all_login_server(&pdu); //if (pImUser->IsMsgConnEmpty()) { CImPduUserStatusUpdate pdu2(USER_STATUS_ONLINE, pImUser->GetUserId(), GetClientTypeFlag()); send_to_all_route_server(&pdu2); //} } else if (user_status == USER_STATUS_OFFLINE) { CImPduUserCntUpdate pdu(USER_CNT_DEC, pImUser->GetUserId()); send_to_all_login_server(&pdu); //if (pImUser->IsMsgConnEmpty()) { CImPduUserStatusUpdate pdu2(USER_STATUS_OFFLINE, pImUser->GetUserId(), GetClientTypeFlag()); send_to_all_route_server(&pdu2); //} } }