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 发送心跳包,发送成功后自动更新基类CImConn的m_last_send_tick(最后一次发送数据时间)

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

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

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

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

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

相关推荐
动词ing23 分钟前
【学习笔记】动态数码管显示
笔记·学习
陈年老古董23 分钟前
ClickHouse 单机搭建记录
hive·笔记·学习·clickhouse·硬件架构
艾莉丝努力练剑32 分钟前
【AI大模型接入SDK】ChatServer接口测试
网络·c++·人工智能·学习·ai·大模型·sdk
蓝祁子yoky39 分钟前
Qt学习日记 Day15:网络编程(二)- UDP基础
网络·qt·学习
D e re k ZH42 分钟前
C++ 模板与泛型编程进阶(No 2)
开发语言·c++
云川之下1 小时前
[ensp] 交换机入门配置例子(带vlan)
运维·服务器·网络
FserSuN1 小时前
Hive 分区表存储与查询优化学习总结
hive·hadoop·学习
青少儿编程课堂1 小时前
蓝桥杯青少组图形化+信息素养+电子学会Scratch考级:校园口算闯关解析
c++·python·算法·bfs·信息学竞赛
eggwyw1 小时前
C++深入浅出探索数据结构的原理
开发语言·c++
2603_969694851 小时前
【MySQL学习笔记】DQL(基础查询/条件/聚合/分组/排序/分页)与 DCL(用户权限)全解析
数据库·笔记·学习·mysql·学习方法