提示:阅读本文前,请先读此文了解文章背景:http://data.gameres.com/message.asp?TopicID=27236
让无数中国玩家为之瞩目的“魔兽世界”,随着一系列内测前期工作的逐步展开,正在一步步地走近中国玩家,但是,“魔兽”的服务器,却着实让我们为它捏了一把汗。
造成一个网游服务器当机的原因有很多,但主要有以下两种:一,服务器在线人数达到上限,服务器处理效率严重迟缓,造成当机;二,由于外挂或其它游戏作弊工具导致的非正常数据包的出错,导致游戏服务器逻辑出现混乱,从而造成当机。在这里,我主要想说说后者如何尽可能地避免。
要避免以上所说到的第二种情况,我们就应该遵循一个基本原则:在网游服务器的设计中,对于具有较强逻辑关系的处理单元,服务器端和客户端应该采用“互不信任原则”,即:服务器端即使收到了客户端的数据包,也并不是立刻就认为客户端已经达到了某种功能或者状态,客户端到达是否达到了某种功能或者状态,还必须依靠服务器端上记载的该客户端“以往状态”来判定,也就是说:服务器端的逻辑执行并不单纯地以“当前”的这一个客户端封包来进行,它还应该广泛参考当前封包的上下文环境,对执行的逻辑作出更进一步地判定,同时,在单个封包的处理上,服务器端应该广泛考虑当前客户端封包所需要的“前置”封包,如果没有收到该客户端应该发过来的“前置”封包,则当前的封包应该不进行处理或进行异常处理(如果想要性能高,则可以直接忽略该封包;如果想让服务器稳定,可以进行不同的异常处理)。
之所以采用“互不信任”原则设计网游服务器,一个很重要的考虑是:防外挂。对于一个网络服务器(不仅仅是游戏服务器,泛指所有服务器)而言,它所面对的对象既有属于自己系统内的合法的网络客户端,也有不属于自己系统内的非法客户端访问。所以,我们在考虑服务器向外开放的接口时,就要同时考虑这两种情况:合法客户端访问时的逻辑走向以及非法客户端访问时的逻辑走向。举个简单的例子:一般情况下,玩家登录逻辑中,都是先向服务器发送用户名和密码,然后再向服务器发送进入某组服务器的数据包;但在非法客户端(如外挂)中,则这些客户端则完全有可能先发进入某组服务器的数据包。当然,这里仅仅是举个例子,也许并不妥当,但基本的意思我已经表达清楚了,即:你服务器端不要我客户端发什么你就信什么,你还得进行一系列的逻辑验证,以判定我当前执行的操作是不是合法的。以这个例子中,服务器端可以通过以下逻辑执行验证功能:只有当客户端的用户名和密码通过验证后,该客户端才会进入在线玩家列表中。而只有在线玩家列表中的成员,才可以在登陆服务器的引导下进入各分组服务器。
总之,在从事网游服务器的设计过程中,要始终不移地坚持一个信念:我们的服务器,不仅仅有自己的游戏客户端在访问,还有其它很多他人写的游戏客户端在访问,所以,我们应该确保我们的服务器是足够强壮的,任它风吹雨打也不怕,更不会倒。如果在开发实践中,没有很好地领会这一点或者未能将这一思路贯穿进开发之中,那么,你设计出来的服务器将是无比脆弱的。
当然,安全性和效率总是相互对立的。为了实现我们所说的“互不信任”原则,难免的,就会在游戏逻辑中加入很多的异常检测机制,但异常检测又是比较耗时的,这就需要我们在效率和安全性方面作个取舍,对于特别重要的逻辑,我们应该全面贯彻“互不信任”原则,一步扣一步,步步为营,不让游戏逻辑出现一点漏洞。而对于并非十分重要的场合,则完全可以采用“半信任”或者根本“不须信任”的原则进行设计,以尽可能地提高服务器效率。
本文只是对自己长期从事游戏服务器设计以来的感受加以总结,也是对魔兽的服务器有感而发。欢迎有相同感受的朋友或从事相同工作的朋友一起讨论。