im源码分析(teamtalk)系列:
1. im源码分析(teamtalk)–LoginServer
2. im源码分析(teamtalk)–RouteServer
3. im源码分析(teamtalk)–DbProxyServer
RouteServer
RouteServer介绍
RouteServer: 路由服务器,在存在多个MsgServer的情况下,用户可能登陆在不同的MsgServer上,这个时候就需要RouteServer进行转发。
源码分析
void CRouteConn::HandlePdu(CImPdu* pPdu)
{
switch (pPdu->GetCommandId()) {
case CID_OTHER_HEARTBEAT:
// do not take any action, heart beat only update m_last_recv_tick
break;
case CID_OTHER_ONLINE_USER_INFO:
_HandleOnlineUserInfo( pPdu );
break;
case CID_OTHER_USER_STATUS_UPDATE:
_HandleUserStatusUpdate( pPdu );
break;
case CID_OTHER_ROLE_SET:
_HandleRoleSet( pPdu );
break;
case CID_BUDDY_LIST_USERS_STATUS_REQUEST:
_HandleUsersStatusRequest( pPdu );
break;
case CID_MSG_DATA:
case CID_SWITCH_P2P_CMD:
case CID_MSG_READ_NOTIFY:
case CID_OTHER_SERVER_KICK_USER:
case CID_GROUP_CHANGE_MEMBER_NOTIFY:
case CID_FILE_NOTIFY:
case CID_BUDDY_LIST_REMOVE_SESSION_NOTIFY:
_BroadcastMsg(pPdu, this);
break;
case CID_BUDDY_LIST_SIGN_INFO_CHANGED_NOTIFY:
_BroadcastMsg(pPdu);
break;
default:
log("CRouteConn::HandlePdu, wrong cmd id: %d ", pPdu->GetCommandId());
break;
}
}
_HandleOnlineUserInfo
更新在线用户的信息,只有变更的用户信息,不是所有的。
_HandleUserStatusUpdate
用户多点多端登录的处理逻辑。
_HandleRoleSet
设置MsgServer的主路由服务
_HandleUsersStatusRequest
void CRouteConn::_HandleUsersStatusRequest(CImPdu* pPdu)
{
IM::Buddy::IMUsersStatReq msg;
CHECK_PB_PARSE_MSG(msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength()));
uint32_t request_id = msg.user_id();
uint32_t query_count = msg.user_id_list_size();
log("HandleUserStatusReq, req_id=%u, query_count=%u ", request_id, query_count);
IM::Buddy::IMUsersStatRsp msg2;
msg2.set_user_id(request_id);
msg2.set_attach_data(msg.attach_data());
list<user_stat_t> result_list;
user_stat_t status;
for(uint32_t i = 0; i < query_count; i++)
{
IM::BaseDefine::UserStat* user_stat = msg2.add_user_stat_list();
uint32_t user_id = msg.user_id_list(i);
user_stat->set_user_id(user_id);
CUserInfo* pUser = GetUserInfo(user_id);
if (pUser) {
user_stat->set_status((::IM::BaseDefine::UserStatType) pUser->GetStatus()) ;
}
else
{
user_stat->set_status(USER_STATUS_OFFLINE) ;
}
}
// send back query user status
CImPdu pdu;
pdu.SetPBMsg(&msg2);
pdu.SetServiceId(SID_BUDDY_LIST);
pdu.SetCommandId(CID_BUDDY_LIST_USERS_STATUS_RESPONSE);
pdu.SetSeqNum(pPdu->GetSeqNum());
SendPdu(&pdu);
}
刷新好友状态;
_BroadcastMsg
向MsgServer广播信息。
问题:RouteServer已经有所有用户id的在线状态和连接信息,为什么所有的消息都要广播?
个人推测这可能是要改进的一个点,在多个MsgServer存在的情况下完全可以根据用户id定向转发消息,这样能减少网络资源的浪费。
延伸:存在多个RouteServer的情况下,如何保证消息的唯一性?
OK,这就用到_HandleRoleSet这个接口了:
MsgServer在启动后会主动去RouteServer去注册,并把当前所有在线的用户信息告知RouterServer,然后在所有RouteServer列表中选择一个主路由服务(触发RouterServer的_HandleRoleSet接口),所有的转发消息只走主路由服务。
冗余的RouteServer做为备份,在主RouteServer挂掉的情况下,提高可用性。