在 Unity 中实现客户端与服务器的交互是网络游戏和应用开发的核心部分。以下是全面的 Unity 服务器交互解决方案。
1. 常见通信协议
1.1 HTTP/HTTPS 协议
适用场景:账号系统、商城、排行榜等非实时交互
实现方式:
using UnityEngine.Networking;
IEnumerator GetRequest(string uri) {
using (UnityWebRequest webRequest = UnityWebRequest.Get(uri)) {
yield return webRequest.SendWebRequest();
if (webRequest.result == UnityWebRequest.Result.Success) {
Debug.Log("Received: " + webRequest.downloadHandler.text);
} else {
Debug.LogError("Error: " + webRequest.error);
}
}
}
1.2 WebSocket 协议
适用场景:实时聊天、多人游戏同步
实现方式:
using WebSocketSharp;
WebSocket ws = new WebSocket("ws://yourserver:port");
ws.OnMessage += (sender, e) => {
Debug.Log("Message received: " + e.Data);
};
ws.Connect();
ws.Send("Hello Server");
1.3 TCP/UDP 自定义协议
适用场景:MMORPG、FPS等需要高性能实时交互的游戏
推荐库:LiteNetLib, ENET
2. 数据格式处理
2.1 JSON
// 序列化
string json = JsonUtility.ToJson(playerData);
// 反序列化
PlayerData data = JsonUtility.FromJson<PlayerData>(json);
2.2 Protocol Buffers
// 定义 .proto 文件
message Player {
required string name = 1;
optional int32 level = 2;
}
// C# 中使用
Player player = new Player { Name = "John", Level = 10 };
using (MemoryStream stream = new MemoryStream()) {
Serializer.Serialize(stream, player);
byte[] data = stream.ToArray();
// 发送数据...
}
3. 通信架构设计
3.1 请求-响应模式
public class NetworkManager : MonoBehaviour {
private static NetworkManager _instance;
public static NetworkManager Instance { get { return _instance; } }
void Awake() {
if (_instance != null && _instance != this) {
Destroy(this.gameObject);
} else {
_instance = this;
DontDestroyOnLoad(gameObject);
}
}
public void SendRequest(RequestType type, Action<Response> callback) {
// 实现请求发送和回调处理
}
}
3.2 消息推送模式
public class MessageDispatcher : MonoBehaviour {
private Queue<NetworkMessage> _messageQueue = new Queue<NetworkMessage>();
void Update() {
lock (_messageQueue) {
while (_messageQueue.Count > 0) {
ProcessMessage(_messageQueue.Dequeue());
}
}
}
public void EnqueueMessage(NetworkMessage msg) {
lock (_messageQueue) {
_messageQueue.Enqueue(msg);
}
}
}
4. 安全考虑
4.1 数据加密
// AES加密示例
public static string Encrypt(string plainText, string key) {
byte[] iv = new byte[16];
byte[] array;
using (Aes aes = Aes.Create()) {
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = iv;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream()) {
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) {
using (StreamWriter streamWriter = new StreamWriter(cryptoStream)) {
streamWriter.Write(plainText);
}
array = memoryStream.ToArray();
}
}
}
return Convert.ToBase64String(array);
}
4.2 防作弊措施
服务器端数据验证
关键逻辑放在服务器端
使用时间戳和随机数防止重放攻击
5. 断线重连处理
public class ReconnectManager : MonoBehaviour {
private int _retryCount = 0;
private const int MAX_RETRY = 3;
public void HandleDisconnect() {
if (_retryCount < MAX_RETRY) {
_retryCount++;
StartCoroutine(ReconnectAfterDelay(5f));
} else {
ShowReconnectFailed();
}
}
IEnumerator ReconnectAfterDelay(float delay) {
yield return new WaitForSeconds(delay);
ConnectToServer();
}
}
6. 性能优化
6.1 数据压缩
using Ionic.Zlib;
// 压缩
byte[] compressed = ZlibStream.CompressBuffer(data);
// 解压
byte[] decompressed = ZlibStream.UncompressBuffer(compressed);
6.2 带宽优化
使用Delta压缩(只发送变化的数据)
优化协议字段(使用更小的数据类型)
合并小数据包
7. 测试与调试
7.1 本地测试服务器
# 简单Python HTTP测试服务器
from http.server import BaseHTTPRequestHandler, HTTPServer
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(b'{"status": "ok"}')
HTTPServer(('localhost', 8000), Handler).serve_forever()
8. 实际应用示例:玩家登录系统
public class LoginSystem : MonoBehaviour {
private const string LOGIN_URL = "https://yourserver.com/api/login";
public void Login(string username, string password) {
StartCoroutine(LoginCoroutine(username, password));
}
private IEnumerator LoginCoroutine(string username, string password) {
WWWForm form = new WWWForm();
form.AddField("username", username);
form.AddField("password", password);
using (UnityWebRequest www = UnityWebRequest.Post(LOGIN_URL, form)) {
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success) {
Debug.LogError("Login failed: " + www.error);
yield break;
}
LoginResponse response = JsonUtility.FromJson<LoginResponse>(www.downloadHandler.text);
if (response.success) {
// 登录成功处理
} else {
// 登录失败处理
}
}
}
}
[System.Serializable]
public class LoginResponse {
public bool success;
public string token;
public PlayerData player;
}