文章标题
2017-11-03 18:45
351 查看
msg_serve的分析
msg的源代码开始就是加载全局的配置文件 初始化全局的list在事件eventloop之前有一系列的代码:
//连接msg_serve init_msg_conn(); init_http_conn(); init_file_serv_conn(file_server_list, file_server_count); init_db_serv_conn(db_server_list2, db_server_count2, concurrent_db_conn_cnt); init_login_serv_conn(login_server_list, login_server_count, ip_addr1, ip_addr2, listen_port, max_conn_cnt); init_route_serv_conn(route_server_list, route_server_count); printf("now enter the event loop...\n"); netlib_eventloop();
这里面有很多的初始化代码,结构都相似,所以我就找几个进行分析,其它的就不分析了
init_file_conn() init_http_conn() init_login_serv_con()的使用
init_file_conn()的使用
void init_file_serv_conn(serv_info_t* server_list, uint32_t server_count) { g_file_server_list = server_list; g_file_server_count = server_count; serv_init<CFileServConn>(g_file_server_list, g_file_server_count); netlib_register_timer(file_server_conn_timer_callback, NULL, 1000); s_file_handler = CFileHandler::getInstance(); }
注意里面调用了serv_init()函数,serv_init()代码是一个模板类,它的结构就是:
//serv_init template <class T> void serv_init(serv_info_t* server_list, uint32_t server_count) { for (uint32_t i = 0; i < server_count; i++) { T* pConn = new T(); pConn->Connect(server_list[i].server_ip.c_str(), server_list[i].server_port, i); server_list[i].serv_conn = pConn; server_list[i].idle_cnt = 0; server_list[i].reconnect_cnt = MIN_RECONNECT_CNT / 2; } }
可以看到就是服务器主动连接服务器 file_serve 好的
注意这是一个函数模板,在这里class T 的类型就是 cfileservcon的类型,
那么展开的代码就是
void serv_init(serv_info_t *server_list,uint32_t server_count){ for(int i=0;i<serve_count;i++){ cfileservcon pcon=new cfileservcon(); pcon->connect(sreve_list[i].serve_ip,c_str); } }
所以下载代码跳转到 pcon->connnect()函数上
代码就是:
void CFileServConn::Connect(const char* server_ip, uint16_t server_port, uint32_t idx) { log("Connecting to FileServer %s:%d\n", server_ip, server_port); m_serv_idx = idx; m_handle = netlib_connect(server_ip, server_port, imconn_callback, (void*)&g_file_server_conn_map); if (m_handle != NETLIB_INVALID_HANDLE) { g_file_server_conn_map.insert(make_pair(m_handle, this)); } }
cfileserveconn::connect就是调用netlib_connect()
g_file_server_conn_map.insert(make_pair(m_handle,this));保存cfileconnserve的对象cfileserveconn::connect()之后就是调用cbasesocket的connect()
之后调用netlib_connect();
net_handle_t netlib_connect( const char* server_ip, uint16_t port, callback_t callback, void* callback_data) { CBaseSocket* pSocket = new CBaseSocket(); if (!pSocket) return NETLIB_INVALID_HANDLE; net_handle_t handle = pSocket->Connect(server_ip, port, callback, callback_data); if (handle == NETLIB_INVALID_HANDLE) delete pSocket; return handle; }
可以看到它创建了casesocket对象和调用了psocket->connect()注意里面的回调函数callback
psocket->connect()的实际使用的情况
et_handle_t CBaseSocket::Connect(const char* server_ip, uint16_t port, callback_t callback, void* callback_data) { log("CBaseSocket::Connect, server_ip=%s, port=%d\n", server_ip, port); m_remote_ip = server_ip; m_remote_port = port; m_callback = callback; m_callback_data = callback_data; m_socket = socket(AF_INET, SOCK_STREAM, 0); if (m_socket == INVALID_SOCKET) { log("socket failed, err_code=%d\n", _GetErrorCode()); return NETLIB_INVALID_HANDLE; } _SetNonblock(m_socket); _SetNoDelay(m_socket); sockaddr_in serv_addr; _SetAddr(server_ip, port, &serv_addr); int ret = connect(m_socket, (sockaddr*)&serv_addr, sizeof(serv_addr)); if ( (ret == SOCKET_ERROR) && (!_IsBlock(_GetErrorCode())) ) { log("connect failed, err_code=%d\n", _GetErrorCode()); closesocket(m_socket); return NETLIB_INVALID_HANDLE; } m_state = SOCKET_STATE_CONNECTING; AddBaseSocket(this); CEventDispatch::Instance()->AddEvent(m_socket, SOCKET_ALL); return (net_handle_t)m_socket; }
这里将m_socket对象加入事件机制,之后调用event_loop()的时候就开始轮询对应的事件
需要指出的是:连接服务器、接受连接、收取数据解包、发送数据这四个模块是一个完整的网路库必须具有的东西。这篇文章和上一篇文章完整地介绍了这四个模块,而TeamTalk的实现手法也是目前主流网络库的通用做法。如果从事服务器开发,必须熟练掌握这里面的具体每个细节。而teamtalk服务器这种分布式架构设计的思想也是非常值得学习和借鉴的。