﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-浩毛的博客-随笔分类-服务器开发</title><link>http://www.cppblog.com/jaxe/category/11790.html</link><description>FreeBSD、Linux下高性能网络游戏服务器开发(QQ275051)</description><language>zh-cn</language><lastBuildDate>Thu, 11 Aug 2011 13:34:54 GMT</lastBuildDate><pubDate>Thu, 11 Aug 2011 13:34:54 GMT</pubDate><ttl>60</ttl><item><title>一个利用AOI计算做的 NPC跟随的3D服务器DEMO</title><link>http://www.cppblog.com/jaxe/archive/2011/08/11/153037.html</link><dc:creator>浩毛</dc:creator><author>浩毛</author><pubDate>Thu, 11 Aug 2011 03:22:00 GMT</pubDate><guid>http://www.cppblog.com/jaxe/archive/2011/08/11/153037.html</guid><wfw:comment>http://www.cppblog.com/jaxe/comments/153037.html</wfw:comment><comments>http://www.cppblog.com/jaxe/archive/2011/08/11/153037.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/jaxe/comments/commentRss/153037.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jaxe/services/trackbacks/153037.html</trackback:ping><description><![CDATA[最近做了个DEMO,飞机追飞机的.<br />利用AOI模块产生的enterAOI,LeaveAOI事件 触发NPC追随玩家<br /><br />顺便也测试下服务器实体的欧拉角计算<br /><br /><br />先运行RegionApp.exe<br />然后再运行ClientDemo<br /><br />WSAD 前后左右 J上K下<br /><br />客户端做的很简单..., 支持多开...<br /><br /><a title="下载DEMO" href="/Files/jaxe/3DServerDemo.rar">下载DEMO</a><img src ="http://www.cppblog.com/jaxe/aggbug/153037.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jaxe/" target="_blank">浩毛</a> 2011-08-11 11:22 <a href="http://www.cppblog.com/jaxe/archive/2011/08/11/153037.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏服务器的场景管理计算AOI终于搞出一个靠谱的方案了。。。</title><link>http://www.cppblog.com/jaxe/archive/2011/06/20/148998.html</link><dc:creator>浩毛</dc:creator><author>浩毛</author><pubDate>Sun, 19 Jun 2011 17:25:00 GMT</pubDate><guid>http://www.cppblog.com/jaxe/archive/2011/06/20/148998.html</guid><wfw:comment>http://www.cppblog.com/jaxe/comments/148998.html</wfw:comment><comments>http://www.cppblog.com/jaxe/archive/2011/06/20/148998.html#Feedback</comments><slash:comments>14</slash:comments><wfw:commentRss>http://www.cppblog.com/jaxe/comments/commentRss/148998.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jaxe/services/trackbacks/148998.html</trackback:ping><description><![CDATA[最近在优化游戏服务器的AOI（area of interest)部分，位置有关的游戏实体一般都有一个视野或关心的范围，<br />
当其他实体进出某个实体的这个范围的时候，就会触发leaveAOI或enterAOI事件，并维护一份AOI 实体列表。<br />
我们来考虑最简单的实现，假设区域R中有1000个Entity，当某个entity位置发生变化时，需要计算entity的AOI事件和列表，伪代码如下： <br />
<br />
function onEntityMove(who)&nbsp;&nbsp;&nbsp; <br />
&nbsp; for entity in entities do <br />
&nbsp;&nbsp;&nbsp; if who &lt;&gt; entity then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 计算who和entity之间的距离<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果who移动前entity在who的AOI范围内，且现在在范围外<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 触发who.onLeaveAOI(entity)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果who移动前entity在who的AOI范围外，且现在在范围内<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 触发who.onEnterAOI(entity)&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果who移动前在 entity的AOI范围内，且现在在范围外&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 触发entity.onLeaveAOI(who)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果who移动前在 entity的AOI范围外，且现在在 范围内<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 触发entity.onEntityAOI(who)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br />
&nbsp; end<br />
end <br />
每次一个实体移动一次位置就要遍历1000个实体来计算，这 样做显然不行，效率太低了，<br />
那么就需要引入场景管理，将区域R分成n个格子，每个格子维护一个实体链表，entity移动时，只遍历它所在的格子和周围的8个格子的实体链表，<br />
再优化下，可以加入AOI圆和格子的碰撞检查，9个格子中再去掉没有相交的格子。。。等等<br />
也有用四叉树来进行场景管理的。<br />
<br />
还有些方案更简单，直接是画格子，按以实体为中心的九个格子进行位置广播， 实体从一个格子移动到另外的格子时触发事体。。好处是计算量简单，缺点是带宽占用大<br />
<br />
我上面的方案都试过了，效率和带宽占用都不理想，最近终于弄出一个新的方案，现在的AOI计算量是我们服务器以前计算量的1/40-1/80，由于涉及到公司的保密制度，不便细说，上几个测试的抓图：<br />
<br />
机器配置：win7 ,T5870 inter双核2G,2G内存<br />
20个entity 随机运动计算一次所有entity AOI的时间在0.02毫秒左右：<br />
<img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/jaxe/AOI20.jpg" width="600" height="459" /> <br />
220个实体，选择的实体AOI范围里有68个实体：<br />
<a href="/images/cppblog_com/jaxe/AOI200.jpg" target="_blank"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/jaxe/AOI200.jpg" width="600" height="456" /></a> <br />
4000个实体，选择的实体的AOI区域里有465个实体<br />
</a><a href="/images/cppblog_com/jaxe/AOI4000.jpg" target="_blank"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/jaxe/AOI4000.jpg" width="600" height="459" /></a> <br />
<a href="/Files/jaxe/AOIDemo.rar" target="_blank">AOIDemo.exe 下载</a><br />
<br /><img src ="http://www.cppblog.com/jaxe/aggbug/148998.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jaxe/" target="_blank">浩毛</a> 2011-06-20 01:25 <a href="http://www.cppblog.com/jaxe/archive/2011/06/20/148998.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>面向服务架构(SOA)的一些思考</title><link>http://www.cppblog.com/jaxe/archive/2010/12/29/137631.html</link><dc:creator>浩毛</dc:creator><author>浩毛</author><pubDate>Tue, 28 Dec 2010 16:31:00 GMT</pubDate><guid>http://www.cppblog.com/jaxe/archive/2010/12/29/137631.html</guid><wfw:comment>http://www.cppblog.com/jaxe/comments/137631.html</wfw:comment><comments>http://www.cppblog.com/jaxe/archive/2010/12/29/137631.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/jaxe/comments/commentRss/137631.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jaxe/services/trackbacks/137631.html</trackback:ping><description><![CDATA[

SOA:Service-oriented architecture<br>最近在做游戏服务器引擎，查了不少有关SOA的设计方面的资料。发现JAVA世界有相当多的技术标准。<br>其中比较好的是OSGi （<a href="http://www.osgi.org/About/WhatIsOSGi">http://www.osgi.org/About/WhatIsOSGi</a>），OSGi技术是面向Java的动态模型系统。OSGi服务平台向Java提供服务，这些服务使Java成为软件集成和软件开发的首选环境。Java提供在多个平台支持产品的可移植性。OSGi技术提供允许应用程序使用精炼、可重用和可协作的组件构建的标准化原语。这些组件能够组装进一个应用和部署中。<br>参考它的思路，结合C++语言的特点，我将一个服务器基础框架设计成了这样一种:<br><img border="0" align="absmiddle" src="http://www.cppblog.com/images/cppblog_com/jaxe/SOA.jpg"><br>一个服务器应用，由多个组件组成，组件物理上可以是动态库，也可以是EXE里一段实际的代码，每个组件可以向ApplicationFramework注册多个服务（比如日志服务，网络服务等）。<br>ApplicationFramework启动时，通过配置文件，动态加载和启动组件，读取服务的可配置属性。Framework触发IComponentActivator的OnStart() 和OnStop()事件，在Start事件中，可以注册组件自己的服务，也可以加入一个服务监听器来监听关心的服务的注册，注销等事件。<br>我随便画了几个大概的接口：<br><img border="0" align="absmiddle" src="http://www.cppblog.com/images/cppblog_com/jaxe/SOA2.jpg">&nbsp;&nbsp;<img src ="http://www.cppblog.com/jaxe/aggbug/137631.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jaxe/" target="_blank">浩毛</a> 2010-12-29 00:31 <a href="http://www.cppblog.com/jaxe/archive/2010/12/29/137631.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏服务器中的数据库异步操作技术和游戏数据的保存机制</title><link>http://www.cppblog.com/jaxe/archive/2010/08/30/125258.html</link><dc:creator>浩毛</dc:creator><author>浩毛</author><pubDate>Mon, 30 Aug 2010 03:35:00 GMT</pubDate><guid>http://www.cppblog.com/jaxe/archive/2010/08/30/125258.html</guid><wfw:comment>http://www.cppblog.com/jaxe/comments/125258.html</wfw:comment><comments>http://www.cppblog.com/jaxe/archive/2010/08/30/125258.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/jaxe/comments/commentRss/125258.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jaxe/services/trackbacks/125258.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;在游戏服务器中，处理玩家登陆需要向数据库查询玩家的账号和密码，玩家上线和下线需要对玩家的角色数据从数据库中读取和保存。可以说，相对于游戏逻辑处理来说，数据库操作是一种相对很慢的操作，即便你通过使用多个线程多个数据库连接来提高数据库操作的处理能力，但是，在高并发高负载的服务器应用中，这样仍然会是相当的负载瓶颈。设想这样一种设计方案，见下图：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/jaxe/db1.png" width=543 height=292><br>&nbsp;&nbsp;&nbsp;&nbsp;在大量玩家登陆游戏服务器时，由于有大量的数据库访问请求，即便是有自己实现的CACHE机制，还是会导致服务器耗尽所有的逻辑线程资源，服务器的处理能力将降低成DBMS的处理能力。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; 为了不阻塞逻辑线程，可以采用异步数据库访问的方式，即数据库操作请求提交给专门的数据库处理线程池，然后逻辑线程不再等待数据库处理结果，继续处理其他，不再阻塞在这里。<br>&nbsp;&nbsp;&nbsp;&nbsp; 抽象的来看，对于一个需要持久化的游戏对象来说，可以考虑它有2个方法，读取和保存。那么我们抽象一个DBO接口：<br>&nbsp;&nbsp;&nbsp; </p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;IDbo<br><img id=Codehighlighter1_12_84_Open_Image onclick="this.style.display='none'; Codehighlighter1_12_84_Open_Text.style.display='none'; Codehighlighter1_12_84_Closed_Image.style.display='inline'; Codehighlighter1_12_84_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_12_84_Closed_Image onclick="this.style.display='none'; Codehighlighter1_12_84_Closed_Text.style.display='none'; Codehighlighter1_12_84_Open_Image.style.display='inline'; Codehighlighter1_12_84_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_12_84_Closed_Text></span><span id=Codehighlighter1_12_84_Open_Text><span style="COLOR: #000000">{<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;SaveToDB(DB</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;LoadFromDB(DB</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span><span style="COLOR: #000000">;</span></div>
&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp; 然后把设计方案改成下面这种：<br><br><img style="WIDTH: 569px; HEIGHT: 225px" border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/jaxe/db3.png" width=569 height=225>&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp; 改成数据库异步处理后，在想想现在的游戏数据的保存机制应该是怎样改进的，为了保障数据安全，我们希望不只是玩家下线的时候才会保存玩家数据，而是希望每隔一段时间统一保存所有在线玩家的数据，那么，可以考虑这样的思路：假设我们有一个GAMEDB服务器，GAMEDB缓存了所有在线玩家的角色数据，每到保存时间，GAMEDB就将所有在线玩家的数据(DBO）的副本都统一提交给DB线程池，让它保存数据，提交的过程很快，提交完后，GAMEDB的逻辑线程仍能继续处理游戏服务器的更新和读取CACHE的请求。为什么要保存副本呢，DB线程的执行保存队列的过程也许很耗时，但是队列中的数据都是GAMEDB提交DBO那个时刻的数据，这样就能保证玩家的游戏数据的完整性。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然，我这里提的这只是个思路，这里面还有很多细节没有讨论，例如如果DB线程池正在保存九点钟时刻保存的数据，到了十点钟新的保存时刻时，DB线程池还没保存完九点钟时刻的DBO副本队列，这时应该怎么处理；DBO对象的划分粒度的问题；DBO队列的优先级的问题等等。<br><br>&nbsp;&nbsp;&nbsp;&nbsp; PS:这篇文章里的架构其实就是一个GAMEDB服务器，里面的逻辑处理就是GAMEDB的逻辑处理。你可以把这篇文章理解成：一个GAMEDB服务器 的实现思路。。。
<img src ="http://www.cppblog.com/jaxe/aggbug/125258.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jaxe/" target="_blank">浩毛</a> 2010-08-30 11:35 <a href="http://www.cppblog.com/jaxe/archive/2010/08/30/125258.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程还是单线程？</title><link>http://www.cppblog.com/jaxe/archive/2010/07/06/119387.html</link><dc:creator>浩毛</dc:creator><author>浩毛</author><pubDate>Mon, 05 Jul 2010 16:06:00 GMT</pubDate><guid>http://www.cppblog.com/jaxe/archive/2010/07/06/119387.html</guid><wfw:comment>http://www.cppblog.com/jaxe/comments/119387.html</wfw:comment><comments>http://www.cppblog.com/jaxe/archive/2010/07/06/119387.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.cppblog.com/jaxe/comments/commentRss/119387.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jaxe/services/trackbacks/119387.html</trackback:ping><description><![CDATA[<p>一个典型的游戏服务器设计中，一般都是用的多线程，服务器中一般运行两类线程，N个SOCKET IO线程，1个逻辑线程，<br>IO线程接受客户端发来的信息，通过消息队列发送给逻辑线程处理后，再发送消息给客户端，发送消息这里一般是IO线程处理实际发送。<br><br>其实我认为，如果逻辑线程都是消耗的CPU运算资源的话，服务器完全采用单线程的方式来做。<br><br>首先，我们看IO处理，基本就是数据入队、出队，send、recv操作，作为服务器的SOCKET处理一般都是异步SOCKET，也就是说，send、recv操作只是将信息copy到socket底层的发送接收缓冲区去了，不存在IO堵塞的问题。<br><br>然后，我们再来看逻辑处理，前面已经说了，采用单线程的前提是逻辑处理只是消耗CPU运算资源，那么，不管你开几个线程，对单核的CPU来说，它的处理速度就是这么多，并不会因为你线程开的越多，就处理的越快。<br><br>因此我们可不可以这样说呢，在单核机器上，只消耗CPU运算的服务，多线程并不比单线程能提高多少效率。<br><br>接下来，我们再讨论下多核的情况，你肯定要想，我这台服务器是4个双核CPU，就只跑一个单线程的服务器不是亏死了，多线程多好，我开8个线程，就能很好的利用我的机器啦。是啊，我也觉得这样很好，不过在LINUX、UNIX下，对线程的支持并不像WINDOWS下那么好，LINUX、UNIX下一般都是用LWP（轻量级进程）的方式来支持多线程程序的，Linux内核只提供了轻量进程的支持，限制了更高效的线程模型的实现，但Linux着重优化了进程的调度开销，一定程度上也弥补了这一缺陷。同时，滥用多线程也会造成不必要的上下文切换，不必要的同步机制的引入（如pthread_mutex），让程序频繁的在内核和用户间频繁切换。另外，从开发角度来看，单线程开发比多线程环境开发更不容易出错和更加健壮。<br><br>在游戏服务器架构中，为了提高玩家在线人数，实现负载均衡，现在一般都是采用分布式的多进程服务器集群的方式，我们来看看服务器集群中，每个服务进程是采用多线程的方式还是单线程的方式好呢？我觉得，对于有慢速IO访问的需求的应用进程，多线程肯定比单线程好，最典型的情况就是数据库访问这块，完全可以采用N个DB线程，一个逻辑线程的架构，而对只是消耗CPU运算资源的应用进程，尽量单线程就行了，如果觉得单线程负载不行的话，完全可以分成多个进程来跑。。<br><br>以上只是我自己的一些看法，表达有限，欢迎指正。。。</p>
<img src ="http://www.cppblog.com/jaxe/aggbug/119387.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jaxe/" target="_blank">浩毛</a> 2010-07-06 00:06 <a href="http://www.cppblog.com/jaxe/archive/2010/07/06/119387.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>The Sun Game Server Architecture（转载）</title><link>http://www.cppblog.com/jaxe/archive/2010/06/08/117371.html</link><dc:creator>浩毛</dc:creator><author>浩毛</author><pubDate>Tue, 08 Jun 2010 06:28:00 GMT</pubDate><guid>http://www.cppblog.com/jaxe/archive/2010/06/08/117371.html</guid><wfw:comment>http://www.cppblog.com/jaxe/comments/117371.html</wfw:comment><comments>http://www.cppblog.com/jaxe/archive/2010/06/08/117371.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jaxe/comments/commentRss/117371.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jaxe/services/trackbacks/117371.html</trackback:ping><description><![CDATA[<strong>The Sun Game Server Architecture<br><br></strong>&nbsp;&nbsp;&nbsp;&nbsp; Sun&#8216;s Game Server technology logically is divided vertically into 3 layers: <strong>Communications</strong>, <strong>Simulation Logic</strong>, and<br><strong>Object Store</strong>.<br><br>&nbsp;&nbsp;&nbsp;&nbsp; The<strong> Object Store</strong> layer contains the game states for all games running in the Game Server. It is a highly efficient(tenths of a millisecond per operation), scalable, and fault-tolerant transactional database layer that provides deadlock proof access to the simulation objects, which can either be locked (a write-lock) or peeked (a nonrepeatable read).<br><br>&nbsp;&nbsp;&nbsp;&nbsp; The <strong>Simulation Logic</strong> layer is responsible for executing the actual game code. Here, tasks are created based on incoming events which, in turn, check objects out of the Object Store as needed. When a task is completed, the object is updated and returned to the Object Store.<br><br>&nbsp;&nbsp;&nbsp;&nbsp; The <strong>Communications</strong> layer organizes player communication into channels of grouped communicators. It manages routing of data packets between the players and the Simulation Logic servers, and between the players themselves. It also is responsible for translation to and from other forms of networking (e.g., HTTP communications to and from cell phones).<br><br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/jaxe/aaa.png" width=484 height=470> 
<img src ="http://www.cppblog.com/jaxe/aggbug/117371.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jaxe/" target="_blank">浩毛</a> 2010-06-08 14:28 <a href="http://www.cppblog.com/jaxe/archive/2010/06/08/117371.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏服务器架构设计中的一些思考</title><link>http://www.cppblog.com/jaxe/archive/2010/04/22/113255.html</link><dc:creator>浩毛</dc:creator><author>浩毛</author><pubDate>Thu, 22 Apr 2010 08:16:00 GMT</pubDate><guid>http://www.cppblog.com/jaxe/archive/2010/04/22/113255.html</guid><wfw:comment>http://www.cppblog.com/jaxe/comments/113255.html</wfw:comment><comments>http://www.cppblog.com/jaxe/archive/2010/04/22/113255.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/jaxe/comments/commentRss/113255.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jaxe/services/trackbacks/113255.html</trackback:ping><description><![CDATA[&nbsp;
<p><span><span>1、&nbsp;</span></span><span>游戏世界由很多个游戏对象组成（游戏角色、物品、</span><span>NPC</span><span>、技能等）；</span></p>
<p>&nbsp;</p>
<p><span><span>2、&nbsp;</span></span><span>一个游戏对象的有效数据主要存放在客户端、游戏服务器和持久性数据库中；</span></p>
<p>&nbsp;</p>
<p><span><span>3、&nbsp;</span></span><span>游戏对象的处理可划分为与位置有关的和与位置无关的，如公会处理、物品处理等主要行为可以看作是与位置无关的处理，而</span><span>NPC</span><span>（</span><span>AI</span><span>）、战斗、移动这类的主要行为可以看成是与位置有关的。</span></p>
<p>&nbsp;</p>
<p><span><span>4、&nbsp;</span></span><span>从客户端的角度来看，游戏行为可分为四类动作：</span></p>
<p><span><span>a)<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>来自服务器端的动作</span><span>，如另外一个玩家跳起来。</span></p>
<p><span><span>b)<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>本地动作。</span><span>仅仅发生在本地客户端的动作，不需要与服务器端或其他客户端通讯。</span></p>
<p><span><span>c)<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>先执行后验证的可撤销的动作。客户端先执行，再提交服务器端验证，验证不成功通知客户端将执行的动作撤销。比如玩家控制的游戏角色执行移动处理。</span></p>
<p><span><span>d)<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>严格服务器端验证的动作。客户端执行动作前必须经过服务器端验证后才能执行。如交易行为、攻击其他玩家</span><span>/NPC</span><span>。</span></p>
<p>&nbsp;</p>
<p><span><span>5、&nbsp;</span></span><span>客户端和服务器，服务器进程之间的相互的通信从逻辑上看就是就是向</span><span>RemoteObject </span><span>发起的远程过程调用（</span><span>RPC</span><span>），</span><span>RPC</span><span>主要有两种类型：</span></p>
<p><span><span>a)<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>通知</span><span>(Notify)</span><span>。只通知对方，而不关心和需要对方返回结果。</span></p>
<p><span><span>b)<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>请求</span><span>(Request)</span><span>。向对方发起请求，对方处理请求后返回结果，发起请求和返回结果这个过程可以是同步或异步。游戏服务器中绝大部分</span><span>RPC</span><span>请求都是异步的。</span></p>
<p>&nbsp;</p>
<p><span><span>6、&nbsp;</span></span><span>响应延迟主要是由于网络带宽和服务器处理效率引起的。应尽可能的通过一些技巧来隐藏和减少玩家的响应延迟。但不是所有的最新消息都能立刻发送出去（或接收处理到），因此，要在服务器端采用优先队列来减少重要消息的响应时间。</span><span>延迟也会由客户端产生，如收到消息后的对消息的处理速度。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span><span>7、&nbsp;</span></span><span>服务器负载，除了升级硬件设备外，可以通过一些方式来提高服务器负载。</span></p>
<p>&nbsp;</p>
<p><span><span>a)<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>保证足够的网络带宽。</span></p>
<p><span><span>b)<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>分布式运算，合理的集群式架构。</span></p>
<p><span><span>c)<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>游戏策划从游戏内容上避免设计高并发，高消耗的游戏行为。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span><span>8、&nbsp;</span></span><span>从服务器的可伸缩性，稳定性和高效率方面来考虑，要</span><span>试着避免所有事情都在一个地方处理，尽量让系统分布式运行，但是过多的划分功能到不同的进程</span><span>/</span><span>机器上运行，又会带来数据的大量同步的问题。因此可以将游戏对象的处理主要划分为与位置无关和有关两种。像公会，玩家信息，物品信息，组队，拍卖等等这类与位置无关的但是占用</span><span>CPU</span><span>资源较少的处理可以尽可能的放在一个进程中，避免进程间对象同步，而像</span><span>NPC</span><span>，寻路，</span><span>AOI</span><span>运算，战斗处理等与位置有关的，处理过程中特别关心对象坐标位置的、运算量特别大的，但是进程间对象同步较少的，都可以单独划分成多个进程。</span></p>
<p>&nbsp;</p>
<p><span>每类进程服务的功能尽量单一。负责路由的就尽量只负责网络包转发，而不再承担其他繁重的任务，负责游戏处理的就尽量让网络包流向简单。</span></p>
<img src ="http://www.cppblog.com/jaxe/aggbug/113255.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jaxe/" target="_blank">浩毛</a> 2010-04-22 16:16 <a href="http://www.cppblog.com/jaxe/archive/2010/04/22/113255.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>