TeamTalk-login_server学习

1、概述

LoginServer 承担登录请求分发器的角色,核心职责是为客户端匹配并返回当前负载最小的可用 MsgServer连接信息,同时实时维护集群中所有 MsgServer 的运行负载数据(含最大连接容量、当前在线用户数);当客户端发起登录请求时,若集群中无可用 MsgServer(如全部满载、无 MsgServer 接入),则向客户端返回约定的错误码,明确告知请求失败原因。

2、客户端与login_server的连接

8080端口监听客户端的连接

1、客户端点击登录

2、先连接,再发数据如下

复制代码
发送http请求,发送的报文如下:

GET /msg_server HTTP/1.1
Host:192.168.62.150:8080
Accept: */*
Connection: Keep-Alive

3、login_server,判断请求路径/msg_server,执行响应函CHttpConn::_HandleMsgServRequest

1、如果无可用msg_server,则回复客户端指定错误码

2、如果msg_server连接,找到msg_server在线用户数最少(负载最少),告诉客户端,回复数据如下:

复制代码
$2 = 0x75b080 "HTTP/1.1 200 OK\r\nConnection:close\r\nContent-Length:268\r\nContent-Type:text/html;chars
et=utf-8\r\n\r\n{\n   \"backupIP\" : \"192.168.62.150\",\n   \"code\" : 0,\n   \"discovery\" : \"http://
127.0.0.1/api/discovery\",\n   \"msfsBackup\" : \"http://192.168.62.150:8700/\",\n   \"msfsPrior\" : \"h
ttp://192.168.62.150:8700/\",\n   \"msg\" : \"\",\n   \"port\" : \"8001\",\n   \"priorIP\" : \"192.168.6
2.150\"\n}\n"

4、回复客户端数据后,立刻关闭连接

说明与客户端的http连接是短连接

3、login_server与msg_server的连接

8100端口:监听msg_server的连接

1、msg_server启动

1、init_login_serv_conn连接login_server

2、连接成功,向 LoginServer 注册自身服务信息(IP、端口、连接容量、当前在线数)

3、login_server将相关信息,保存到全局对象中

static ConnMap_t g_msg_serv_conn_map;

2、用户上下线,msg_server会通知login_server,login_server会更新msg_server在线人数

msg_server对应的代码

cpp 复制代码
   if (user_status == ::IM::BaseDefine::USER_STATUS_ONLINE) {
        IM::Server::IMUserCntUpdate msg;
        msg.set_user_action(USER_CNT_INC);
        msg.set_user_id(pImUser->GetUserId());
        CImPdu pdu;
        pdu.SetPBMsg(&msg);
        pdu.SetServiceId(SID_OTHER);
        pdu.SetCommandId(CID_OTHER_USER_CNT_UPDATE);
        send_to_all_login_server(&pdu);

Login_server对应的代码

cpp 复制代码
void CLoginConn::_HandleUserCntUpdate(CImPdu* pPdu)
{
        map<uint32_t, msg_serv_info_t*>::iterator it = g_msg_serv_info.find(m_handle);
        if (it != g_msg_serv_info.end()) {
                msg_serv_info_t* pMsgServInfo = it->second;
        IM::Server::IMUserCntUpdate msg;
        msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength());

                uint32_t action = msg.user_action();
                if (action == USER_CNT_INC) {
                        pMsgServInfo->cur_conn_cnt++;
                        g_total_online_user_cnt++;
                } else {
                        pMsgServInfo->cur_conn_cnt--;
                        g_total_online_user_cnt--;
                }

                log("%s:%d, cur_cnt=%u, total_cnt=%u ", pMsgServInfo->hostname.c_str(),
            pMsgServInfo->port, pMsgServInfo->cur_conn_cnt, g_total_online_user_cnt);
        }
}

3、其他

3.1、心跳包发送触发条件

当前时间 > 最后一次发送数据时间(m_last_send_tick) + 心跳间隔(SERVER_HEARTBEAT_INTERVAL),立即向对端发送心跳包。

3.2、连接超时关闭触发条件

当前时间 > 最后一次发送数据时间(m_last_send_tick) + 超时间隔(SERVER_TIMEOUT)

关闭连接。

cpp 复制代码
void CLoginConn::OnTimer(uint64_t curr_tick)
{
	if (m_conn_type == LOGIN_CONN_TYPE_CLIENT) {
		if (curr_tick > m_last_recv_tick + CLIENT_TIMEOUT) {
			Close();
		}
	} else {
		if (curr_tick > m_last_send_tick + SERVER_HEARTBEAT_INTERVAL) {
            IM::Other::IMHeartBeat msg;
            CImPdu pdu;
            pdu.SetPBMsg(&msg);
            pdu.SetServiceId(SID_OTHER);
            pdu.SetCommandId(CID_OTHER_HEARTBEAT);
			SendPdu(&pdu);
		}

		if (curr_tick > m_last_recv_tick + SERVER_TIMEOUT) {
			log("connection to MsgServer timeout ");
			Close();
		}
	}
}

3.3、心跳包设计

其实看源码,代码中并没有处理心跳包消息CID_OTHER_HEARTBEAT。

  • 若满足心跳发送条件,LoginServer 向 MsgServer 发送心跳包,发送成功后自动更新基类CImConnm_last_send_tick(最后一次发送数据时间)

  • MsgServer 侧遵循完全相同的逻辑:定时器触发后,满足条件则向 LoginServer 发送心跳包,同时更新自身基类的m_last_send_tick

  • 对端收到心跳包(合法 PDU)后,会自动刷新基类CImConnm_last_recv_tick(最后一次接收数据时间)

  • 定时器持续执行超时检查:若当前时间超过m_last_recv_tick + SERVER_TIMEOUT,即判定对端超长时间未发送任何数据(含心跳包、业务包),直接关闭连接

    m_last_send_tick本端发送任意数据后自动更新 (无论发送的是心跳包、业务包)

    m_last_recv_tick本端收到对端任意合法 PDU 后自动更新(无论接收的是心跳包、业务包)

相关推荐
枕星而眠5 分钟前
C++ 面向对象核心机制深度解析:多态性、虚函数、虚继承与 final 类
运维·开发语言·c++·后端
着迷不白12 分钟前
八、shell脚本
linux·运维
tobias.b14 分钟前
JumpServer4\.10\.16离线部署\+外部Nginx反向代理 解决30分钟空闲断开WebSocket超时(延长10天)
运维·websocket·nginx
_李小白24 分钟前
【android opencv学习笔记】Day 31:提取轮廓之Canny算法
android·opencv·学习
智者知已应修善业30 分钟前
【51单片机8个LED,已经使用了D1D2,怎么样在不动D1D2的前提下实现D6~D8的流水灯】2024-1-19
c++·经验分享·笔记·算法·51单片机
零陵上将军_xdr32 分钟前
后端转全栈学习-Day6-JavaScript 基础-4
前端·javascript·学习
坚果派·白晓明32 分钟前
鸿蒙PC适配实战:simdjson 三方库移植攻略与 AtomCode Skills 提效之道
c++·harmonyos·三方库·skills·atomcode·c/c++三方库·c/c++三方库适配
爱装代码的小瓶子32 分钟前
3. 设计buffer模块
linux·服务器·开发语言·c++·php
郝学胜-神的一滴33 分钟前
Qt 高级开发 027: QTabWidget自定义样式表美化实战
开发语言·c++·qt·程序人生·软件构建·用户界面
双河子思34 分钟前
《代码整洁之道》——读书笔记(持续更新)
开发语言·c++·c#