这一部分需要向大家介绍的是服务器的select以及收发包的具体流程,从核心代码功能上分析网络交互具体过程。

  首先大家要看第二部分(part2 of net)的代码结构图,因为在接下来的流程过程中会用到其中模块的名称,若是不知道大致的功能那么接下来的解说可能就成为天书了。

  总体流程为:服务器管理器初始化并创建主套接字连接,进入主循环等待新连接(select),如果有新的连接则将新连接加入连接管理器。不管有没有新的连接,循环会依次处理连接的异常->输入流->输出流->命令处理。其中异常即连接包发送错误的处理,输入流即套接字输入流中如果大小长度不为空则重新拼接包,输出流进行包的拼接,并将未发送的流进行发送,命令处理其实是对输入流的处理,处理(handler)发送过来的包。

  以下详细说明这几个流程从代码上的实现,以及所在的模块。

  1、  服务器管理器初始化(servermanager)

bool ServerManager::init() {
__ENTER_FUNCTION
serversocket_ =
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 = ;
timeout_[kSelectFull].tv_usec = ;
threadid_ = pap_common_sys::get_current_thread_id();
uint16_t i;
for (i = ; i < OVER_SERVER_MAX; ++i) {
serverhash_[i] = ID_INVALID;
}
return true;
__LEAVE_FUNCTION
return false;
}

  2、  服务器管理器进入主循环(servermanager)

void ServerManager::loop() {
__ENTER_FUNCTION
while (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、  服务器线程进入select模式

bool ServerManager::select() {
__ENTER_FUNCTION
timeout_[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();
int32_t result = SOCKET_ERROR;
try {
result = pap_common_net::socket::Base::select(
maxfd_ + ,
&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、  服务器线程进行异常处理

bool ServerManager::processexception() {
__ENTER_FUNCTION
if (SOCKET_INVALID == minfd_ && SOCKET_INVALID == maxfd_)
return true;
uint16_t connectioncount = billingconnection::Manager::getcount();
billingconnection::Server* serverconnection = NULL;
uint16_t i;
for (i = ; 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、  服务器线程进行输入流处理

bool ServerManager::processinput() {
__ENTER_FUNCTION
if (SOCKET_INVALID == minfd_ && SOCKET_INVALID == maxfd_)
return true; //no connection
uint16_t i;
if (FD_ISSET(socketid_, &readfds_[kSelectUse])) {
for (i = ; i < kOneStepAccept; ++i) {
if (!accept_newconnection()) break;
}
}
uint16_t connectioncount = billingconnection::Manager::getcount();
for (i = ; 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、  服务器线程进行输出流处理

bool ServerManager::processoutput() {
__ENTER_FUNCTION
if (SOCKET_INVALID == maxfd_&& SOCKET_INVALID == minfd_)
return false;
uint16_t i;
uint16_t connectioncount = billingconnection::Manager::getcount();
for (i = ; 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、  服务器线程进行命令处理

bool ServerManager::processcommand() {
__ENTER_FUNCTION
if (SOCKET_INVALID == maxfd_&& SOCKET_INVALID == minfd_)
return false;
uint16_t i;
uint16_t connectioncount = billingconnection::Manager::getcount();
for (i = ; 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

  下一部分,我将讲解在网络部分一些重要的代码块。

MMORPG大型游戏设计与开发(part3 of net)的更多相关文章

  1. MMORPG大型游戏设计与开发(概述)updated

    1.定义 MMORPG,是英文Massive(或Massively)Multiplayer Online Role-PlayingGame的缩写,即大型多人在线角色扮演游戏. 2.技术与知识 在这系列 ...

  2. MMORPG大型游戏设计与开发(UI SYSTEM SHOW)

    接下来一段时间,这些文件可能不再更新,期间我会学习和掌握一些前端知识.虽然我非常欣赏剑侠网络版叁和九阴真经的画面,但是那是一个庞大的游戏引擎,一般人是无法窥伺的,除非你是天才而且要拥有机器毫无中断的毅 ...

  3. MMORPG大型游戏设计与开发(服务器 游戏场景 核心详述)

    核心这个词来的是多么的高深,可能我们也因为这个字眼望而却步,也就很难去掌握这部分的知识.之所以将核心放在最前面讲解,也可以看出它真的很重要,希望朋友们不会错过这个一直以来让大家不熟悉的知识,同我一起进 ...

  4. MMORPG大型游戏设计与开发(游戏服务器 游戏场景 概述 updated)

    我们在玩游戏的时候,我们进入游戏后第一眼往往都是看到游戏世界中的场景,当然除了个别例外,因为那些游戏将游戏场景隐藏了起来,如文字游戏中的地点一样.既然我们接触了游戏世界的核心,那么作为核心的场景又包括 ...

  5. MMORPG大型游戏设计与开发(客户端架构 part8 of vegine)

    脚本模块是游戏设计中争论比较多的话题,那是因为作为脚本本身所带来的利弊.其实这都无关紧要,取舍是人必须学会的一项技能,如果你不会取舍那么就让趋势给你一个满意的答复.自从魔兽世界以及传奇(世界)问世以来 ...

  6. MMORPG大型游戏设计与开发(客户端架构 part3 of vegine)

    无论在何处在什么地方,我们都或多或少的接触到数学知识.特别是在客户端中,从打开界面的那一刻起就有太多与数学扯上的关联,如打开窗口的大小,窗口的位置,窗口里面的元件对象,以及UI的坐标等等.而在进入游戏 ...

  7. MMORPG大型游戏设计与开发(客户端架构 part12 of vegine)

    在游戏中的交互过程中输入是一个必不可少的过程,比如登陆的时候需要用户输入用户名与密码,就算是单机游戏很多时候也要求用户输入一个用户名作为存档的依据.网络游戏中没有了输入,只用鼠标来交互是不切实际的,因 ...

  8. MMORPG大型游戏设计与开发(part1 of net)

    网络模块的设计,是大型多人在线游戏中比较重要的一部分.我之所以将网络模块放到最前面,是因为许许多多的开发者面对这一块的时候充满了疑惑,而且也觉得很神秘和深奥.这些我们面对到的困难,其实是由于我们对这方 ...

  9. MMORPG大型游戏设计与开发(规范)

    一件事如果没有规范.章法,那么做这件事起来往往会遇到许多难题,特别是在多人协作的时候,没有到规范通常让每个人多多少少都面临着头疼的困难.举个例子,多个人要做一桌美味的饺子,有买材料.做面皮.弄肉(菜) ...

随机推荐

  1. Code First :使用Entity. Framework编程(3) ----转发 收藏

    第三章 对属性使用约定和配置 在第2章,对Code First的约定以及如何通过配置覆写默认约定行为进行了大致的介绍.学习了如何使用Data Annotations进行配置,也学习了如何使用Fluen ...

  2. 《javascript权威指南》读书笔记(连载)

    这是一篇很长的博客 终于把权威指南给买回来了,之前一直犹豫,第一:书太厚,怕买了不能坚持看完.第二:觉得太贵,最少100¥.现在实习也能发点工资了,给自己定了一个志愿:把一个月的工资用于买书.这么一想 ...

  3. 记录一下dotnetcore.1.0.0-VS2015Tools.preview2安装不上的问题

    错误提示:未指定错误 解决方案: 从这里下载:https://visualstudiogallery.msdn.microsoft.com/32f1fa1b-cdd5-4bd3-8f51-cd8f09 ...

  4. 对比MS Test与NUnit Test框架

    前言: 项目中进行Unit Test时,肯定会用到框架,因为这样能够更快捷.方便的进行测试. .Net环境下的测试框架非常多,在这里只是对MS Test和NUnit Test进行一下比较, 因为这两个 ...

  5. openlayers方法总结

    openlayers中的一些方法:OpenLayers.Layer::initialize:创建层Div,注册事件:destroy:注销:clone:克隆当前层:setName:设置层name:add ...

  6. iOS使用Charles(青花瓷)抓包并篡改返回数据图文详解

    写本文的契机主要是前段时间有次用青花瓷抓包有一步忘了,在网上查了半天也没找到写的完整的教程,于是待问题解决后抽时间截了图,自己写一遍封存在博客园中以便以后随时查阅. charles又名青花瓷,在iOS ...

  7. jsp声称的java文件位置

    想找到JSP生成的字节码文件还是Java文件,这得看你加载Web应用是自己配置的Tomcat还是加载到Eclipse默认路径下:先说Eclipse默认路径下的吧,其路径为:你的eclipse存放工程的 ...

  8. swift 中手势的使用

    swift 中手势的使用 /**点击手势*/ func tapGestureDemo() { //建立手势识别器 let gesture = UITapGestureRecognizer(target ...

  9. OC点语法和变量作用域

    OC点语法和变量作用域 一.点语法 (一)认识点语法 声明一个Person类: #import <Foundation/Foundation.h> @interface Person : ...

  10. 【代码笔记】iOS-抽屉效果的实现

    一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController ...