Creative Commons License
本Blog采用 知识共享署名-非商业性使用-禁止演绎 3.0 Unported许可协议 进行许可。 —— Fox <游戏人生>

游戏人生

游戏人生 != ( 人生 == 游戏 )
站点迁移至:http://www.yulefox.com。请订阅本博的朋友将RSS修改为http://feeds.feedburner.com/yulefox
posts - 62, comments - 508, trackbacks - 0, articles - 7

MMORPG网络模型剖析——网络连接实例分析

Posted on 2008-03-28 01:41 Fox 阅读(3640) 评论(8)  编辑 收藏 引用 所属分类: G游戏编程

Author: Fox

在以前写 MMORPG中游戏世界的构建 时,提到服务器架构的分类。大多数情况下,每一种不同的服务器只会与其对应的一个服务器和多个客户端通信。比如,GameServer(GS)只会与WorldServer(WS)通信,也就是说GS只作为WS的客户端。这次,由于项目需求,新增加了一个SomeServer(SS)作为GS的服务器。

一、SS网络连接分析

由于需要和大量GS建立网络连接,所以SS使用了IOCP模型。鉴于 上一次写IOCP 时遭到 Kevin TX的鄙视,所以决定今天多写一点。SS的网络模型大致如下:

0、服务器主线程启动;

1、初始化Winsock,SDK func: WSAStartup ();

2、创建一个使用overlapped I/O的socket,SDK func: WSASocket();

3、绑定端口,将本地地址与创建的socket关联起来,SDK func: bind();

4、创建IOCP对象,SDK func: CreateIoCompletionPort();

5、创建工作者线程,CreateWorkerThreads();

6、开始监听,SDK func: listen();

7、接受客户端连接,SDK func: WSAAccept();

8、当有新的连接请求到达时,将WSAAccept返回的对应的客户端socket关联到IOCP;

9、处理WSASend() or WSARecv()。

在实际处理时,可能会根据需要建立额外的线程处理socketopt命令,甚至建立专门处理WSAccept的线程。

关于工作者线程WorkerThread:

通过GetQueuedCompletionStatus(),获取I/O类型和对应的socket,如果为接收则通知接收完成并继续新的WSARecv(),如果为发送则通知发送完成。

二、GS网络连接分析

GS上对于SS客户端采用的是WSAEventSelect模型,通过网络事件触发相应操作。

0、服务器主线程启动;

1、初始化Winsock,SDK func: WSAStartup ();

2、创建一个使用overlapped I/O的socket,SDK func: WSASocket();

4、绑定端口,将本地地址与创建的socket关联起来,SDK func: bind();

5、创建网络事件,SDK func: CreateEvent();

6、设置网络事件的响应,SDK func: WSAEventSelect();

7、等待网络事件,SDK func: WSAWaitForMultipleEvents();

8、分析网络事件类型并处理,SDK func: WSAEnumNetworkEvents()。

这里之所以采用CreateEvent而不是WSACreateEvent,是因为由CreateEvent创建的事件允许为auto reset的,而WSACreateEvent创建的事件是manually reset的。

三、实现过程中的小插曲

在GS的客户端实现中遇到几个问题。

首先是在消息处理上,GS发到SS的消息,SS并没有完全接受到,而SS发送到GS的消息一切正常。后来跟了一下SS消息队列,发现SS居然可以收到GS发送到WS的消息!然后就在GS上找原因,原来是WS在和SS共用消息队列,以前GS只对应一个服务器,无所谓共用。现在加了SS,自然要分开处理,否则WS和SS都可能收到发给对方的消息。

后面一个bug从周一开始已经强奸了我四天了。即使SS已经关闭,WSAEnumNetworkEvents返回的事件对应FD_CONNECT的iErrorCode值始终为0。因为中间涉及到多线程和多个服务器分别对应的客户端,连接到WS的没有问题,就是SS的客户端有问题。到今天上午为止,我已经把GS的网络处理逻辑全部静态分析了一遍,没有任何发现。临近中午吃饭的时候,不得已只好用WS的客户端socket去连接SS,居然出现同样问题!而我的WS和SS都是放在我机器上的,这样来看,就只有端口不同了!

果然,当我把SS的监听端口修改之后,问题解决了。因为我是使用8088端口监听GS连接的。当我把端口换成80,同样问题再次出现,而且SS无法通过80端口监听。

接下来提几个问题:

1、 被卡巴斯基监控的端口8088和服务器开启的监听端口8088有什么联系?为什么没有冲突?卡巴仅仅只是从该端口获取数据吗?为什么网络事件的FD_CONNECT的对应iErrorCode为0(表明连接成功)?

2、 80是常规http端口,它与8080、8088这些http端口的区别在哪儿?这些端口绑定成功与否的原则是什么?

 

PS:文中关于IOCP和WSAEventSelect模型更为详细的实现,可以参考 Network Programming for Microsoft Windows 2nd 的第五章:Winsock I/O Methods。

最后写完了,发觉自己写的很垃圾,完全就是记流水帐。转念一想,为什么呢?自己基础不扎实嘛,第一次接触IOCP和网络模型,也就这样了。

今天太晚了,要睡了,上面的问题明天再考虑吧 J

Feedback

# re: MMORPG网络模型剖析——网络连接实例分析  回复  更多评论   

2008-03-28 08:22 by cppexplore
系统调用不检查返回值?系统没有log机制?
监控一个冲突一个的话,还有什么监控的必要。
这些端口没什么区别,linux上1024下的是预留端口,需要root帐号才能bind。
bind成功的标志就是bind函数返回成功,呵呵。

# re: MMORPG网络模型剖析——网络连接实例分析  回复  更多评论   

2008-03-28 09:28 by Kevin Lynx
1. "如果为接收则完成WSARecv()" 不知道这句话是什么意思。异步IO中当上层被内核通知IO操作完成时,已经表明该操作完成,即之前提交的WSARecv操作已经完成,可以直接从参数中获取数据(直接拿来用即可)。
2. 刚才看了下代码,确认了一下,客户端创建socket调用的是socket,因为将其与一个event对象关联了起来,所以其所有操作默认变为非阻塞的。(所以send, recv之类的操作有时候会返回WSAEWOULDBLOCK)
3."因为由CreateEvent创建的事件是auto reset的"说的有失偏颇,因为这个函数可以指定是否是manual set的。:)
4.我很会挑fox的毛病。:D。

# re: MMORPG网络模型剖析——网络连接实例分析  回复  更多评论   

2008-03-28 11:01 by Fox
1、是指继续完成新的wsarecv。
2、我的理解是socket和wsasocet的区别只是wsasocket可以自由决定是否使用重叠I/O,和阻塞与否没有关系。
3、恩,应该是允许auto才对。
4、你让我不得不把一个本来认为理解了的问题思考再思考,的确有压力!

# re: MMORPG网络模型剖析——网络连接实例分析  回复  更多评论   

2008-03-28 15:36 by 饭中淹
这个,分析到最后,怎么就分析到WINSOCK上去了呢。。。。抽象的分析是不应该扯上os和api的。

# re: MMORPG网络模型剖析——网络连接实例分析  回复  更多评论   

2008-03-28 16:42 by RichardHe
大哥.你们现在在做什么游戏吗??有什么运营的了没?

# re: MMORPG网络模型剖析——网络连接实例分析  回复  更多评论   

2008-03-28 16:42 by Kevin Lynx
@饭中淹
饭叔叔说得对! :D

@fox
"1、是指继续完成新的wsarecv。"
继续发出recv的异步请求
"4.....的确有压力!" :D 压力产生动力

# re: MMORPG网络模型剖析——网络连接实例分析[未登录]  回复  更多评论   

2008-03-29 18:38 by noname
@Kevin Lynx
为什么每次称饭中淹为饭叔叔,他有这么大了吗?

# re: MMORPG网络模型剖析——网络连接实例分析  回复  更多评论   

2008-03-29 22:17 by Kevin Lynx
@noname

:D

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理