游戏网络同步学习

0. 学习路径

  1. 网络编程基础:
    • 学习基本的网络通信概念,了解TCP/IP和UDP协议。
    • 学习Socket编程,掌握套接字的使用和网络通信的基本原理。
    • 了解网络模型和常见的网络通信模式。
  2. 游戏网络同步基础:
    • 了解游戏网络同步的基本原理,包括客户端-服务器架构和点对点架构。
    • 熟悉帧同步和状态同步的概念。
  3. 游戏引擎和框架:
    • 学习一些流行的游戏引擎,如Unity或Unreal Engine。
    • 掌握该引擎的网络模块和相关API。
  4. 多线程编程:
    • 了解多线程编程的基本概念,学习如何使用线程来处理并发任务。
    • 学习线程同步和互斥机制,以确保线程安全。
  5. 同步算法:
    • 学习关于游戏同步的算法,如时间插值、状态插值、预测性同步等。
    • 了解如何处理网络延迟和抖动。
  6. 网络优化:
    • 学习网络优化技术,减少带宽占用和延迟。
    • 了解并实践压缩和流量控制等技术。
  7. 实际项目经验:
    • 参与小型游戏项目,实践所学知识。
    • 阅读开源游戏项目的源代码,了解实际应用。

1. 网络编程基础

1.1 网络协议

1.2 TCP传输控制协议

  • 特点:
    • 提供可靠的数据传输,确保数据完整无误地到达。
    • 有序传输数据包,维护数据顺序。
    • 自动处理数据包重传和丢失问题。
  • 适用场景:
    • 当游戏需要可靠的数据传输时,例如在一些需要高度数据一致性的策略游戏或回合制游戏中。
    • 客户端-服务器架构中,尤其是涉及到重要游戏状态和玩家数据的时候,经常使用TCP。

1.3 UDP用户数据报协议

  • 特点:
    • 提供快速的数据传输,但不保证数据包的可靠到达。
    • 不保证数据包的顺序。
    • 无连接,减少数据传输的延迟。
  • 适用场景:
    • 当游戏需要快速响应和实时更新时,例如在射击游戏或竞速游戏中。
    • 在点对点架构中,尤其是对实时性要求较高的游戏,UDP经常被使用。

1.4 结合TCP和UDP

有些游戏可能会同时使用TCP和UDP,根据不同的需求选择不同的协议。例如,使用TCP来处理登录、聊天和交易等需要高可靠性的数据传输,而使用UDP来处理实时的游戏状态更新。

1.5 其它协议

除了TCP和UDP,还存在其他一些网络通信协议,但在游戏开发中,TCP和UDP是最常用的。

以下是一些其他协议的简要介绍:

  1. HTTP/HTTPS:
    • 超文本传输协议(HTTP)和其安全版本(HTTPS)通常用于在Web浏览器和服务器之间传输数据。
    • 虽然HTTP不适用于实时性要求高的游戏,但在一些需要通过Web进行访问的游戏和应用中可能会使用。
  2. QUIC(Quick UDP Internet Connections):
    • QUIC是一个基于UDP的传输协议,旨在提供更快的连接建立和更低的延迟。
    • 由Google推出,适用于一些对延迟敏感的应用,但在游戏领域的应用尚不如TCP和UDP广泛。
  3. SCTP(Stream Control Transmission Protocol):
    • SCTP是一个支持可靠和不可靠传输的协议,同时具有多流和多宿主的特性。
    • SCTP被设计为提供比TCP更好的性能,并提供更好的消息边界控制。
  4. RUDP(Reliable UDP):
    • RUDP是对UDP的扩展,通过在应用层实现可靠性,使UDP具备了类似于TCP的可靠传输特性,但不同于TCP的有序传输。
    • 一些游戏开发者选择在UDP基础上实现自定义的可靠性,以避免TCP的一些缺点,如拥塞控制导致的延迟增加。

1.4 Socket

Socket(套接字)在严格意义上是一种编程接口(API),用于在网络中实现进程间的通信。
它可以被看作是一种在应用层和传输层之间的接口,使得程序可以通过网络发送和接收数据。
Socket并不是协议,而是一个用于进行网络编程的抽象接口。

在具体实现中,Socket可以使用不同的传输协议,最常见的是TCP和UDP。
通过使用Socket API,开发者可以创建套接字并使用它来建立网络连接、发送和接收数据。

在网络同步中,Socket扮演着关键的角色,特别是在实现客户端-服务器模型时。以下是Socket在网络同步中的一些关键作用:

  1. 建立连接: Socket用于建立客户端与服务器之间的连接。客户端和服务器分别创建套接字,然后通过Socket建立连接。
  2. 数据传输: 通过Socket,程序可以使用不同的方法(如sendrecv)发送和接收数据。这是网络同步中实现信息交换的关键。
  3. 实时通信: 在实时多人游戏中,Socket负责实现玩家之间的实时通信。通过套接字,游戏客户端可以向服务器发送玩家的输入,服务器可以将更新的游戏状态广播给所有连接的客户端。
  4. 协议选择: Socket API允许开发者选择不同的传输协议,如TCP或UDP,根据游戏的需求来确定数据传输的可靠性和效率。

总的来说,Socket是一个在网络编程中用于实现通信的工具库(或者说是编程接口),它在网络同步中扮演着连接、数据传输和实时通信等关键角色。通过使用Socket,开发者可以在应用层进行网络编程,实现不同设备之间的数据交换。

2. 游戏网络同步基础

2.1 网络同步架构

2.1.1 客户端-服务端架构

原理

游戏客户端和服务器之间存在中央服务器,负责处理游戏逻辑和同步状态。
客户端发送输入信息到服务器,服务器处理并更新游戏状态,然后将新的状态广播给所有连接的客户端。
客户端只负责输入处理和本地预测,而真正的游戏状态由服务器维护。
服务器是唯一的权威来源,决定游戏中的事件和状态变化。
通信通常使用可靠的传输协议(如TCP)以确保数据完整性。

优缺点

优点:

  • 中央服务器可以处理作弊和安全性问题,因为它有权力验证和修正客户端的输入。
  • 适用于大型多人在线游戏,可以管理数以千计的玩家。

缺点:

  • 服务器压力大,可能成为性能瓶颈。
  • 有较高的延迟,因为所有操作都需要经过服务器。

适用场景

大型多人在线游戏,需要中央权威来确保游戏状态的一致性和防止作弊。

案例游戏

  • 《魔兽世界》(World of Warcraft)
    作为一款经典的大型多人在线角色扮演游戏(MMORPG),《魔兽世界》使用客户端-服务器架构来处理大量玩家的交互和游戏状态更新。
  • 《反恐精英:全球攻势》(Counter-Strike: Global Offensive)
    这是一款流行的第一人称射击游戏,使用客户端-服务器模型来保证游戏的公平性和同步。
  • 《英雄联盟》(League of Legends)
    这款广受欢迎的多人在线战术竞技游戏也采用客户端-服务器架构,服务器负责处理游戏逻辑和同步玩家状态。

2.1.2 点对点架构

原理

每个玩家都有一个独立的客户端,彼此直接通信。
每个客户端处理自身的输入和状态更新,并将这些信息发送给其他玩家。
没有中央服务器,玩家直接交换信息,共同维护游戏状态。
每个客户端对自身状态的变化有权威性。
通信通常使用UDP

优缺点

优点:

  • 低延迟,因为信息直接从一个客户端传递到另一个客户端。
  • 适用于小型游戏,不需要庞大的服务器支持。

缺点:

  • 难以处理作弊,因为每个客户端都有权更改自己的状态。
  • 对于大型多人在线游戏可能会导致网络流量激增。

适合的场景

小型游戏,例如局域网游戏或小团队合作游戏,不需要中央服务器来维护所有玩家的状态。

案例游戏

  • 《星际争霸》(StarCraft)
    早期的《星际争霸》在局域网游戏中主要使用点对点通信模型,每个客户端直接与其他客户端通信。
  • 《FIFA》系列(局域网模式)
    体育游戏如《FIFA》系列在其局域网对战模式中,通常使用点对点架构来实现玩家之间的连接。

2.1.3 混合型架构

客户端-服务器与点对点相结合,以兼顾两者的优点。

案例游戏

  • 《命令与征服》系列
    某些版本的《命令与征服》使用了混合型架构,结合了客户端-服务器和点对点的优势,使得游戏既可以在局域网中高效运行,又可以通过服务器进行更广泛的匹配和竞赛。
  • 《GTA在线》(Grand Theft Auto Online)
    这款游戏在某些方面使用了类似于客户端-服务器的架构,但在其他方面,如玩家间的直接交互,则采用了点对点通信。

2.2 同步方式

在实际游戏开发中,有时也会采用帧同步和状态同步的混合策略,以平衡实时性和效率。

2.2.1 帧同步 Frame Synchronization

概念:
在帧同步中,游戏被划分为一系列帧,每一帧都表示一个瞬间的游戏状态。
所有玩家在每一帧中发送他们的输入到服务器,服务器进行处理,然后将更新的游戏状态广播给所有玩家。
所有客户端根据接收到的状态更新来渲染下一帧。

工作原理:

  1. 输入收集: 每个客户端在每一帧中记录玩家的输入,例如键盘按键、鼠标移动等。
  2. 输入发送: 客户端将输入信息发送到服务器。
  3. 状态更新: 服务器根据接收到的所有玩家的输入,计算并更新游戏状态。
  4. 状态广播: 服务器将新的游戏状态广播给所有连接的客户端。
  5. 状态接收和渲染: 客户端接收新状态并使用它来渲染下一帧。

优点:

  • 玩家在同一帧中看到相同的游戏状态,保持了实时性。
  • 对于快节奏的游戏,帧同步能提供更好的玩家体验。

缺点:

  • 需要较高的带宽和处理能力,尤其是在大规模多人在线游戏中。
  • 对网络延迟和不稳定性敏感,可能导致不同玩家看到不同的游戏状态。

适用于:

  • 快节奏的实时多人游戏,如射击游戏、格斗游戏等。
  • 要求玩家在同一时刻看到相同状态的场景。

应用场景和游戏案例:

  1. 实时射击游戏:
    应用场景: 快节奏的射击游戏,玩家需要在同一时刻看到相同的敌人和环境状态。
    游戏案例: 如《Counter-Strike: Global Offensive》、《Overwatch》等。
  2. 格斗游戏:
    应用场景: 玩家进行实时对战,需要确保所有玩家看到相同的动作和攻击效果。
    游戏案例: 如《街头霸王》、《超级马里奥派对》等。
  3. 赛车游戏:
    应用场景: 在多人赛车比赛中,所有玩家需要在同一时刻看到相同的赛道和对手位置。
    游戏案例: 如《尘埃3》、《极品飞车》系列等。

2.2.2 状态同步 State Synchronization

概念:

  • 在状态同步中,服务器维护整个游戏世界的状态,而不是每一帧的状态。
  • 客户端定期向服务器请求当前的游戏状态,然后使用接收到的状态更新本地渲染。
  • 不同的客户端在不同的时间可能看到不同的状态,因为他们在不同的时刻请求了状态。

工作原理:

  1. 定期状态请求: 客户端定期向服务器请求当前的游戏状态。
  2. 状态发送: 服务器响应请求,将当前游戏状态发送给客户端。
  3. 状态接收和渲染: 客户端接收到新状态并使用它来更新本地渲染。

优点:

  • 相对较低的带宽需求,因为不需要每一帧都广播完整的游戏状态。
  • 对于网络延迟和不稳定性的容忍度较高。

缺点:

  • 状态同步引入了较大的延迟,因为客户端只能在定期请求状态时才能看到更新。
  • 可能导致不同客户端之间的状态差异,影响玩家之间的互动。

适用于:

  • 较为宽松的同步要求,例如策略游戏、角色扮演游戏等。
  • 对带宽和延迟有较为严格的限制。

应用场景和游戏案例:

  1. 策略游戏:
    应用场景: 缓慢节奏、强调战略和决策的游戏类型,可以容忍一些同步延迟。
    游戏案例: 如《星际争霸》、《文明 VI》等。
  2. 角色扮演游戏(RPG):
    应用场景: 单人或小型多人团队合作,玩家更注重故事和角色发展。
    游戏案例: 如《巫师 3:狂猎》、《上古卷轴 V:天际》等。
  3. 虚拟世界游戏:
    应用场景: 大型多人在线游戏,强调玩家自由探索和社交互动。
    游戏案例: 如《魔兽世界》、《黑色沙漠》等。

2.2.3 混合同步(Hybrid Synchronization)

  • 概念: 结合了多种同步技术,根据游戏的不同部分和需求选择不同的同步策略。
  • 适用场景: 复杂的多人游戏,其中不同游戏元素和互动可能需要不同的同步方法。
  • 优点: 灵活,可以针对不同游戏场景和需求优化。
  • 缺点: 实现复杂,需要精细调整和测试。

3. 游戏引擎网络模块

3.1 Unity官方

UNET(Unity Networking)

UNET是Unity的早期网络模块,旨在简化多人游戏的开发。然而,在Unity 2019.1版本后,Unity宣布停止对UNET的维护,将重心转向新一代的Networking。

UNET的主要特点和组件包括:

  • NetworkManager: 用于管理多人游戏的主要组件,处理连接、断开、玩家管理等。
  • NetworkIdentity: 标识具有网络同步行为的对象。
  • NetworkBehaviour: 通过继承该类,可以在脚本中实现网络同步的行为。
  • SyncVar: 用于标记在客户端和服务器之间同步的变量。
  • RPC(Remote Procedure Call): 用于在客户端和服务器之间调用函数。

UNET的主要缺点在于其设计相对复杂,可能会在大型项目中引起性能问题,并且在Unity版本升级后停止了官方维护。

Networking(Multiplayer HLAPI):

新一代的Networking模块是对UNET的改进和替代,它在Unity 2019.1版本后成为官方推荐的网络解决方案。它通过简化API、提高性能和引入新的概念来改进网络开发体验。

Networking的主要特点和组件包括:

  • NetworkManager: 与UNET中的NetworkManager类似,用于管理多人游戏的主要组件。
  • NetworkIdentity: 标识具有网络同步行为的对象。
  • NetworkBehaviour: 通过继承该类,可以在脚本中实现网络同步的行为。
  • SyncVar: 仍然用于标记在客户端和服务器之间同步的变量。
  • Command 和 ClientRpc: 取代了UNET中的RPC,用于在客户端和服务器之间调用函数。
  • Spawnable Prefabs: 管理在不同客户端之间同步生成和销毁的物体。
  • NetworkTransform: 管理物体的位置和旋转同步。
  • NetworkAnimator: 用于同步动画状态。

新一代的Networking模块在性能和易用性上有所提升,因此在选择网络模块时,推荐使用Unity的Networking。具体选择取决于项目需求、Unity版本以及个人或团队的熟悉程度。

3.2 社区框架

Mirror 是一个基于 Unity 的开源网络框架,专门用于简化和增强多人游戏的开发。它是从 Unity 的 Networking 模块中分离出来的独立项目,旨在提供更好的性能、更简单的 API 和更好的可维护性。

4. 多线程

5. 同步算法

6. 网络优化

6.1 预测与回滚 Prediction and Rollback

2. 锁步(Lockstep)机制:

  • 概念: 在锁步机制中,所有的客户端必须在进入下一帧之前达成当前帧的一致状态。这通常通过交换和确认每个玩家的输入来实现。
  • 适用场景: 需要严格一致性的策略游戏和回合制游戏。
  • 优点: 确保了游戏状态的完全一致性。
  • 缺点: 对网络延迟非常敏感,可能导致游戏进度放慢。

4. 区域同步(Area of Interest Synchronization):

  • 概念: 只同步玩家当前所在区域或感兴趣区域的状态,而非整个游戏世界。

  • 适用场景: 大型多人在线游戏(MMORPGs)和广阔的开放世界游戏。

  • 优点: 减少了需要同步的数据量,提高了效率,特别是在大型游戏世界中。

  • 缺点: 需要复杂的管理逻辑来处理玩家移动和不同区域之间的交互。

7. 项目实战