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掛掉的情況下,提高可用性。