MMORPG大型游戏设计与开发(part3 of net)
這一部分需要向大家介紹的是服務(wù)器的select以及收發(fā)包的具體流程,從核心代碼功能上分析網(wǎng)絡(luò)交互具體過(guò)程。
首先大家要看第二部分(part2 of net)的代碼結(jié)構(gòu)圖,因?yàn)樵诮酉聛?lái)的流程過(guò)程中會(huì)用到其中模塊的名稱(chēng),若是不知道大致的功能那么接下來(lái)的解說(shuō)可能就成為天書(shū)了。
總體流程為:服務(wù)器管理器初始化并創(chuàng)建主套接字連接,進(jìn)入主循環(huán)等待新連接(select),如果有新的連接則將新連接加入連接管理器。不管有沒(méi)有新的連接,循環(huán)會(huì)依次處理連接的異常->輸入流->輸出流->命令處理。其中異常即連接包發(fā)送錯(cuò)誤的處理,輸入流即套接字輸入流中如果大小長(zhǎng)度不為空則重新拼接包,輸出流進(jìn)行包的拼接,并將未發(fā)送的流進(jìn)行發(fā)送,命令處理其實(shí)是對(duì)輸入流的處理,處理(handler)發(fā)送過(guò)來(lái)的包。
以下詳細(xì)說(shuō)明這幾個(gè)流程從代碼上的實(shí)現(xiàn),以及所在的模塊。
1、? 服務(wù)器管理器初始化(servermanager)
bool ServerManager::init() {__ENTER_FUNCTIONserversocket_ = new pap_server_common_net::Socket(g_config.billing_info_.port_);Assert(serversocket_);serversocket_->set_nonblocking();socketid_ = serversocket_->getid(); Assert(socketid_ != SOCKET_INVALID); FD_SET(socketid_, &readfds_[kSelectFull]); FD_SET(socketid_, &exceptfds_[kSelectFull]); minfd_ = maxfd_ = socketid_; timeout_[kSelectFull].tv_sec = 0; timeout_[kSelectFull].tv_usec = 0; threadid_ = pap_common_sys::get_current_thread_id(); uint16_t i; for (i = 0; i < OVER_SERVER_MAX; ++i) { serverhash_[i] = ID_INVALID; } return true; __LEAVE_FUNCTION return false; }2、? 服務(wù)器管理器進(jìn)入主循環(huán)(servermanager)
?
void ServerManager::loop() {__ENTER_FUNCTIONwhile (isactive()) {bool result = false; try { result = select(); Assert(result); //ERRORPRINTF("select"); result = processexception(); Assert(result); //ERRORPRINTF("processexception"); result = processinput(); Assert(result); //ERRORPRINTF("processinput"); result = processoutput(); Assert(result); //ERRORPRINTF("processoutput"); } catch(...) { } try { result = processcommand(); Assert(result); //ERRORPRINTF("processcommand"); } catch(...) { } try { result = heartbeat(); Assert(result); } catch(...) { } } __LEAVE_FUNCTION } loop?
3、? 服務(wù)器線(xiàn)程進(jìn)入select模式
?
bool ServerManager::select() {__ENTER_FUNCTIONtimeout_[kSelectUse].tv_sec = timeout_[kSelectFull].tv_sec;timeout_[kSelectUse].tv_usec = timeout_[kSelectFull].tv_usec;readfds_[kSelectUse] = readfds_[kSelectFull]; writefds_[kSelectUse] = writefds_[kSelectFull]; exceptfds_[kSelectUse] = exceptfds_[kSelectFull]; pap_common_base::util::sleep(100); int32_t result = SOCKET_ERROR; try { result = pap_common_net::socket::Base::select( maxfd_ + 1, &readfds_[kSelectUse], &writefds_[kSelectUse], &exceptfds_[kSelectUse], &timeout_[kSelectUse]); Assert(result != SOCKET_ERROR); } catch(...) { g_log->fast_save_log(kBillingLogFile, "ServerManager::select have error, result: %d", result); } return true; __LEAVE_FUNCTION return false; } select?
4、? 服務(wù)器線(xiàn)程進(jìn)行異常處理
?
bool ServerManager::processexception() {__ENTER_FUNCTIONif (SOCKET_INVALID == minfd_ && SOCKET_INVALID == maxfd_)return true; uint16_t connectioncount = billingconnection::Manager::getcount(); billingconnection::Server* serverconnection = NULL; uint16_t i; for (i = 0; i < connectioncount; ++i) { if (ID_INVALID == connectionids_[i]) continue; serverconnection = g_connectionpool->get(connectionids_[i]); Assert(serverconnection); int32_t socketid = serverconnection->getsocket()->getid(); if (socketid_ == socketid) { Assert(false); continue; } if (FD_ISSET(socketid, &exceptfds_[kSelectUse])) { removeconnection(serverconnection); } } return true; __LEAVE_FUNCTION return false; } processexception?
5、? 服務(wù)器線(xiàn)程進(jìn)行輸入流處理
?
bool ServerManager::processinput() {__ENTER_FUNCTIONif (SOCKET_INVALID == minfd_ && SOCKET_INVALID == maxfd_)return true; //no connection uint16_t i; if (FD_ISSET(socketid_, &readfds_[kSelectUse])) { for (i = 0; i < kOneStepAccept; ++i) { if (!accept_newconnection()) break; } } uint16_t connectioncount = billingconnection::Manager::getcount(); for (i = 0; i < connectioncount; ++i) { if (ID_INVALID == connectionids_[i]) continue; billingconnection::Server* serverconnection = NULL; serverconnection = g_connectionpool->get(connectionids_[i]); Assert(serverconnection); int32_t socketid = serverconnection->getsocket()->getid(); if (socketid_ == socketid) continue; if (FD_ISSET(socketid, &readfds_[kSelectUse])) { //read information if (serverconnection->getsocket()->iserror()) { removeconnection(serverconnection); } else { try { if (!serverconnection->processinput()) removeconnection(serverconnection); } catch(...) { removeconnection(serverconnection); } } } } return true; __LEAVE_FUNCTION return false; } processinput?
6、? 服務(wù)器線(xiàn)程進(jìn)行輸出流處理
?
bool ServerManager::processoutput() {__ENTER_FUNCTIONif (SOCKET_INVALID == maxfd_&& SOCKET_INVALID == minfd_)return false; uint16_t i; uint16_t connectioncount = billingconnection::Manager::getcount(); for (i = 0; i < connectioncount; ++i) { if (ID_INVALID == connectionids_[i]) continue; billingconnection::Server* serverconnection = NULL; serverconnection = g_connectionpool->get(connectionids_[i]); Assert(serverconnection); int32_t socketid = serverconnection->getsocket()->getid(); if (socketid_ == socketid) continue; if (FD_ISSET(socketid, &writefds_[kSelectUse])) { if (serverconnection->getsocket()->iserror()) { removeconnection(serverconnection); } else { try { if (!serverconnection->processoutput()) removeconnection(serverconnection); } catch(...) { removeconnection(serverconnection); } } } } return true; __LEAVE_FUNCTION return false; } processoutput?
7、? 服務(wù)器線(xiàn)程進(jìn)行命令處理
bool ServerManager::processcommand() {__ENTER_FUNCTIONif (SOCKET_INVALID == maxfd_&& SOCKET_INVALID == minfd_)return false; uint16_t i; uint16_t connectioncount = billingconnection::Manager::getcount(); for (i = 0; i < connectioncount; ++i) { if (ID_INVALID == connectionids_[i]) continue; billingconnection::Server* serverconnection = NULL; serverconnection = g_connectionpool->get(connectionids_[i]); //serverconnection = &billing_serverconnection_; Assert(serverconnection); int32_t socketid = serverconnection->getsocket()->getid(); if (socketid_ == socketid) continue; if (serverconnection->getsocket()->iserror()) { removeconnection(serverconnection); } else { //connection is ok try { if (!serverconnection->processcommand(false)) removeconnection(serverconnection); } catch(...) { removeconnection(serverconnection); } } } return true; __LEAVE_FUNCTION return false; } processcommand?
下一部分,我將講解在網(wǎng)絡(luò)部分一些重要的代碼塊。
轉(zhuǎn)載于:https://www.cnblogs.com/liuzhi/p/4084565.html
總結(jié)
以上是生活随笔為你收集整理的MMORPG大型游戏设计与开发(part3 of net)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 警惕使用WebClient.Downlo
- 下一篇: Oracle 11g 建表 表名大小写问