登陆服务器启动会执行如下语句:
1 main函数介绍
int main(int argc, char* argv[])
{
CStrExplode client_listen_ip_list(client_listen_ip, ';');
for (uint32_t i = 0; i < client_listen_ip_list.GetItemCnt(); i++) {
ret = netlib_listen(client_listen_ip_list.GetItem(i), client_port, client_callback, NULL);
if (ret == NETLIB_ERROR)
return ret;
}
CStrExplode msg_server_listen_ip_list(msg_server_listen_ip, ';');
for (uint32_t i = 0; i < msg_server_listen_ip_list.GetItemCnt(); i++) {
ret = netlib_listen(msg_server_listen_ip_list.GetItem(i), msg_server_port, msg_serv_callback, NULL);
if (ret == NETLIB_ERROR)
return ret;
}
printf("server start listen on:\nFor client %s:%d\nFor MsgServer: %s:%d\n",
client_listen_ip, client_port, msg_server_listen_ip, msg_server_port);
init_login_conn();//实际上是定时轮训login_conn_timer_callback函数,做心跳检测用。
printf("now enter the event loop...\n");
netlib_eventloop(); //开始进入轮训。
return 0;
}
对于客户端的连接会进入client_callback回调,如下:
void client_callback(void* callback_data, uint8_t msg, uint32_t handle, void* pParam)
{
if (msg == NETLIB_MSG_CONNECT)
{
CLoginConn* pConn = new CLoginConn();
pConn->OnConnect2(handle, LOGIN_CONN_TYPE_CLIENT);
}
else
{
log("!!!error msg: %d\n", msg);
}
}
可以看到,直接进入CLoginConn::OnConnect2函数,如下:
void CLoginConn::OnConnect2(net_handle_t handle, int conn_type)
{
m_handle = handle;
m_conn_type = conn_type;
ConnMap_t* conn_map = &g_msg_serv_conn_map;
if (conn_type == LOGIN_CONN_TYPE_CLIENT) {
conn_map = &g_client_conn_map;
}
conn_map->insert(make_pair(handle, this));
netlib_option(handle, NETLIB_OPT_SET_CALLBACK, (void*)imconn_callback);
netlib_option(handle, NETLIB_OPT_SET_CALLBACK_DATA, (void*)conn_map);
}
可以看到,把客户加到g_client_conn_map,handle为accept后的SOCKET,并给SOCKET设置了回调函数imconn_callback,回调参数conn_map。
2 CLoginConn介绍
void CLoginConn::Close()
{
if (m_handle != NETLIB_INVALID_HANDLE) {
netlib_close(m_handle);
if (m_conn_type == LOGIN_CONN_TYPE_CLIENT) {
g_client_conn_map.erase(m_handle);
//对于客户端,从g_client_conn_map去掉指定的m_handle即可。
} else {
//对于消息服务器,从g_msg_serv_conn_map去掉指定的m_handle,并从g_msg_serv_info删除消息服务器的信息,并更新总的用户数g_total_online_user_cnt。
g_msg_serv_conn_map.erase(m_handle);
// remove all user count from this message server
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;
g_total_online_user_cnt -= pMsgServInfo->cur_conn_cnt;
log("onclose from MsgServer: %s:%u\n", pMsgServInfo->hostname.c_str(), pMsgServInfo->port);
delete pMsgServInfo;
g_msg_serv_info.erase(it);
}
}
}
ReleaseRef();
}
void CLoginConn::_HandleMsgServInfo(CImPduMsgServInfo* pPdu)
{
//处理消息服务器的登陆,将服务器信息加入g_msg_serv_info,并更新总的用户数g_total_online_user_cnt。
msg_serv_info_t* pMsgServInfo = new msg_serv_info_t;
pMsgServInfo->ip_addr1 = string(pPdu->GetIp1Addr(), pPdu->GetIp1Len());
pMsgServInfo->ip_addr2 = string(pPdu->GetIp2Addr(), pPdu->GetIp2Len());
pMsgServInfo->port = pPdu->GetPort();
pMsgServInfo->max_conn_cnt = pPdu->GetMaxConnCnt();
pMsgServInfo->cur_conn_cnt = pPdu->GetCurConnCnt();
pMsgServInfo->hostname = string(pPdu->GetHostname(), pPdu->GetHostnameLen());
pMsgServInfo->server_type = pPdu->GetServerType();
g_msg_serv_info.insert(make_pair(m_handle, pMsgServInfo));
g_total_online_user_cnt += pMsgServInfo->cur_conn_cnt;
log("MsgServInfo, ip_addr1=%s, ip_addr2=%s, port=%d, max_conn_cnt=%d, cur_conn_cnt=%d, "\
"hostname: %s, server_type: %d\n",
pMsgServInfo->ip_addr1.c_str(), pMsgServInfo->ip_addr2.c_str(), pMsgServInfo->port,pMsgServInfo->max_conn_cnt,
pMsgServInfo->cur_conn_cnt, pMsgServInfo->hostname.c_str(), pMsgServInfo->server_type);
}
void CLoginConn::_HandleUserCntUpdate(CImPduUserCntUpdate* pPdu)
{
//处理用户数更新
map<uint32_t, msg_serv_info_t*>::iterator it = g_msg_serv_info.find(m_handle);
if (it != g_msg_serv_info.end()) {
//先根据m_handle找到消息服务器的指针。
msg_serv_info_t* pMsgServInfo = it->second;
uint32_t action = pPdu->GetUserAction();
uint32_t user_id = pPdu->GetUserId();
if (action == USER_CNT_INC) {
//用户数增加的情况
pMsgServInfo->cur_conn_cnt++; //先更服务器信息的当前连接数。
UserConnCntMap_t::iterator iter = g_user_conn_cnt_map.find(user_id);
//如果user_id未添加过,先添加,再更新总在线数g_total_online_user_cnt;如果user_id已添加过,更新user_id对于的个数。
if(iter == g_user_conn_cnt_map.end()) {
g_user_conn_cnt_map.insert(make_pair(user_id, 1));
g_total_online_user_cnt++;
} else {
++iter->second;
}
iter = pMsgServInfo->user_cnt_map.find(user_id);
if (iter == pMsgServInfo->user_cnt_map.end()) {
pMsgServInfo->user_cnt_map.insert(make_pair(user_id, 1));
pMsgServInfo->cur_user_cnt++;
}
else
{
++iter->second;
}
}
else
{
//用户数减少的情况
pMsgServInfo->cur_conn_cnt--; //先更服务器信息的当前连接数。
UserConnCntMap_t::iterator iter = g_user_conn_cnt_map.find(user_id);
//查找全局用户信息g_user_conn_cnt_map,更新user_id对于的个数,如果为0,更新g_total_online_user_cnt。
if((iter == g_user_conn_cnt_map.end())) {
log("user_id is not exist, id=%u\n", user_id);
}
else
{
if(--iter->second <= 0)
{
g_user_conn_cnt_map.erase(iter);
--g_total_online_user_cnt;
}
}
//查找服务器信息用户信息user_cnt_map,更新user_id对于的个数,如果为0,更新对应的cur_user_cnt。
iter = pMsgServInfo->user_cnt_map.find(user_id);
if (iter == pMsgServInfo->user_cnt_map.end())
{
log("no user_id in MsgServer\n");
}
else
{
if (--iter->second <= 0)
{
pMsgServInfo->cur_user_cnt--;
pMsgServInfo->user_cnt_map.erase(iter);
}
}
}
log("%s:%d, conn_cnt=%u, user_cnt=%u, total_cnt=%u\n", pMsgServInfo->hostname.c_str(),
pMsgServInfo->port, pMsgServInfo->cur_conn_cnt, pMsgServInfo->cur_user_cnt,
g_total_online_user_cnt);
}
}
void CLoginConn::_HandleMsgServRequest(CImPduMsgServRequest* pPdu)
{
log("HandleMsgServReq\n");
// no MessageServer available
if (g_msg_serv_info.size() == 0) {
CImPduMsgServResponse pdu(REFUSE_REASON_NO_MSG_SERVER);
pdu.SetReserved(pPdu->GetReserved());
SendPdu(&pdu);
Close();
return;
}
// return a message server with minimum concurrent connection count
msg_serv_info_t* pMsgServInfo;
uint32_t min_user_cnt = (uint32_t)-1;
map<uint32_t, msg_serv_info_t*>::iterator it_min_conn = g_msg_serv_info.end(),it;
for (it = g_msg_serv_info.begin() ; it != g_msg_serv_info.end(); it++) {
pMsgServInfo = it->second;
if ( (pMsgServInfo->cur_conn_cnt < pMsgServInfo->max_conn_cnt) &&
(pMsgServInfo->cur_conn_cnt < min_user_cnt) &&
(pMsgServInfo->server_type == MSG_SERVER_TYPE_TCP) ) {
it_min_conn = it;
min_user_cnt = pMsgServInfo->cur_conn_cnt;
}
}
if (it_min_conn == g_msg_serv_info.end()) {
log("All TCP MsgServer are full\n");
CImPduMsgServResponse pdu(REFUSE_REASON_MSG_SERVER_FULL);
pdu.SetReserved(pPdu->GetReserved());
SendPdu(&pdu);
} else {
CImPduMsgServResponse pdu(0, it_min_conn->second->ip_addr1.c_str(),
it_min_conn->second->ip_addr2.c_str(), it_min_conn->second->port);
pdu.SetReserved(pPdu->GetReserved());
SendPdu(&pdu);
}
Close(); // after send MsgServResponse, active close the connection
}
void CLoginConn::_HandleUserConnInfo(CImPduUserConnInfo *pPdu)
{
uint32_t user_cnt = pPdu->GetUserCnt();
user_conn_t* user_conn_list = pPdu->GetUserConnList();
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;
pMsgServInfo->cur_user_cnt = user_cnt;
for (uint32_t i = 0; i < user_cnt; i++) {
pMsgServInfo->user_cnt_map.insert(make_pair(user_conn_list[i].user_id, user_conn_list[i].conn_cnt));
UserConnCntMap_t::iterator it_user = g_user_conn_cnt_map.find(user_conn_list[i].user_id);
if(it_user == g_user_conn_cnt_map.end()) {
g_user_conn_cnt_map.insert(make_pair(user_conn_list[i].user_id, 1));
g_total_online_user_cnt++;
} else {
++it_user->second;
}
}
}
log("HandleUserConnInfo, user_cnt=%u, total_user_cnt=%u\n", user_cnt, g_total_online_user_cnt);
}