MMORPG大型游戏设计与开发(part3 of net)
这一部分需要向大家介绍的是服务器的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)的更多相关文章
- MMORPG大型游戏设计与开发(概述)updated
1.定义 MMORPG,是英文Massive(或Massively)Multiplayer Online Role-PlayingGame的缩写,即大型多人在线角色扮演游戏. 2.技术与知识 在这系列 ...
- MMORPG大型游戏设计与开发(UI SYSTEM SHOW)
接下来一段时间,这些文件可能不再更新,期间我会学习和掌握一些前端知识.虽然我非常欣赏剑侠网络版叁和九阴真经的画面,但是那是一个庞大的游戏引擎,一般人是无法窥伺的,除非你是天才而且要拥有机器毫无中断的毅 ...
- MMORPG大型游戏设计与开发(服务器 游戏场景 核心详述)
核心这个词来的是多么的高深,可能我们也因为这个字眼望而却步,也就很难去掌握这部分的知识.之所以将核心放在最前面讲解,也可以看出它真的很重要,希望朋友们不会错过这个一直以来让大家不熟悉的知识,同我一起进 ...
- MMORPG大型游戏设计与开发(游戏服务器 游戏场景 概述 updated)
我们在玩游戏的时候,我们进入游戏后第一眼往往都是看到游戏世界中的场景,当然除了个别例外,因为那些游戏将游戏场景隐藏了起来,如文字游戏中的地点一样.既然我们接触了游戏世界的核心,那么作为核心的场景又包括 ...
- MMORPG大型游戏设计与开发(客户端架构 part8 of vegine)
脚本模块是游戏设计中争论比较多的话题,那是因为作为脚本本身所带来的利弊.其实这都无关紧要,取舍是人必须学会的一项技能,如果你不会取舍那么就让趋势给你一个满意的答复.自从魔兽世界以及传奇(世界)问世以来 ...
- MMORPG大型游戏设计与开发(客户端架构 part3 of vegine)
无论在何处在什么地方,我们都或多或少的接触到数学知识.特别是在客户端中,从打开界面的那一刻起就有太多与数学扯上的关联,如打开窗口的大小,窗口的位置,窗口里面的元件对象,以及UI的坐标等等.而在进入游戏 ...
- MMORPG大型游戏设计与开发(客户端架构 part12 of vegine)
在游戏中的交互过程中输入是一个必不可少的过程,比如登陆的时候需要用户输入用户名与密码,就算是单机游戏很多时候也要求用户输入一个用户名作为存档的依据.网络游戏中没有了输入,只用鼠标来交互是不切实际的,因 ...
- MMORPG大型游戏设计与开发(part1 of net)
网络模块的设计,是大型多人在线游戏中比较重要的一部分.我之所以将网络模块放到最前面,是因为许许多多的开发者面对这一块的时候充满了疑惑,而且也觉得很神秘和深奥.这些我们面对到的困难,其实是由于我们对这方 ...
- MMORPG大型游戏设计与开发(规范)
一件事如果没有规范.章法,那么做这件事起来往往会遇到许多难题,特别是在多人协作的时候,没有到规范通常让每个人多多少少都面临着头疼的困难.举个例子,多个人要做一桌美味的饺子,有买材料.做面皮.弄肉(菜) ...
随机推荐
- jshint配置(js检查)
JSHint的选项配置 asi 如果是真,JSHint会无视没有加分号的行尾,自动补全分号一直是Javascript很有争议的一个语法特性.默认,JSHint会要求你在每个语句后面加上分号,但是如果你 ...
- ArcGIS Server开发实践之【Search Widget工具查询本地地图服务】
加载本地地图服务,并实现要素的查询.(不足之处还请指点)具体代码如下: <!DOCTYPE html> <html dir="ltr"> <head& ...
- Aurelia – 模块化,简单,可测试的 JS 框架
Aurelia 是下一代 JavaScript 客户端框架,利用简单的约定来激发你的创造力.凭借其强大的专注于开发经验, Aurelia 可以使您不仅创造惊人的应用程序,同时也享受这个过程.它经过精心 ...
- Autodesk Cloud Accelerator Program 开始报名
如果你没有注意到这个消息,那你就会错过一个前往旧金山和硅谷工程师一起工作数周的机会. 摘要一下: 时间: 1月10前提交你的提案,3月飞往旧金山 地点: 旧金山. 包住宿哦~ 不过,既然要去美国,既然 ...
- Web自动化测试 Selenium 3/3 https的配置
Https的信任问题处理 具体步骤如下(以demo为例) 1) ./ca.sh : 使用默认的服务器192.168.1.1的证书 ./ca.sh IP : 使用IP设置的证书 2) 以上运行后把 ge ...
- android https正确调用方案(防中间人劫持)
以下内容为原创,欢迎转载,转载请注明 来自博客园:http://www.cnblogs.com/joey-hua/p/4971380.html 1.劫持https接口 很多android客户端虽然使用 ...
- Android Builder模式在开发中的应用
最近在学习图片加载框架Glide的时候,被他精简的写法震惊了.一句话,就可以搞定. Glide.with(mContext) .load(url) .centerCrop() .placeholder ...
- SwipeBackActivity 的使用
1.SwipeBackLayout 项目地址:https://github.com/ikew0ng/SwipeBackLayout 2.用法 android studio compile 'me.i ...
- 开发https应用
开发https应用 SSL, 或者Secure Socket Layer,是一种允许web浏览器和web服务器通过一个安全的连接进行交流的技术.这意味着将被发送的数据在一端被翻译成密码,传送出去,然后 ...
- C语言退出多层嵌套循环技巧
由于break语句只能影响它的最内层循环,要想立即从深层嵌套循环中退出,有哪些方法呢? 1.使用goto语句: while(condition1) { while(condition2) { whil ...