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大型游戏设计与开发(规范)
一件事如果没有规范.章法,那么做这件事起来往往会遇到许多难题,特别是在多人协作的时候,没有到规范通常让每个人多多少少都面临着头疼的困难.举个例子,多个人要做一桌美味的饺子,有买材料.做面皮.弄肉(菜) ...
随机推荐
- Python multi-thread 多线程 print 如何避免print的结果混乱
multithread如何写 这是我第一次写multithread,所以就是照着例子学,下面是我用来学的例子 来自于”Automate the boring stuff with Python”的15 ...
- 为Titanium创建自己的安卓推送模块
在手机应用中,推送是一个非常重要的功能.相对来说ios应用的推送功能很容易做,因为它统一都是用苹果的APNS服务实现的.但安卓这边就比较混乱了,虽然谷歌也推出了类似苹果的官方推送服务,但由于谷歌的服务 ...
- sizzle源码分析 (3)sizzle 不能快速匹配时 选择器流程
如果快速匹配不成功,则会进入sizzle自己的解析顺序,主要流程如下: 总结流程如下: (1)函数sizzle是sizzle的入口,如果能querySelectAll快速匹配,则返回结果 (2)函数S ...
- SharePoint 2013 日历视图兼容性问题
在IE11上访问SharePoint 2013 calendar视图,发现加入兼容性视图以后访问,正常,如下图: 不加入兼容性视图IE11访问,出现兼容性问题,如下图: 因为有些环境有问题,有些环境没 ...
- 为什么你找不到优秀的GISer?
每年的三四月是招聘的黄金时节,故有金三银四的说法.求贤纳才对于处在发展上升期的公司来说,是全年性的常态化工作.只是这俩月市场上求职者数量较别的月份多.基数大了,淘到金子的概率自然会增加.大部分公司的伯 ...
- DevExpress 13.1.8全面支持VS2013
界面套包DevExpress 13.1.8重磅来袭.从这个版本开始所有.NET控件均正式支持VS2013,当然还有很多其他更新,下面是部分更新内容: DevExpress所有.NET控件: 正式支持V ...
- 【C语言】C语言运算符
目录: [算术运算符] [自增运算符] [自减运算符] [关系运算符] [逻辑运算符] [三目运算符] [sizeof运算符] · 作用 1.算术运算符 +(加).-(减).*(乘)./(除).%(取 ...
- 【代码笔记】iOS-点击一个按钮会出现多个按钮的动画效果
一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController ...
- 自己用js写的日历(在考勤中使用,显示员工的日期的考勤情况)
1.HTML部分 <div id="AttendanceDataDetailDiv"> <div class="A_close"> &l ...
- Xcode常用快捷键的使用
熟练使用Xcode的一些快捷方式,会大大加快项目开发的速度.