Unity网络开发从入门到精通:从基础原理到企业级实战的完全指南
## 前言:为什么网络开发是Unity开发者的分水岭
你是否曾经遇到过这些问题:
- 看到别人开发的多人联机游戏,自己却不知从何下手
- 对"同步"、"帧同步"、"状态同步"这些概念感到迷茫
- 用Unity自带的NetworkManager做出的多人游戏卡顿严重
- 面对网络延迟、丢包、带宽限制等问题束手无策
- 不知道如何设计一个能支撑1000人同时在线的服务器架构
这些问题都指向同一个事实:**网络开发是Unity开发者从"初级"到"高级"的分水岭**。一个精通网络开发的Unity开发者,不仅能创造出引人入胜的多人游戏体验,更能理解游戏开发的完整技术栈,成为团队中的技术骨干。
本文将为你构建完整的Unity网络知识体系,从TCP/IP协议基础出发,深入到Unity网络框架的底层实现,再到高并发服务器架构设计,帮助你真正掌握Unity网络开发。
---
## 第一部分:网络编程基础知识
### 1.1 计算机网络核心协议栈
#### OSI七层模型与TCP/IP四层模型
```
OSI七层模型 → TCP/IP四层模型的映射关系:
┌─────────────────────┐ ┌─────────────────────┐
│ 7. 应用层 │ │ 4. 应用层 │
│ (HTTP, FTP, DNS) │ │ (HTTP, FTP, DNS) │
├─────────────────────┤ ├─────────────────────┤
│ 6. 表示层 │ │ │
│ (加密, 压缩) │────┘ │
├─────────────────────┤ │
│ 5. 会话层 │ │
│ (会话管理) │──────────────────────────┘
├─────────────────────┤ ┌─────────────────────┐
│ 4. 传输层 │ │ 3. 传输层 │
│ (TCP, UDP) │ │ (TCP, UDP) │
├─────────────────────┤ ├─────────────────────┤
│ 3. 网络层 │ │ 2. 网络层 │
│ (IP, ICMP, ARP) │ │ (IP, ICMP, ARP) │
├─────────────────────┤ ├─────────────────────┤
│ 2. 数据链路层 │ │ 1. 网络接口层 │
│ (以太网, WiFi) │ │ (以太网, WiFi) │
├─────────────────────┤ ├─────────────────────┤
│ 1. 物理层 │ │ 0. 物理介质 │
│ (网线, 光纤) │ │ (网线, 光纤) │
└─────────────────────┘ └─────────────────────┘
```
**Unity开发者必须理解的协议**:
| 协议 | 层级 | 特点 | 游戏应用场景 |
|------|------|------|--------------|
| **TCP** | 传输层 | 可靠、有序、重传 | 登录、交易、聊天等需要可靠性的场景 |
| **UDP** | 传输层 | 不可靠、无连接、高速 | 游戏状态同步、语音、广播等对实时性要求高的场景 |
| **HTTP** | 应用层 | 请求-响应模型,基于TCP | 登录验证、资源下载、排行榜等 |
| **WebSocket** | 应用层 | 双向通信,基于TCP | 长连接服务、实时数据推送 |
| **QUIC** | 传输层 | 基于UDP的可靠传输 | 低延迟游戏、跨平台通信 |
#### TCP与UDP的深度对比
```csharp
// TCP和UDP的代码对比示例
public class TcpUdpComparison : MonoBehaviour {
void Start() {
// TCP客户端示例
StartCoroutine(TcpClientExample());
// UDP客户端示例
StartCoroutine(UdpClientExample());
}
IEnumerator TcpClientExample() {
// 创建TCP客户端
TcpClient client = new TcpClient();
// 连接服务器
yield return StartCoroutine(
ConnectTcp(client, "127.0.0.1", 8888));
if (client.Connected) {
// 发送数据
NetworkStream stream = client.GetStream();
byte[] data = Encoding.UTF8.GetBytes("Hello TCP Server!");
stream.Write(data, 0, data.Length);
// 接收响应
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Debug.Log("TCP Response: " + response);
client.Close();
}
}
IEnumerator UdpClientExample() {
// 创建UDP客户端
UdpClient client = new UdpClient();
// 发送数据(无需提前连接)
byte[] data = Encoding.UTF8.GetBytes("Hello UDP Server!");
IPEndPoint serverEndPoint = new IPEndPoint(
IPAddress.Parse("127.0.0.1"), 8889);
client.Send(data, data.Length, serverEndPoint);
// 接收响应
byte[] buffer = client.Receive(ref serverEndPoint);
string response = Encoding.UTF8.GetString(buffer);
Debug.Log("UDP Response: " + response);
client.Close();
}
}
```
**性能对比**:
| 特性 | TCP | UDP | 游戏中的权衡 |
|------|-----|-----|--------------|
| **可靠性** | 可靠(保证送达) | 不可靠(可能丢失) | 关键数据用TCP,实时数据用UDP |
| **传输效率** | 较低(握手、确认) | 极高(无额外开销) | UDP适合实时游戏状态同步 |
| **延迟** | 较高(重传机制) | 极低(直接发送) | 竞技类游戏必须使用UDP |
| **顺序性** | 保证顺序 | 不保证顺序 | UDP需要自己处理顺序问题 |
| **连接管理** | 需要建立连接 | 无连接 | TCP适合长连接,UDP适合短消息 |
| **开销** | 20-60字节/包 | 8字节/包 | UDP带宽占用约为TCP的1/3 |
### 1.2 网络编程核心概念
#### IP地址、端口、套接字(Socket)
```csharp
// Socket编程基础示例
public class SocketBasics : MonoBehaviour {
void Start() {
// 创建TCP Socket
Socket tcpSocket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp
);
// 创建UDP Socket
Socket udpSocket = new Socket(
AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp
);
// 解析IP地址
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
// 网络端点(IP + 端口)
IPEndPoint endPoint = new IPEndPoint(ipAddress, 8888);
Debug.Log($"IP地址: {ipAddress}");
Debug.Log($"端口: {endPoint.Port}");
Debug.Log($"网络端点: {endPoint}");
}
}
```
**关键概念解释**:
- **IP地址**:网络设备的唯一标识(如192.168.1.100)
- **端口**:同一设备上不同服务的标识(范围0-65535,0-1023为系统端口)
- **Socket**:应用程序与网络之间的通信端点
- **TCP Socket**:基于流的可靠通信
- **UDP Socket**:基于数据报的不可靠通信
#### 字节序与数据序列化
```csharp
// 字节序处理示例
public class ByteOrderHandling : MonoBehaviour {
void Start() {
// 主机字节序到网络字节序的转换
int number = 12345;
// 转换为网络字节序(大端)
byte[] networkBytes = BitConverter.GetBytes(
IPAddress.HostToNetworkOrder(number));
// 从网络字节序转换为主机字节序
int hostNumber = IPAddress.NetworkToHostOrder(
BitConverter.ToInt32(networkBytes, 0));
Debug.Log($"原始值: {number}");
Debug.Log($"网络字节序: {BitConverter.ToString(networkBytes)}");
Debug.Log($"转换后的值: {hostNumber}");
}
}
// 自定义数据序列化
public class CustomDataSerializer {
// 将对象序列化为字节数组
public static byte[] Serialize(PlayerData data) {
using (MemoryStream ms = new MemoryStream()) {
using (BinaryWriter writer = new BinaryWriter(ms)) {
writer.Write(data.playerId);
writer.Write(data.username);
writer.Write(data.position.x);
writer.Write(data.position.y);
writer.Write(data.position.z);
writer.Write(data.health);
writer.Write(data.isAlive);
}
return ms.ToArray();
}
}
// 从字节数组反序列化为对象
public static PlayerData Deserialize(byte[] data) {
using (MemoryStream ms = new MemoryStream(data)) {
using (BinaryReader reader = new BinaryReader(ms)) {
PlayerData result = new PlayerData();
result.playerId = reader.ReadInt32();
result.username = reader.ReadString();
result.position = new Vector3(
reader.ReadSingle(),
reader.ReadSingle(),
reader.ReadSingle());
result.health = reader.ReadSingle();
result.isAlive = reader.ReadBoolean();
return result;
}
}
}
}
public struct PlayerData {
public int playerId;
public string username;
public Vector3 position;
public float health;
public bool isAlive;
}
```
**序列化方案对比**:
| 序列化方案 | 优点 | 缺点 | 游戏应用场景 |
|------------|------|------|--------------|
| **Binary** | 性能高、体积小 | 可读性差 | 游戏状态同步 |
| **JSON** | 可读性好、跨平台 | 体积大、解析慢 | 配置文件、非关键数据 |
| **Protobuf** | 体积小、性能高、跨平台 | 需要定义Schema | 网络通信、数据存储 |
| **MessagePack** | 类似JSON但体积更小 | 生态不如JSON完善 | 高性能通信场景 |
#### 网络延迟、丢包与带宽限制
```csharp
// 网络质量监测工具
public class NetworkQualityMonitor : MonoBehaviour {
private Dictionary rttHistory =
new Dictionary();
private float packetLossRate = 0f;
private int totalPacketsSent = 0;
private int totalPacketsReceived = 0;
void Update() {
// 模拟网络质量计算
if (Time.frameCount % 60 == 0) {
float rtt = CalculateRTT();
packetLossRate = CalculatePacketLoss();
float bandwidthUsage = CalculateBandwidthUsage();
Debug.Log($"RTT: {rtt:F2}ms");
Debug.Log($"丢包率: {packetLossRate:P1}");
Debug.Log($"带宽: {bandwidthUsage:F2} KB/s");
}
}
float CalculateRTT() {
// 测量往返时间
return UnityEngine.Random.Range(20f, 200f);
}
float CalculatePacketLoss() {
// 计算丢包率
return (totalPacketsSent - totalPacketsReceived) / (float)totalPacketsSent;
}
float CalculateBandwidthUsage() {
// 计算带宽使用
return UnityEngine.Random.Range(10f, 1000f);
}
}
```
**游戏中的网络质量应对策略**:
| 网络问题 | 应对策略 | 技术实现 |
|----------|----------|----------|
| **高延迟** | 预测插值、延迟补偿 | 基于历史位置预测未来位置 |
| **丢包** | 冗余发送、快速重传 | UDP使用NACK机制快速请求重传 |
| **带宽限制** | 数据压缩、带宽自适应 | 根据网络质量调整发送频率 |
| **抖动** | 缓冲区、平滑算法 | 对收到的数据进行时间戳排序 |
---
## 第二部分:Unity网络编程基础
### 2.1 Unity网络通信底层API
#### Unity的Socket封装
```csharp
// Unity中使用Socket进行TCP通信示例
public class TcpSocketExample : MonoBehaviour {
private Socket clientSocket;
private byte[] receiveBuffer = new byte[4096];
void Start() {
// 初始化TCP客户端
clientSocket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp
);
// 连接服务器
ConnectToServer("127.0.0.1", 8888);
}
void ConnectToServer(string ip, int port) {
try {
clientSocket.BeginConnect(
ip, port, OnConnectCallback, clientSocket);
} catch (Exception e) {
Debug.LogError("连接失败: " + e.Message);
}
}
void OnConnectCallback(IAsyncResult ar) {
try {
Socket socket = (Socket)ar.AsyncState;
socket.EndConnect(ar);
Debug.Log("成功连接到服务器");
// 开始接收数据
socket.BeginReceive(
receiveBuffer, 0, receiveBuffer.Length,
SocketFlags.None, OnReceiveCallback, socket);
} catch (Exception e) {
Debug.LogError("连接回调错误: " + e.Message);
}
}
void OnReceiveCallback(IAsyncResult ar) {
try {
Socket socket = (Socket)ar.AsyncState;
int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0) {
// 处理收到的数据
string message = Encoding.UTF8.GetString(
receiveBuffer, 0, bytesRead);
Debug.Log("收到服务器消息: " + message);
// 继续接收下一个消息
socket.BeginReceive(
receiveBuffer, 0, receiveBuffer.Length,
SocketFlags.None, OnReceiveCallback, socket);
} else {
Debug.Log("服务器断开连接");
socket.Close();
}
} catch (Exception e) {
Debug.LogError("接收回调错误: " + e.Message);
}
}
// 发送数据到服务器
public void SendMessage(string message) {
if (clientSocket != null && clientSocket.Connected) {
byte[] data = Encoding.UTF8.GetBytes(message);
clientSocket.BeginSend(
data, 0, data.Length,
SocketFlags.None, OnSendCallback, clientSocket);
}
}
void OnSendCallback(IAsyncResult ar) {
try {
Socket socket = (Socket)ar.AsyncState;
int bytesSent = socket.EndSend(ar);
Debug.Log("成功发送 " + bytesSent + " 字节");
} catch (Exception e) {
Debug.LogError("发送回调错误: " + e.Message);
}
}
}
```
#### UDP通信实现
```csharp
// Unity中使用Socket进行UDP通信示例
public class UdpSocketExample : MonoBehaviour {
private Socket udpSocket;
private byte[] receiveBuffer = new byte[4096];
private IPEndPoint serverEndPoint;
void Start() {
// 初始化UDP Socket
udpSocket = new Socket(
AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp
);
// 绑定本地端口(可选)
udpSocket.Bind(new IPEndPoint(IPAddress.Any, 0));
// 设置服务器地址
serverEndPoint = new IPEndPoint(
IPAddress.Parse("127.0.0.1"), 8889);
// 开始接收数据
StartReceiving();
// 发送测试消息
SendUdpMessage("Hello UDP Server!");
}
void StartReceiving() {
try {
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
udpSocket.BeginReceiveFrom(
receiveBuffer, 0, receiveBuffer.Length,
SocketFlags.None, ref remoteEndPoint,
OnReceiveFromCallback, remoteEndPoint);
} catch (Exception e) {
Debug.LogError("UDP接收错误: " + e.Message);
}
}
void OnReceiveFromCallback(IAsyncResult ar) {
try {
IPEndPoint remoteEndPoint = (IPEndPoint)ar.AsyncState;
int bytesRead = udpSocket.EndReceiveFrom(
ar, ref remoteEndPoint);
if (bytesRead > 0) {
string message = Encoding.UTF8.GetString(
receiveBuffer, 0, bytesRead);
Debug.Log($"收到来自 {remoteEndPoint} 的消息: {message}");
}
// 继续接收
StartReceiving();
} catch (Exception e) {
Debug.LogError("UDP接收回调错误: " + e.Message);
}
}
void SendUdpMessage(string message) {
try {
byte[] data = Encoding.UTF8.GetBytes(message);
udpSocket.BeginSendTo(
data, 0, data.Length,
SocketFlags.None, serverEndPoint,
OnSendToCallback, serverEndPoint);
} catch (Exception e) {
Debug.LogError("UDP发送错误: " + e.Message);
}
}
void OnSendToCallback(IAsyncResult ar) {
try {
IPEndPoint endPoint = (IPEndPoint)ar.AsyncState;
int bytesSent = udpSocket.EndSendTo(ar);
Debug.Log($"成功发送 {bytesSent} 字节到 {endPoint}");
} catch (Exception e) {
Debug.LogError("UDP发送回调错误: " + e.Message);
}
}
}
```
### 2.2 Unity高级网络API
#### UnityWebRequest与HTTP通信
```csharp
// UnityWebRequest示例 - 异步GET请求
public class UnityWebRequestExample : MonoBehaviour {
void Start() {
// 发送GET请求
StartCoroutine(SendGetRequest(
"https://api.example.com/users/123"));
// 发送POST请求
StartCoroutine(SendPostRequest(
"https://api.example.com/login",
new { username = "test", password = "123456" }));
// 下载文件
StartCoroutine(DownloadFile(
"https://example.com/assets/texture.jpg",
Application.persistentDataPath + "/texture.jpg"));
}
IEnumerator SendGetRequest(string url) {
using (UnityWebRequest request = UnityWebRequest.Get(url)) {
// 设置请求头
request.SetRequestHeader(
"Authorization", "Bearer your_token_here");
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success) {
Debug.Log("GET请求成功: " + request.downloadHandler.text);
// 解析JSON响应
UserData user = JsonUtility.FromJson(
request.downloadHandler.text);
Debug.Log($"用户名: {user.username}, 等级: {user.level}");
} else {
Debug.LogError("GET请求失败: " + request.error);
}
}
}
IEnumerator SendPostRequest(string url, object postData) {
string jsonData = JsonUtility.ToJson(postData);
byte[] postBytes = Encoding.UTF8.GetBytes(jsonData);
using (UnityWebRequest request = UnityWebRequest.Post(
url, "POST")) {
UploadHandlerRaw uploadHandler = new UploadHandlerRaw(postBytes);
uploadHandler.contentType = "application/json";
request.uploadHandler = uploadHandler;
request.SetRequestHeader(
"Content-Type", "application/json");
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success) {
Debug.Log("POST请求成功: " + request.downloadHandler.text);
} else {
Debug.LogError("POST请求失败: " + request.error);
}
}
}
IEnumerator DownloadFile(string url, string savePath) {
using (UnityWebRequest request = UnityWebRequestMultimedia.GetTexture(url)) {
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success) {
Texture2D texture = DownloadHandlerTexture.GetContent(request);
Debug.Log("文件下载成功");
// 保存到本地
byte[] pngData = texture.EncodeToPNG();
File.WriteAllBytes(savePath, pngData);
Debug.Log("文件已保存到: " + savePath);
} else {
Debug.LogError("文件下载失败: " + request.error);
}
}
}
}
[System.Serializable]
public class UserData {
public int id;
public string username;
public int level;
public string avatarUrl;
}
```
#### WebSocket实时通信
```csharp
// Unity WebSocket示例
public class WebSocketExample : MonoBehaviour {
private WebSocket webSocket;
async void Start() {
// 连接WebSocket服务器
webSocket = new WebSocket(
new Uri("wss://api.example.com/ws"));
// 设置接收回调
webSocket.OnMessage += (sender, e) => {
Debug.Log("收到WebSocket消息: " + Encoding.UTF8.GetString(e.RawData));
};
webSocket.OnError += (sender, e) => {
Debug.LogError("WebSocket错误: " + e.Message);
};
webSocket.OnClose += (sender, e) => {
Debug.Log("WebSocket连接关闭: " + e.Reason);
};
// 异步连接
await webSocket.ConnectAsync();
Debug.Log("WebSocket连接成功");
// 发送消息
await SendWebSocketMessage("Hello WebSocket!");
}
async Task SendWebSocketMessage(string message) {
if (webSocket != null && webSocket.State == WebSocketState.Open) {
byte[] data = Encoding.UTF8.GetBytes(message);
await webSocket.SendAsync(
new ArraySegment(data),
WebSocketMessageType.Text,
true,
CancellationToken.None);
Debug.Log("WebSocket消息已发送");
}
}
void OnDestroy() {
// 关闭WebSocket连接
if (webSocket != null && webSocket.State == WebSocketState.Open) {
webSocket.CloseAsync(
WebSocketCloseStatus.NormalClosure,
"连接关闭",
CancellationToken.None);
}
}
}
```
### 2.3 第三方网络库集成
#### Photon PUN 2集成与使用
```csharp
// Photon PUN 2 基本使用示例
public class PhotonNetworkManager : MonoBehaviourPunCallbacks {
[Header("Room Settings")]
public string roomName = "DefaultRoom";
public int maxPlayers = 10;
[Header("Player Settings")]
public GameObject playerPrefab;
public Transform spawnPoint;
void Start() {
// 连接到Photon服务器
PhotonNetwork.ConnectUsingSettings();
}
// 连接到Master服务器成功
public override void OnConnectedToMaster() {
Debug.Log("成功连接到Photon Master服务器");
// 加入或创建房间
RoomOptions roomOptions = new RoomOptions();
roomOptions.MaxPlayers = (byte)maxPlayers;
roomOptions.IsVisible = true;
roomOptions.IsOpen = true;
PhotonNetwork.JoinOrCreateRoom(roomName, roomOptions, TypedLobby.Default);
}
// 加入房间成功
public override void OnJoinedRoom() {
Debug.Log("成功加入房间: " + PhotonNetwork.CurrentRoom.Name);
Debug.Log("当前房间玩家数: " + PhotonNetwork.CurrentRoom.PlayerCount);
// 生成玩家对象
SpawnPlayer();
}
// 生成玩家
void SpawnPlayer() {
if (playerPrefab != null && spawnPoint != null) {
// 使用PhotonNetwork生成同步对象
GameObject player = PhotonNetwork.Instantiate(
playerPrefab.name,
spawnPoint.position,
spawnPoint.rotation,
0);
// 设置玩家昵称
PhotonNetwork.NickName = "Player_" + Random.Range(1000, 9999);
Debug.Log("生成玩家: " + PhotonNetwork.NickName);
}
}
// 其他玩家加入房间
public override void OnPlayerEnteredRoom(Player newPlayer) {
Debug.Log("玩家加入房间: " + newPlayer.NickName);
}
// 玩家离开房间
public override void OnPlayerLeftRoom(Player otherPlayer) {
Debug.Log("玩家离开房间: " + otherPlayer.NickName);
}
}
// 玩家同步控制器
public class PlayerSyncController : MonoBehaviourPunCallbacks, IPunObservable {
private Vector3 targetPosition;
private Quaternion targetRotation;
[Header("Sync Settings")]
public float smoothSpeed = 10f;
public bool useInterpolation = true;
void Start() {
targetPosition = transform.position;
targetRotation = transform.rotation;
// 只有本地玩家可以控制
GetComponent().enabled = photonView.IsMine;
}
void Update() {
if (photonView.IsMine) {
// 本地玩家输入处理
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 movement = transform.right * horizontal + transform.forward * vertical;
GetComponent().Move(movement * Time.deltaTime * 5f);
// 相机旋转
float mouseX = Input.GetAxis("Mouse X");
transform.Rotate(Vector3.up, mouseX * 2f);
} else {
// 远程玩家插值
if (useInterpolation) {
transform.position = Vector3.Lerp(
transform.position, targetPosition,
smoothSpeed * Time.deltaTime);
transform.rotation = Quaternion.Lerp(
transform.rotation, targetRotation,
smoothSpeed * Time.deltaTime);
} else {
transform.position = targetPosition;
transform.rotation = targetRotation;
}
}
}
// 同步数据(Photon会自动调用)
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
if (stream.IsWriting) {
// 本地玩家发送数据
stream.SendNext(transform.position);
stream.SendNext(transform.rotation);
} else {
// 远程玩家接收数据
targetPosition = (Vector3)stream.ReceiveNext();
targetRotation = (Quaternion)stream.ReceiveNext();
// 延迟补偿
float lag = (float)(PhotonNetwork.Time - info.timestamp);
targetPosition += GetComponent().velocity * lag;
}
}
}
```
#### Mirror网络框架入门
```csharp
// Mirror网络管理器示例
public class MirrorNetworkManager : NetworkManager {
[Header("Game Settings")]
public GameObject playerPrefab;
public Transform[] spawnPoints;
// 服务器启动成功
public override void OnStartServer() {
Debug.Log("Mirror服务器启动成功");
// 注册自定义消息
NetworkServer.RegisterHandler(
CustomMsgType.PlayerStats, OnPlayerStatsReceived);
}
// 客户端连接成功
public override void OnClientConnect() {
Debug.Log("客户端连接服务器成功");
// 发送玩家数据到服务器
PlayerStatsMessage msg = new PlayerStatsMessage {
playerId = 123,
username = "TestPlayer",
level = 10,
score = 1500
};
NetworkClient.Send(CustomMsgType.PlayerStats, msg);
}
// 生成玩家
public override void OnServerAddPlayer(NetworkConnectionToClient conn) {
// 选择随机出生点
Transform spawnPoint = spawnPoints[Random.Range(0, spawnPoints.Length)];
// 生成玩家对象
GameObject player = Instantiate(
playerPrefab, spawnPoint.position, spawnPoint.rotation);
// 给玩家分配网络身份
NetworkServer.AddPlayerForConnection(conn, player);
Debug.Log("生成玩家: " + conn.connectionId);
}
// 处理自定义消息
void OnPlayerStatsReceived(NetworkConnectionToClient conn, PlayerStatsMessage msg) {
Debug.Log($"收到玩家数据: {msg.username} (等级 {msg.level}, 分数 {msg.score})");
}
}
// 自定义消息类型
public enum CustomMsgType {
PlayerStats = MsgType.Highest + 1
}
// 玩家数据消息
public struct PlayerStatsMessage : NetworkMessage {
public int playerId;
public string username;
public int level;
public int score;
}
// Mirror玩家控制器
public class MirrorPlayerController : NetworkBehaviour {
[SyncVar(hook = nameof(OnHealthChanged))]
public int health = 100;
[SyncVar]
public string playerName = "Player";
void Update() {
// 只有本地玩家可以控制
if (!isLocalPlayer) return;
// 玩家输入
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 movement = transform.right * horizontal + transform.forward * vertical;
transform.Translate(movement * Time.deltaTime * 5f, Space.World);
// 射击
if (Input.GetMouseButtonDown(0)) {
CmdShoot();
}
}
// 命令:从客户端发送到服务器
[Command]
void CmdShoot() {
Debug.Log("服务器收到射击命令");
// 在服务器生成子弹
GameObject bullet = Instantiate(
bulletPrefab,
transform.position + transform.forward,
transform.rotation);
NetworkServer.Spawn(bullet);
// 告诉所有客户端播放射击效果
RpcPlayShootEffect();
}
// 客户端RPC:从服务器发送到所有客户端
[ClientRpc]
void RpcPlayShootEffect() {
// 播放射击动画或音效
Debug.Log("播放射击效果");
}
// SyncVar钩子函数
void OnHealthChanged(int oldHealth, int newHealth) {
Debug.Log($"生命值变化: {oldHealth} → {newHealth}");
// 更新UI
if (isLocalPlayer) {
UpdateHealthUI(newHealth);
}
}
void UpdateHealthUI(int health) {
// 更新生命值显示
}
}
```
---
## 第三部分:多人游戏网络同步技术
### 3.1 游戏网络同步基础
#### 帧同步与状态同步的核心区别
```
帧同步 vs 状态同步的技术对比:
┌─────────────────────────┬─────────────────────────┬─────────────────────────┐
│ 特性 │ 帧同步 │ 状态同步 │
├─────────────────────────┼─────────────────────────┼─────────────────────────┤
│ **核心原理** │ 同步输入,各端独立计算 │ 同步状态,服务器权威 │
│ **数据量** │ 极小(仅输入) │ 较大(状态数据) │
│ **一致性** │ 强一致(需确定性算法) │ 最终一致(允许短期差异)│
│ **服务器压力** │ 极小(仅转发输入) │ 极大(需处理所有逻辑) │
│ **客户端性能要求** │ 较高(需实时计算) │ 较低(状态直接应用) │
│ **外挂防护** │ 困难(客户端有计算逻辑)│ 容易(服务器权威验证) │
│ **开发复杂度** │ 高(需确定性逻辑) │ 中(状态管理) │
│ **适合游戏类型** │ 竞技类、格斗类 │ RPG、MMO、开放世界 │
│ **代表游戏** │ 星际争霸、拳皇 │ LOL、魔兽世界 │
└─────────────────────────┴─────────────────────────┴─────────────────────────┘
```
```csharp
// 帧同步输入收集与发送
public class FrameSyncInput : MonoBehaviour {
[Header("Frame Settings")]
public int frameRate = 30; // 每秒30帧
public float sendInterval = 0.1f; // 每100ms发送一次
private Queue inputFrames = new Queue();
private float frameTimer = 0f;
private float sendTimer = 0f;
void Update() {
// 按固定帧率收集输入
frameTimer += Time.deltaTime;
if (frameTimer >= 1f / frameRate) {
frameTimer = 0f;
CollectInputFrame();
}
// 定期发送输入到服务器
sendTimer += Time.deltaTime;
if (sendTimer >= sendInterval) {
sendTimer = 0f;
SendInputFrames();
}
}
// 收集单帧输入
void CollectInputFrame() {
InputFrame frame = new InputFrame();
frame.frameId = Time.frameCount;
frame.timestamp = Time.realtimeSinceStartup;
frame.horizontal = Input.GetAxis("Horizontal");
frame.vertical = Input.GetAxis("Vertical");
frame.jump = Input.GetButton("Jump");
frame.attack = Input.GetMouseButton(0);
inputFrames.Enqueue(frame);
// 本地执行输入
ExecuteInputFrame(frame);
}
// 执行输入帧(必须是确定性的)
void ExecuteInputFrame(InputFrame frame) {
// 移动逻辑(必须是纯函数,无随机、无时间依赖)
Vector3 movement = transform.right * frame.horizontal +
transform.forward * frame.vertical;
transform.Translate(movement * 5f / frameRate, Space.World);
// 跳跃逻辑
if (frame.jump && IsGrounded()) {
GetComponent().AddForce(Vector3.up * 5f, ForceMode.Impulse);
}
}
// 将输入帧发送到服务器
void SendInputFrames() {
if (inputFrames.Count == 0) return;
// 打包多个输入帧
InputFrame[] framesToSend = inputFrames.ToArray();
inputFrames.Clear();
// 发送到服务器(通常用UDP)
byte[] data = InputFrameSerializer.Serialize(framesToSend);
networkManager.SendData(data);
}
// 检查是否在地面上(确定性实现)
bool IsGrounded() {
return Physics.Raycast(
transform.position, Vector3.down,
GetComponent().bounds.extents.y + 0.1f);
}
}
// 输入帧结构(必须是值类型,保证确定性)
public struct InputFrame {
public int frameId;
public float timestamp;
public float horizontal;
public float vertical;
public bool jump;
public bool attack;
}
// 输入帧序列化器
public static class InputFrameSerializer {
public static byte[] Serialize(InputFrame[] frames) {
using (MemoryStream ms = new MemoryStream()) {
using (BinaryWriter writer = new BinaryWriter(ms)) {
writer.Write(frames.Length);
foreach (var frame in frames) {
writer.Write(frame.frameId);
writer.Write(frame.timestamp);
writer.Write(frame.horizontal);
writer.Write(frame.vertical);
writer.Write(frame.jump);
writer.Write(frame.attack);
}
return ms.ToArray();
}
}
}
public static InputFrame[] Deserialize(byte[] data) {
using (MemoryStream ms = new MemoryStream(data)) {
using (BinaryReader reader = new BinaryReader(ms)) {
int count = reader.ReadInt32();
InputFrame[] frames = new InputFrame[count];
for (int i = 0; i < count; i++) {
frames[i] = new InputFrame {
frameId = reader.ReadInt32(),
timestamp = reader.ReadSingle(),
horizontal = reader.ReadSingle(),
vertical = reader.ReadSingle(),
jump = reader.ReadBoolean(),
attack = reader.ReadBoolean()
};
}
return frames;
}
}
}
}
```
#### 游戏状态同步设计
```csharp
// 状态同步管理器
public class StateSyncManager : MonoBehaviour {
[Header("Sync Settings")]
public int sendRate = 20; // 每秒发送20次
public float interpolationDelay = 0.1f; // 100ms延迟缓冲
private Dictionary playerStates =
new Dictionary();
private float sendTimer = 0f;
void Update() {
// 定期发送本地玩家状态
sendTimer += Time.deltaTime;
if (sendTimer >= 1f / sendRate) {
sendTimer = 0f;
SendLocalPlayerState();
}
// 应用远程玩家状态
ApplyRemotePlayerStates();
}
// 发送本地玩家状态
void SendLocalPlayerState() {
if (localPlayer == null) return;
PlayerState state = new PlayerState {
playerId = localPlayer.playerId,
timestamp = Time.realtimeSinceStartup,
position = localPlayer.transform.position,
rotation = localPlayer.transform.rotation,
velocity = localPlayer.GetComponent().velocity,
health = localPlayer.health,
mana = localPlayer.mana,
animationState = localPlayer.currentAnimationState
};
// 发送到服务器(TCP或可靠UDP)
byte[] data = StateSerializer.Serialize(state);
networkManager.SendReliableData(data);
}
// 接收远程玩家状态
public void OnPlayerStateReceived(byte[] data) {
PlayerState state = StateSerializer.Deserialize(data);
if (!playerStates.ContainsKey(state.playerId)) {
playerStates[state.playerId] = new PlayerState();
}
// 添加到状态缓冲区进行插值
playerStates[state.playerId] = state;
}
// 应用远程玩家状态(带插值)
void ApplyRemotePlayerStates() {
foreach (var kvp in playerStates) {
int playerId = kvp.Key;
PlayerState state = kvp.Value;
GameObject player = GetPlayerById(playerId);
if (player == null) continue;
// 简单插值实现
PlayerController controller = player.GetComponent();
float interpolationFactor = sendRate * Time.deltaTime;
controller.targetPosition = Vector3.Lerp(
controller.targetPosition, state.position,
interpolationFactor);
controller.targetRotation = Quaternion.Lerp(
controller.targetRotation, state.rotation,
interpolationFactor);
// 立即应用非位置状态
controller.health = state.health;
controller.mana = state.mana;
controller.animationState = state.animationState;
}
}
}
// 玩家状态结构
public struct PlayerState {
public int playerId;
public float timestamp;
public Vector3 position;
public Quaternion rotation;
public Vector3 velocity;
public float health;
public float mana;
public int animationState;
}
// 状态序列化器
public static class StateSerializer {
public static byte[] Serialize(PlayerState state) {
using (MemoryStream ms = new MemoryStream()) {
using (BinaryWriter writer = new BinaryWriter(ms)) {
writer.Write(state.playerId);
writer.Write(state.timestamp);
WriteVector3(writer, state.position);
WriteQuaternion(writer, state.rotation);
WriteVector3(writer, state.velocity);
writer.Write(state.health);
writer.Write(state.mana);
writer.Write(state.animationState);
return ms.ToArray();
}
}
}
public static PlayerState Deserialize(byte[] data) {
using (MemoryStream ms = new MemoryStream(data)) {
using (BinaryReader reader = new BinaryReader(ms)) {
PlayerState state = new PlayerState();
state.playerId = reader.ReadInt32();
state.timestamp = reader.ReadSingle();
state.position = ReadVector3(reader);
state.rotation = ReadQuaternion(reader);
state.velocity = ReadVector3(reader);
state.health = reader.ReadSingle();
state.mana = reader.ReadSingle();
state.animationState = reader.ReadInt32();
return state;
}
}
}
static void WriteVector3(BinaryWriter writer, Vector3 v) {
writer.Write(v.x);
writer.Write(v.y);
writer.Write(v.z);
}
static Vector3 ReadVector3(BinaryReader reader) {
return new Vector3(
reader.ReadSingle(),
reader.ReadSingle(),
reader.ReadSingle());
}
static void WriteQuaternion(BinaryWriter writer, Quaternion q) {
writer.Write(q.x);
writer.Write(q.y);
writer.Write(q.z);
writer.Write(q.w);
}
static Quaternion ReadQuaternion(BinaryReader reader) {
return new Quaternion(
reader.ReadSingle(),
reader.ReadSingle(),
reader.ReadSingle(),
reader.ReadSingle());
}
}
```
### 3.2 高级同步技术
#### 插值与预测算法
```csharp
// 高级插值与预测系统
public class AdvancedInterpolation : MonoBehaviour {
[Header("Interpolation Settings")]
public int bufferSize = 10; // 保存10个状态
public float predictionTime = 0.1f; // 预测100ms后的位置
private CircularBuffer stateBuffer =
new CircularBuffer(10);
private PlayerController controller;
void Start() {
controller = GetComponent();
}
// 接收新的状态
public void OnStateReceived(PlayerState state) {
stateBuffer.Add(state);
// 状态缓冲足够时开始预测
if (stateBuffer.Count >= 3) {
StartPrediction();
}
}
// 开始预测
void StartPrediction() {
// 获取最近三个状态
PlayerState state0 = stateBuffer[stateBuffer.Count - 1];
PlayerState state1 = stateBuffer[stateBuffer.Count - 2];
PlayerState state2 = stateBuffer[stateBuffer.Count - 3];
// 计算速度和加速度
Vector3 velocity0 = (state0.position - state1.position) /
(state0.timestamp - state1.timestamp);
Vector3 velocity1 = (state1.position - state2.position) /
(state1.timestamp - state2.timestamp);
Vector3 acceleration = (velocity0 - velocity1) /
(state0.timestamp - state1.timestamp);
// 预测未来位置
float timeSinceLastUpdate = Time.realtimeSinceStartup - state0.timestamp;
Vector3 predictedPosition = PredictPosition(
state0.position, velocity0, acceleration,
timeSinceLastUpdate + predictionTime);
// 应用预测位置
controller.targetPosition = predictedPosition;
}
// 二次函数预测位置
Vector3 PredictPosition(
Vector3 initialPos, Vector3 initialVel,
Vector3 acceleration, float time) {
return initialPos + initialVel * time +
0.5f * acceleration * time * time;
}
// 贝塞尔曲线平滑
Vector3 BezierSmooth(Vector3 p0, Vector3 p1, Vector3 p2, float t) {
Vector3 q0 = Vector3.Lerp(p0, p1, t);
Vector3 q1 = Vector3.Lerp(p1, p2, t);
return Vector3.Lerp(q0, q1, t);
}
}
// 循环缓冲区实现
public class CircularBuffer {
private T[] buffer;
private int head = 0;
private int tail = 0;
private int count = 0;
public int Count => count;
public int Capacity => buffer.Length;
public CircularBuffer(int capacity) {
buffer = new T[capacity];
}
public void Add(T item) {
buffer[head] = item;
head = (head + 1) % buffer.Length;
if (count < buffer.Length) {
count++;
} else {
tail = (tail + 1) % buffer.Length;
}
}
public T this[int index] {
get {
if (index < 0 || index >= count) {
throw new IndexOutOfRangeException();
}
int actualIndex = (tail + index) % buffer.Length;
return buffer[actualIndex];
}
}
}
```
#### 延迟补偿技术
```csharp
// 命中检测延迟补偿
public class LagCompensation : MonoBehaviour {
[Header("Compensation Settings")]
public int historyLength = 20; // 保存200ms的状态历史
public float maxCompensationTime = 0.2f; // 最大补偿200ms
private Dictionary> playerStateHistory =
new Dictionary>();
// 记录玩家状态快照
void RecordPlayerState(int playerId) {
GameObject player = GetPlayerById(playerId);
if (player == null) return;
PlayerStateSnapshot snapshot = new PlayerStateSnapshot {
timestamp = Time.realtimeSinceStartup,
position = player.transform.position,
rotation = player.transform.rotation,
colliderBounds = player.GetComponent().bounds,
velocity = player.GetComponent().velocity
};
if (!playerStateHistory.ContainsKey(playerId)) {
playerStateHistory[playerId] = new List();
}
playerStateHistory[playerId].Add(snapshot);
// 清理旧的快照
while (playerStateHistory[playerId].Count > historyLength) {
playerStateHistory[playerId].RemoveAt(0);
}
}
// 延迟补偿命中检测
public bool CompensatedRaycast(
int shooterId, int targetId,
Vector3 firePosition, Vector3 fireDirection,
float fireTime, out HitResult result) {
result = new HitResult();
// 获取射击时的延迟
float lag = Time.realtimeSinceStartup - fireTime;
if (lag > maxCompensationTime) {
Debug.LogWarning("延迟过大,无法补偿: " + lag);
return false;
}
// 查找目标玩家在射击时的状态
PlayerStateSnapshot snapshot = FindSnapshotAtTime(targetId, fireTime);
if (snapshot == null) {
Debug.LogWarning("找不到历史状态,无法补偿");
return false;
}
// 计算目标在射击时的位置(考虑移动)
Vector3 predictedPosition = PredictPosition(
snapshot.position, snapshot.velocity, lag);
// 创建临时碰撞体进行检测
using (TemporaryCollider tempCollider =
CreateTemporaryCollider(predictedPosition, snapshot.colliderBounds)) {
// 进行射线检测
if (Physics.Raycast(
firePosition, fireDirection,
out RaycastHit hit, 100f)) {
result.hit = true;
result.hitPoint = hit.point;
result.hitNormal = hit.normal;
result.targetId = targetId;
result.shooterId = shooterId;
result.compensationTime = lag;
return true;
}
}
result.hit = false;
return false;
}
// 查找指定时间的状态快照
PlayerStateSnapshot FindSnapshotAtTime(int playerId, float timestamp) {
if (!playerStateHistory.ContainsKey(playerId)) {
return null;
}
List snapshots = playerStateHistory[playerId];
// 二分查找最接近的快照
int left = 0;
int right = snapshots.Count - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (snapshots[mid].timestamp == timestamp) {
return snapshots[mid];
} else if (snapshots[mid].timestamp < timestamp) {
left = mid + 1;
} else {
right = mid - 1;
}
}
// 返回最接近的快照
if (left > 0 && left < snapshots.Count) {
float timeDiffLeft = timestamp - snapshots[left - 1].timestamp;
float timeDiffRight = snapshots[left].timestamp - timestamp;
return timeDiffLeft < timeDiffRight ?
snapshots[left - 1] : snapshots[left];
}
return null;
}
// 预测位置
Vector3 PredictPosition(
Vector3 initialPos, Vector3 velocity, float time) {
return initialPos + velocity * time;
}
// 创建临时碰撞体用于检测
TemporaryCollider CreateTemporaryCollider(
Vector3 position, Bounds bounds) {
// 实现临时碰撞体创建逻辑
return null;
}
}
// 玩家状态快照
public struct PlayerStateSnapshot {
public float timestamp;
public Vector3 position;
public Quaternion rotation;
public Bounds colliderBounds;
public Vector3 velocity;
}
// 命中检测结果
public struct HitResult {
public bool hit;
public Vector3 hitPoint;
public Vector3 hitNormal;
public int shooterId;
public int targetId;
public float compensationTime;
}
```
#### 带宽优化技术
```csharp
// 智能状态压缩系统
public class StateCompression : MonoBehaviour {
[Header("Compression Settings")]
public float positionPrecision = 0.01f; // 位置精度0.01米
public float rotationPrecision = 0.01f; // 旋转精度0.01弧度
public float velocityPrecision = 0.1f; // 速度精度0.1米/秒
// 压缩玩家状态
public byte[] CompressPlayerState(PlayerState state) {
using (MemoryStream ms = new MemoryStream()) {
using (BinaryWriter writer = new BinaryWriter(ms)) {
// 玩家ID(32位整数)
writer.Write(state.playerId);
// 时间戳(压缩为16位,精度10ms)
ushort timestamp = (ushort)(state.timestamp * 100);
writer.Write(timestamp);
// 位置(每个分量16位,范围-327.68到327.68米)
short posX = (short)(state.position.x / positionPrecision);
short posY = (short)(state.position.y / positionPrecision);
short posZ = (short)(state.position.z / positionPrecision);
writer.Write(posX);
writer.Write(posY);
writer.Write(posZ);
// 旋转(四元数压缩为32位)
uint compressedRotation = CompressQuaternion(state.rotation);
writer.Write(compressedRotation);
// 速度(每个分量12位,范围-20.48到20.48米/秒)
ushort velX = (ushort)((state.velocity.x + 20.48f) / (40.96f / 4096f));
ushort velY = (ushort)((state.velocity.y + 20.48f) / (40.96f / 4096f));
ushort velZ = (ushort)((state.velocity.z + 20.48f) / (40.96f / 4096f));
writer.Write((ushort)((velX & 0xFFF) | ((velY & 0xFFF) << 12)));
writer.Write((ushort)((velZ & 0xFFF) | 0));
// 生命值和魔法值(各8位,0-100)
byte healthByte = (byte)(state.health * 2.55f); // 0-100 → 0-255
byte manaByte = (byte)(state.mana * 2.55f);
writer.Write(healthByte);
writer.Write(manaByte);
// 动画状态(4位,0-15种状态)
byte animationByte = (byte)(state.animationState & 0x0F);
writer.Write(animationByte);
}
return ms.ToArray();
}
}
// 解压缩玩家状态
public PlayerState DecompressPlayerState(byte[] data) {
using (MemoryStream ms = new MemoryStream(data)) {
using (BinaryReader reader = new BinaryReader(ms)) {
PlayerState state = new PlayerState();
// 玩家ID
state.playerId = reader.ReadInt32();
// 时间戳
ushort timestamp = reader.ReadUInt16();
state.timestamp = timestamp / 100f;
// 位置
short posX = reader.ReadInt16();
short posY = reader.ReadInt16();
short posZ = reader.ReadInt16();
state.position = new Vector3(
posX * positionPrecision,
posY * positionPrecision,
posZ * positionPrecision);
// 旋转
uint compressedRotation = reader.ReadUInt32();
state.rotation = DecompressQuaternion(compressedRotation);
// 速度
ushort velLow = reader.ReadUInt16();
ushort velHigh = reader.ReadUInt16();
short velX = (short)((velLow & 0xFFF) - 2048);
short velY = (short)((velLow >> 12) - 2048);
short velZ = (short)((velHigh & 0xFFF) - 2048);
state.velocity = new Vector3(
velX * velocityPrecision,
velY * velocityPrecision,
velZ * velocityPrecision);
// 生命值和魔法值
byte healthByte = reader.ReadByte();
byte manaByte = reader.ReadByte();
state.health = healthByte / 2.55f; // 0-255 → 0-100
state.mana = manaByte / 2.55f;
// 动画状态
byte animationByte = reader.ReadByte();
state.animationState = animationByte & 0x0F;
return state;
}
}
}
// 压缩四元数为32位
uint CompressQuaternion(Quaternion q) {
// 找到最大分量
float maxComponent = Mathf.Max(
Mathf.Abs(q.x), Mathf.Abs(q.y),
Mathf.Abs(q.z), Mathf.Abs(q.w));
int maxIndex = 0;
if (maxComponent == Mathf.Abs(q.x)) maxIndex = 0;
else if (maxComponent == Mathf.Abs(q.y)) maxIndex = 1;
else if (maxComponent == Mathf.Abs(q.z)) maxIndex = 2;
else maxIndex = 3;
// 计算符号
int sign = (q[maxIndex] > 0) ? 0 : 1;
// 压缩其他三个分量为9位
uint x = CompressFloat(q.x, maxComponent, maxIndex == 0);
uint y = CompressFloat(q.y, maxComponent, maxIndex == 1);
uint z = CompressFloat(q.z, maxComponent, maxIndex == 2);
uint w = CompressFloat(q.w, maxComponent, maxIndex == 3);
// 打包为32位整数
uint result = (uint)maxIndex;
result |= (uint)sign << 2;
result |= x << 3;
result |= y << 12;
result |= z << 21;
return result;
}
// 解压缩四元数
Quaternion DecompressQuaternion(uint data) {
int maxIndex = (int)(data & 0x03);
int sign = (int)((data >> 2) & 0x01);
uint x = (data >> 3) & 0x1FF;
uint y = (data >> 12) & 0x1FF;
uint z = (data >> 21) & 0x1FF;
float[] components = new float[4];
components[maxIndex] = sign == 0 ? 1f : -1f;
components[(maxIndex + 1) % 4] = DecompressFloat(x);
components[(maxIndex + 2) % 4] = DecompressFloat(y);
components[(maxIndex + 3) % 4] = DecompressFloat(z);
// 归一化
float sum = components[0] * components[0] +
components[1] * components[1] +
components[2] * components[2] +
components[3] * components[3];
float invSqrt = 1f / Mathf.Sqrt(sum);
return new Quaternion(
components[0] * invSqrt,
components[1] * invSqrt,
components[2] * invSqrt,
components[3] * invSqrt);
}
// 压缩浮点数为9位
uint CompressFloat(float value, float maxComponent, bool isMaxComponent) {
if (isMaxComponent) return 0;
float normalized = value / maxComponent;
float scaled = (normalized + 1f) / 2f; // -1..1 → 0..1
return (uint)(scaled * 511f); // 0..1 → 0..511
}
// 解压缩9位浮点数
float DecompressFloat(uint data) {
float scaled = data / 511f; // 0..511 → 0..1
return scaled * 2f - 1f; // 0..1 → -1..1
}
}
```
---
## 第四部分:服务器架构设计
### 4.1 服务器基础架构
#### TCP Socket服务器实现
```csharp
// 多线程TCP服务器
public class TcpServer : IDisposable {
[Header("Server Settings")]
public int port = 8888;
public int maxConnections = 1000;
public int bufferSize = 4096;
private TcpListener tcpListener;
private Thread acceptThread;
private bool isRunning = false;
private Dictionary clients =
new Dictionary();
private object clientsLock = new object();
public void Start() {
tcpListener = new TcpListener(IPAddress.Any, port);
tcpListener.Start();
isRunning = true;
// 启动接受连接线程
acceptThread = new Thread(AcceptConnections);
acceptThread.IsBackground = true;
acceptThread.Start();
Debug.Log("TCP服务器启动成功,监听端口: " + port);
}
// 接受客户端连接
void AcceptConnections() {
while (isRunning) {
try {
TcpClient tcpClient = tcpListener.AcceptTcpClient();
// 检查连接数是否达到上限
lock (clientsLock) {
if (clients.Count >= maxConnections) {
tcpClient.Close();
Debug.LogWarning("服务器达到最大连接数,拒绝新连接");
continue;
}
}
// 创建客户端连接
ClientConnection client = new ClientConnection(
tcpClient, bufferSize, OnClientDataReceived, OnClientDisconnected);
lock (clientsLock) {
clients[client.connectionId] = client;
}
Debug.Log("新客户端连接: " + client.connectionId + ", 总连接数: " + clients.Count);
} catch (Exception e) {
if (isRunning) {
Debug.LogError("接受连接错误: " + e.Message);
}
}
}
}
// 收到客户端数据
void OnClientDataReceived(int connectionId, byte[] data) {
// 处理客户端数据
Debug.Log("收到客户端 " + connectionId + " 数据: " + data.Length + " 字节");
// 解析协议
NetworkMessage message = ProtocolParser.Parse(data);
// 分发消息到处理模块
messageDispatcher.DispatchMessage(connectionId, message);
}
// 客户端断开连接
void OnClientDisconnected(int connectionId) {
lock (clientsLock) {
if (clients.ContainsKey(connectionId)) {
clients.Remove(connectionId);
Debug.Log("客户端断开连接: " + connectionId + ", 总连接数: " + clients.Count);
}
}
}
// 发送数据到客户端
public void SendData(int connectionId, byte[] data) {
lock (clientsLock) {
if (clients.ContainsKey(connectionId)) {
clients[connectionId].SendData(data);
}
}
}
// 广播数据到所有客户端
public void BroadcastData(byte[] data) {
lock (clientsLock) {
foreach (var client in clients.Values) {
client.SendData(data);
}
}
}
public void Stop() {
isRunning = false;
tcpListener.Stop();
// 关闭所有客户端连接
lock (clientsLock) {
foreach (var client in clients.Values) {
client.Dispose();
}
clients.Clear();
}
Debug.Log("TCP服务器已停止");
}
public void Dispose() {
Stop();
}
}
// 客户端连接处理
public class ClientConnection : IDisposable {
public int connectionId { get; private set; }
public IPEndPoint remoteEndPoint { get; private set; }
private TcpClient tcpClient;
private NetworkStream networkStream;
private byte[] receiveBuffer;
private int bufferSize;
private Action onDataReceived;
private Action onDisconnected;
private bool isConnected = false;
public ClientConnection(
TcpClient client, int bufferSize,
Action onDataReceived,
Action onDisconnected) {
this.tcpClient = client;
this.bufferSize = bufferSize;
this.receiveBuffer = new byte[bufferSize];
this.onDataReceived = onDataReceived;
this.onDisconnected = onDisconnected;
this.connectionId = GenerateConnectionId();
this.remoteEndPoint = client.Client.RemoteEndPoint as IPEndPoint;
this.networkStream = client.GetStream();
this.isConnected = true;
// 开始异步接收数据
BeginReceive();
}
// 生成唯一连接ID
int GenerateConnectionId() {
return UnityEngine.Random.Range(10000, 99999);
}
// 开始异步接收数据
void BeginReceive() {
if (!isConnected) return;
networkStream.BeginRead(
receiveBuffer, 0, receiveBuffer.Length,
OnReceiveCallback, null);
}
// 接收数据回调
void OnReceiveCallback(IAsyncResult ar) {
try {
int bytesRead = networkStream.EndRead(ar);
if (bytesRead > 0) {
// 处理收到的数据
byte[] data = new byte[bytesRead];
Array.Copy(receiveBuffer, data, bytesRead);
onDataReceived?.Invoke(connectionId, data);
// 继续接收
BeginReceive();
} else {
// 客户端断开连接
OnDisconnected();
}
} catch (Exception e) {
Debug.LogError("接收数据错误: " + e.Message);
OnDisconnected();
}
}
// 发送数据到客户端
public void SendData(byte[] data) {
if (!isConnected) return;
try {
networkStream.BeginWrite(
data, 0, data.Length,
OnSendCallback, null);
} catch (Exception e) {
Debug.LogError("发送数据错误: " + e.Message);
OnDisconnected();
}
}
// 发送数据回调
void OnSendCallback(IAsyncResult ar) {
try {
networkStream.EndWrite(ar);
} catch (Exception e) {
Debug.LogError("发送完成回调错误: " + e.Message);
OnDisconnected();
}
}
// 客户端断开连接
void OnDisconnected() {
if (!isConnected) return;
isConnected = false;
tcpClient.Close();
networkStream.Dispose();
onDisconnected?.Invoke(connectionId);
}
public void Dispose() {
OnDisconnected();
}
}
```
#### UDP服务器实现
```csharp
// 异步UDP服务器
public class UdpServer : IDisposable {
[Header("Server Settings")]
public int port = 8889;
public int bufferSize = 4096;
private Socket udpSocket;
private IPEndPoint localEndPoint;
private byte[] receiveBuffer;
private bool isRunning = false;
public void Start() {
udpSocket = new Socket(
AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
localEndPoint = new IPEndPoint(IPAddress.Any, port);
udpSocket.Bind(localEndPoint);
receiveBuffer = new byte[bufferSize];
isRunning = true;
// 开始异步接收数据
BeginReceive();
Debug.Log("UDP服务器启动成功,监听端口: " + port);
}
// 开始异步接收数据
void BeginReceive() {
if (!isRunning) return;
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
udpSocket.BeginReceiveFrom(
receiveBuffer, 0, receiveBuffer.Length,
SocketFlags.None, ref remoteEndPoint,
OnReceiveFromCallback, remoteEndPoint);
}
// 接收数据回调
void OnReceiveFromCallback(IAsyncResult ar) {
if (!isRunning) return;
try {
IPEndPoint remoteEndPoint = ar.AsyncState as IPEndPoint;
int bytesRead = udpSocket.EndReceiveFrom(ar, ref remoteEndPoint);
if (bytesRead > 0) {
// 处理收到的数据
byte[] data = new byte[bytesRead];
Array.Copy(receiveBuffer, data, bytesRead);
OnDataReceived(remoteEndPoint, data);
}
// 继续接收
BeginReceive();
} catch (Exception e) {
Debug.LogError("UDP接收错误: " + e.Message);
// 尝试重新开始接收
if (isRunning) {
BeginReceive();
}
}
}
// 收到数据处理
void OnDataReceived(IPEndPoint remoteEndPoint, byte[] data) {
Debug.Log($"收到来自 {remoteEndPoint} 的数据: {data.Length} 字节");
// 解析协议
NetworkMessage message = ProtocolParser.Parse(data);
// 处理消息
messageHandler.HandleMessage(remoteEndPoint, message);
}
// 发送数据到客户端
public void SendData(IPEndPoint remoteEndPoint, byte[] data) {
if (!isRunning) return;
try {
udpSocket.BeginSendTo(
data, 0, data.Length,
SocketFlags.None, remoteEndPoint,
OnSendToCallback, remoteEndPoint);
} catch (Exception e) {
Debug.LogError("UDP发送错误: " + e.Message);
}
}
// 发送数据回调
void OnSendToCallback(IAsyncResult ar) {
try {
IPEndPoint remoteEndPoint = ar.AsyncState as IPEndPoint;
int bytesSent = udpSocket.EndSendTo(ar);
Debug.Log($"成功发送 {bytesSent} 字节到 {remoteEndPoint}");
} catch (Exception e) {
Debug.LogError("UDP发送完成回调错误: " + e.Message);
}
}
// 广播数据到所有客户端
public void BroadcastData(byte[] data, List clients) {
foreach (var client in clients) {
SendData(client, data);
}
}
public void Stop() {
isRunning = false;
udpSocket.Close();
Debug.Log("UDP服务器已停止");
}
public void Dispose() {
Stop();
}
}
```
### 4.2 高并发服务器架构
#### 线程池与IOCP模型
```csharp
// 基于IOCP的高性能服务器
public class IocpServer : IDisposable {
[Header("Server Settings")]
public int port = 8888;
public int maxConnections = 10000;
public int bufferSize = 8192;
public int concurrentThreads = 0; // 0表示使用默认线程数
private Socket listenSocket;
private BufferManager bufferManager;
private SocketAsyncEventArgsPool readWritePool;
private int numConnectedSockets;
private bool isRunning = false;
public void Start() {
// 初始化缓冲区管理器
bufferManager = new BufferManager(
bufferSize * maxConnections * 2, // 每个连接两个缓冲区
bufferSize);
// 初始化SocketAsyncEventArgs池
readWritePool = new SocketAsyncEventArgsPool(maxConnections);
// 分配缓冲区
bufferManager.InitBuffer();
// 填充SocketAsyncEventArgs池
for (int i = 0; i < maxConnections; i++) {
SocketAsyncEventArgs readWriteEventArg = new SocketAsyncEventArgs();
readWriteEventArg.Completed += IO_Completed;
readWriteEventArg.UserToken = new AsyncUserToken();
// 分配缓冲区
bufferManager.SetBuffer(readWriteEventArg);
readWritePool.Push(readWriteEventArg);
}
// 设置线程池
if (concurrentThreads > 0) {
ThreadPool.SetMinThreads(concurrentThreads, concurrentThreads);
ThreadPool.SetMaxThreads(concurrentThreads, concurrentThreads);
}
// 创建监听Socket
listenSocket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
listenSocket.Bind(new IPEndPoint(IPAddress.Any, port));
listenSocket.Listen(100);
isRunning = true;
// 开始接受连接
StartAccept(null);
Debug.Log("IOCP服务器启动成功,监听端口: " + port);
Debug.Log("最大连接数: " + maxConnections);
Debug.Log("工作线程数: " + (concurrentThreads > 0 ?
concurrentThreads.ToString() : "自动"));
}
// 开始接受连接
void StartAccept(SocketAsyncEventArgs acceptEventArg) {
if (acceptEventArg == null) {
acceptEventArg = new SocketAsyncEventArgs();
acceptEventArg.Completed += AcceptEventArg_Completed;
} else {
acceptEventArg.AcceptSocket = null;
}
bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg);
if (!willRaiseEvent) {
ProcessAccept(acceptEventArg);
}
}
// 接受连接完成回调
void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e) {
ProcessAccept(e);
}
// 处理接受的连接
void ProcessAccept(SocketAsyncEventArgs e) {
if (!isRunning) return;
// 获取客户端Socket
Socket clientSocket = e.AcceptSocket;
if (clientSocket.Connected) {
// 从池获取SocketAsyncEventArgs
SocketAsyncEventArgs readWriteEventArgs = readWritePool.Pop();
if (readWriteEventArgs != null) {
// 设置用户令牌
AsyncUserToken token = readWriteEventArgs.UserToken as AsyncUserToken;
token.socket = clientSocket;
token.remoteEndPoint = clientSocket.RemoteEndPoint as IPEndPoint;
token.connectionId = GenerateConnectionId();
// 开始异步接收数据
bool willRaiseEvent = clientSocket.ReceiveAsync(readWriteEventArgs);
if (!willRaiseEvent) {
ProcessReceive(readWriteEventArgs);
}
Interlocked.Increment(ref numConnectedSockets);
Debug.Log("新客户端连接: " + token.connectionId + ", 总连接数: " + numConnectedSockets);
} else {
// 连接池已满,拒绝连接
clientSocket.Close();
Debug.LogWarning("连接池已满,拒绝新连接");
}
}
// 继续接受新连接
StartAccept(e);
}
// IO操作完成回调
void IO_Completed(object sender, SocketAsyncEventArgs e) {
switch (e.LastOperation) {
case SocketAsyncOperation.Receive:
ProcessReceive(e);
break;
case SocketAsyncOperation.Send:
ProcessSend(e);
break;
default:
throw new ArgumentException("未知操作: " + e.LastOperation);
}
}
// 处理接收到的数据
void ProcessReceive(SocketAsyncEventArgs e) {
AsyncUserToken token = e.UserToken as AsyncUserToken;
try {
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) {
// 处理收到的数据
byte[] data = new byte[e.BytesTransferred];
Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred);
OnDataReceived(token.connectionId, data);
// 继续接收
bool willRaiseEvent = token.socket.ReceiveAsync(e);
if (!willRaiseEvent) {
ProcessReceive(e);
}
} else {
// 客户端断开连接
CloseClientSocket(e);
}
} catch (Exception ex) {
Debug.LogError("处理接收数据错误: " + ex.Message);
CloseClientSocket(e);
}
}
// 处理发送完成
void ProcessSend(SocketAsyncEventArgs e) {
if (e.SocketError == SocketError.Success) {
// 发送完成,继续接收
AsyncUserToken token = e.UserToken as AsyncUserToken;
bool willRaiseEvent = token.socket.ReceiveAsync(e);
if (!willRaiseEvent) {
ProcessReceive(e);
}
} else {
// 发送错误,关闭连接
CloseClientSocket(e);
}
}
// 关闭客户端Socket
void CloseClientSocket(SocketAsyncEventArgs e) {
AsyncUserToken token = e.UserToken as AsyncUserToken;
try {
token.socket.Shutdown(SocketShutdown.Both);
} catch (Exception) {}
token.socket.Close();
Interlocked.Decrement(ref numConnectedSockets);
Debug.Log("客户端断开连接: " + token.connectionId + ", 总连接数: " + numConnectedSockets);
// 重置并放回池
e.UserToken = new AsyncUserToken();
readWritePool.Push(e);
}
// 发送数据到客户端
public void SendData(int connectionId, byte[] data) {
// 实现根据连接ID查找客户端并发送数据
}
// 处理收到的数据
void OnDataReceived(int connectionId, byte[] data) {
Debug.Log("收到客户端 " + connectionId + " 数据: " + data.Length + " 字节");
}
// 生成连接ID
int GenerateConnectionId() {
return UnityEngine.Random.Range(100000, 999999);
}
public void Stop() {
isRunning = false;
listenSocket.Close();
Debug.Log("IOCP服务器已停止");
}
public void Dispose() {
Stop();
}
}
// 异步用户令牌
public class AsyncUserToken {
public Socket socket;
public IPEndPoint remoteEndPoint;
public int connectionId;
// 可以添加更多用户数据
}
// SocketAsyncEventArgs池
public class SocketAsyncEventArgsPool {
private Stack pool;
public SocketAsyncEventArgsPool(int capacity) {
pool = new Stack(capacity);
}
public void Push(SocketAsyncEventArgs item) {
if (item == null) {
throw new ArgumentNullException("item");
}
lock (pool) {
pool.Push(item);
}
}
public SocketAsyncEventArgs Pop() {
lock (pool) {
return pool.Pop();
}
}
public int Count {
get { lock (pool) { return pool.Count; } }
}
}
// 缓冲区管理器
public class BufferManager {
private int totalBytesInBufferBlock;
private byte[] bufferBlock;
private Stack freeIndexPool;
private int currentIndex;
private int bufferSize;
public BufferManager(int totalBytes, int bufferSize) {
totalBytesInBufferBlock = totalBytes;
this.bufferSize = bufferSize;
freeIndexPool = new Stack();
}
public void InitBuffer() {
bufferBlock = new byte[totalBytesInBufferBlock];
}
public bool SetBuffer(SocketAsyncEventArgs args) {
if (freeIndexPool.Count > 0) {
args.SetBuffer(bufferBlock, freeIndexPool.Pop(), bufferSize);
} else {
if (totalBytesInBufferBlock - bufferSize < currentIndex) {
return false;
}
args.SetBuffer(bufferBlock, currentIndex, bufferSize);
currentIndex += bufferSize;
}
return true;
}
public void FreeBuffer(SocketAsyncEventArgs args) {
freeIndexPool.Push(args.Offset);
args.SetBuffer(null, 0, 0);
}
}
```
#### 分布式服务器架构设计
```csharp
// 分布式服务器节点管理器
public class DistributedServerManager : MonoBehaviour {
[Header("Cluster Settings")]
public string masterServerAddress = "127.0.0.1";
public int masterServerPort = 9000;
private Dictionary serverNodes =
new Dictionary();
private bool isMasterServer = false;
void Start() {
// 根据配置启动主服务器或从服务器
if (IsMasterServer()) {
StartMasterServer();
isMasterServer = true;
} else {
StartSlaveServer();
}
}
// 启动主服务器
void StartMasterServer() {
Debug.Log("启动主服务器...");
// 启动主服务器节点
MasterServer masterServer = gameObject.AddComponent();
masterServer.StartServer(masterServerPort);
// 启动服务发现
ServiceDiscovery serviceDiscovery = gameObject.AddComponent();
serviceDiscovery.StartDiscovery();
// 启动负载均衡器
LoadBalancer loadBalancer = gameObject.AddComponent();
loadBalancer.StartBalancer();
}
// 启动从服务器
void StartSlaveServer() {
Debug.Log("启动从服务器...");
// 连接到主服务器
StartCoroutine(ConnectToMasterServer());
// 启动游戏服务器
GameServer gameServer = gameObject.AddComponent();
gameServer.StartServer(8888);
// 启动房间管理器
RoomManager roomManager = gameObject.AddComponent();
roomManager.Init();
}
// 连接到主服务器
IEnumerator ConnectToMasterServer() {
using (TcpClient client = new TcpClient()) {
yield return StartCoroutine(
ConnectTcpClient(client, masterServerAddress, masterServerPort));
if (client.Connected) {
Debug.Log("成功连接到主服务器");
// 注册本节点到主服务器
RegisterServerNode(client.GetStream());
} else {
Debug.LogError("无法连接到主服务器");
}
}
}
// 注册服务器节点
void RegisterServerNode(NetworkStream stream) {
ServerNodeInfo nodeInfo = new ServerNodeInfo {
nodeId = Guid.NewGuid().ToString(),
nodeType = ServerNodeType.GameServer,
address = GetLocalIPAddress(),
port = 8888,
maxPlayers = 1000,
currentPlayers = 0,
loadLevel = 0f
};
// 发送注册信息
byte[] data = JsonUtility.ToJson(nodeInfo).ToByteArray();
stream.Write(data, 0, data.Length);
}
// 获取本地IP地址
string GetLocalIPAddress() {
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList) {
if (ip.AddressFamily == AddressFamily.InterNetwork) {
return ip.ToString();
}
}
return "127.0.0.1";
}
// 判断是否为主服务器
bool IsMasterServer() {
// 根据命令行参数或配置文件判断
return false;
}
}
// 服务器节点类型
public enum ServerNodeType {
MasterServer,
GameServer,
ChatServer,
DatabaseServer,
MatchmakingServer,
AnalyticsServer
}
// 服务器节点信息
[System.Serializable]
public class ServerNodeInfo {
public string nodeId;
public ServerNodeType nodeType;
public string address;
public int port;
public int maxPlayers;
public int currentPlayers;
public float loadLevel;
// 可以添加更多服务器信息
}
```
### 4.3 服务器性能优化
#### 内存管理与对象池
```csharp
// 高性能对象池系统
public class ObjectPoolManager : MonoBehaviour {
private Dictionary objectPools =
new Dictionary();
private Dictionary