高级网络概念

本节涵盖了使用 Unity 网络架构开发游戏之前应该理解的一般网络概念。

网络是什么??

网络是两台或两台以上计算机之间的通信。其基本概念是客户端 (client)(请求信息的计算机)与服务器 (server)(响应信息请求的计算机)之间的通信。服务器可以是由所有客户使用的专用主机,或仅仅是一台运行游戏同时作为其他玩家的服务器的玩家计算机(客户端)。建立好服务器并将客户端与其连接后,这两台电脑就可以按游戏要求交换数据了。

创建网络游戏需要十分注意一些非常具体的细节。尽管在 Unity 中网络动作的设计和创建都很简单,但网络连接却仍然是相当复杂的。Unity 中主要的设计目标是要使网络尽可能的稳健和灵活。这意味着作为游戏创建者的您要负责在其他引擎中以自动但欠稳健处理方式的内容。由于您的选择在未来会对游戏的设计造成重大影响,因此最好尽可能在设计阶段早期就做好这些选择。理解网络概念将帮助您很好地计划游戏设计以及避免实施期间的问题。

网络方法

构建网络游戏有两种常见且被认可的方法,称为授权服务器 (Authoritative Server)非授权服务器 (Non-Authoritative Server)。这两种方法都依赖一台服务器将客户端连接起来并在它们之间传送信息。这两种方法还为终端用户提供 了保密机制,因为客户端之间不会直接相连,其 IP 地址也不会向其他客户端显示。

授权服务器 (Authoritative Server)

授权服务器方法需要服务器执行世界坐标模拟、游戏规则应用以及玩家客户端输入的处理等。每个客户端会将它们的输入(以按键或请求动作的形式)发送到服务器,并从服务器持续接收游戏的当前状态。客户端不会对游戏状态本身做任何更改。相反,它只会告诉服务器它想做什么,然后服务器就会处理该请求并回应客户端以说明结果。

从根本上讲,玩家想进行的操作和实际发生的情况之间有一个隔层。这使服务器可以在决定如何更新游戏状态之前听到每个客户端的请求。

此方法的一个优势是使客户端更难以作弊。举例来说,客户端不可能欺骗服务器(因此也无法欺骗其他客户端)说敌人已被杀死了,因为它们无法自行做出此决定。它们只能告诉服务器武器开了火,之后将由服务器决定敌人是否已被杀死。

授权服务器 (authoritative server) 的另一个例子是依赖于物理的多人游戏。如果允许每个客户端运行自己的物理模拟,那么客户端之间的小变动将逐步导致它们相互之间偏离同步。然而,如果所有物理对象的模拟都是在中央服务器上处理的,将更新的状态发送回各客户端后则可以保证所有客户端的一致性。

授权服务器 (authoritative server) 的一个潜在不足之处在于消息在网络上传送所花费的时间。如果玩家按下控件向前移动,需十分之一秒才从服务器得到响应,则玩家明显觉到延迟。这种情况的一个解决方案是使用一种被称为客户端预测 (client-side prediction) 的技术。这种技术的重要特点是允许客户端更新自己游戏状态的本地版本,但它必须能够在必要时接收来自服务器授权版本的修正。通常情况下,这应该仅用于简单的游戏动作而不用于对游戏状态作出显著的逻辑更改。例如,将敌人被杀死的消息报告给玩家是不明智的,而应该仅由服务器来覆盖这个决定。

由于客户端预测 (client-side prediction) 是高级主题,因此我们并不打算在本指南中涵盖这方面的内容。但是如果您想做进一步研究,我们可提供 相关书籍或网络资源。

授权服务器的处理开销比非授权服务器大。当不需要服务器处理对游戏状态的所有更改时,可在客户端之间分配很多这种加载。

非授权服务器 (Non-Authoritative Server)

非授权服务器 (non-authoritative server) 不会控制每次用户输入的结果。客户端在本地处理用户输入和游戏逻辑,然后将任意确定动作的结果发送到服务器。然后,服务器会将所有动作与世界坐标状态同步。服务器只是在客户端之间转发消息,并不会超出客户端的工作范围做更多处理,因此从设计观点来看更容易实施。

不需要任何类型的预测 (prediction) 方法,因为客户端会自己处理所有物理和事件,并将发生的情况转发给服务器。它们是自身对象的所有者 (owners),是受允许通过网络发送这些对象的本地修改的唯一代理。

网络通信的方法

既然我们已经了解了网络游戏的基础架构,那么现在让我们来探索客户端和服务器是如何在底层相互对话的。

有两种相关方法:远程过程调用 (Remote Procedure Call)状态同步 (State Synchronization)。在任意特定游戏的不同点同时使用两种方法的情况并不少见。

远程过程调用 (Remote Procedure Call)

远程过程调用 (RPC) 用于通过网络调用其他计算机上的函数。然而在客户端与服务器运行于同一台计算机上时,“网络”也可以表示客户端和服务器之间的消息通道。客户端可以向服务器发送 RPC,而服务器可以向一个或多个客户端发送 RPC。通常情况下,它们用于很少发生的动作。例如,如果一个客户端按一个开关来打开一扇门,它可以发送一个 RPC 到服务器,告诉它门被打开了。然后服务器能发送另一个 RPC 到所有客户端,调用这些客户端的本地函数来打开同一扇门。RPC 用于管理和执行单个事件。

状态同步 (State Synchronization)

状态同步 (State Synchronization) 用于共享不断更改的数据。最好的例子是动作游戏中的玩家位置。玩家总是在移动,跑动和跳跃等等。网络上的其他所有玩家,甚至没有本地控制这个角色的玩家,都需要知道该玩家在哪里以及在做什么。通过不断的转发关于这个玩家位置的数据,游戏能够精确地向其他玩家表现该玩家的位置。

这种类型的数据会定期和频繁地通过网络发送。这种数据是具有时间敏感性的,并且从一台设备通过网络传送到另一台设备需要耗用时间,因此尽可能减少发送的数据量是非常重要的。简单地说就是状态同步 (state synchronization) 必然需要大量的带宽,因此您应该尽量少用带宽。

连接服务器和客户端

连接服务器和客户端是一项复杂的过程。设备可以有私有和公有 IP 地址,它们还可以具有阻止访问的本地或外部防火墙。Unity 网络的目标在于能尽可能多地处理各种情况,但没有一种通用的解决方案。

私有地址是一种不能从互联网上直接访问的 IP 地址(在使用方法对其实施之后,它们也被称作网络地址转换或 NAT 地址)。简单地说,私有地址会经过本地路由器,将地址转换为公有地址。通过这个操作,许多有私有地址的设备就能用一个公有 IP 地址来与互联网通信了。在没有人想从互联网上与一个私有地址通信的情况下这还是不错的。通信必须经过路由器的公有地址,然后路由器必须将消息传递到私有地址。一种叫做 NAT 穿透的技术使用一种被称为服务商 (facilitator) 的共享服务器来调节通信,以此方式可从公有地址访问私有地址。工作原理是私有地址首先联系服务商 (facilitator),在本地路由上“穿透”一个洞。然后服务商 (facilitator) 就能看到私有地址正在使用的公有 IP 地址和端口。通过使用该信息,互联网上的任何设备现在都可以直接连接到用其他方法无法连接的私有地址。(请注意 NAT 穿透的详细情况在实际操作时比这里说的方法稍微复杂些。)

公有地址更简单直接。这里的主要问题是连接可能会被内部或外部防火墙阻止(内部防火墙是在其保护的计算机上本地运行的防火墙)。对于内部防火墙,可请求用户解除特定端口的限制,从而使游戏服务器可访问该计算机。相比之下,外部防火墙则不受用户的控制。Unity 可以尝试使用 NAT 穿透 (punchthrough) 通过外部防火墙进行访问,但无法保证此技术是否成功。我们的测试表明该技术在实践中通常都有效,但似乎没有任何正式的研究证实此发现。

上述的连接问题分别影响服务器和客户端。客户端请求仅涉及相对简单输出网络流量。如果客户端具有共有地址,那么该技术就总是有效。这是因为输出流量通常只在实行严格访问限制的公司网络中才会被阻止。如果客户端具有私有地址,那么可以访问所有的服务器,除非服务器也有不支持 NAT 穿透 (punchthrough) 的私有地址(稍后将对此进行详述)。因为服务器需要能够接受来自未知源的连接,所以服务器端更加复杂。在具有公有地址的条件下,服务器需要向互联网开放游戏端口(即未被防火墙阻止的端口),否则它将无法接受来自客户端的任何连接而无法使用。如果服务器具有私有地址,则必须能够进行 NAT 穿透 (punchthrough) 来允许连接。为了连接到该服务器,客户端也必须允许 NAT 穿透 (punchthrough)。

Unity 提供 了工具用于测试所有不同的连接情况。当建立好并能进行连接时,有两种方法可以实现连接:直接连接(客户端需要知道服务器的 DNS 名称或者 IP 地址)和通过主服务器连接。主服务器允许服务器使客户端得知其存,客户端不需要预先知道任何特定游戏服务器的信息。

最小化网络带宽

在多个客户端之间使用状态同步 (State Synchronization) 时,为了使对象看起来同步而同步每个细节是没有必要的。例如,同步一个角色 Avatar 时,您只需要在客户端之间发送其位置和旋转角度信息。即使角色本身更加复杂并可能包括较深的变换 (Transform) 层级,也不需要共享整个层级的数据。

游戏中的许多数据实际上是静态的,客户端没有必要在开始的时候传输这些数据也没必要同步数据。很少或者一次 RPC 调用就足以使这些功能生效。利用每次游戏安装中您所知存在的数据并尽可能使客户端自行工作。例如,您知道纹理或者网格等资源存在于所有安装中且通常不会变化,因此没有必要对其进行同步。这只是一个简单的例子,但却能引导您思考什么数据是必须在客户端之间共享的。这也是您唯一需要共享的数据。

要准确地计算出哪些数据需要共享和哪些不需要是很困难的工作,对于没有网络游戏制作经验的人来说更是如此。记住,您可以使用一次带级别名称的 RPC 调用,使所有客户端加载整个特定级别并自动添加自己的网络元素。结构化游戏使每个客户端都能尽可能自给自足将会减少带宽。

多人游戏性能

服务器自身的物理位置和性能可极大地影响所运行的游戏的可玩性。与服务器不在同一个洲的客户端将感受到极大的延迟。这是互联网的物理限制。唯一真正的解决方案是将服务器安排得尽可能靠近使用它的客户端,或者至少将它们安排在同一个大洲。

其他资源s

我们在下面收集了有关网络的附加资源的链接:-

Page last updated: 2013-07-01