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
。