《Unity3D網絡遊戲實踐》(第2版)要點摘錄 - 「通信協議與消息隊列基礎」
書名:****《Unity3D網絡遊戲實踐》(第2版)
作者:羅培羽
所讀版本:機械工業出版社
通信協議與消息隊列
- 通信協議:把協議名、客戶端標識、具體參數組成一個固定格式的字符串,在服務端和客戶端之間傳輸,再根據協議格式解析出數據使用/轉發
- 如:消息名|客戶端IP與端口, 參數1, 參數2, 參數n
- 消息隊列:在Unity裡只有主線程可以操作UI組件,多線程消息處理容易導致各種奇怪的混亂,因此可以使用消息隊列讓主線程去處理Socket異步接收到的信息
- C#異步通信由線程池實現,不同的BeginReceive不一定在同一線程中執行
- 創建一個由主線程讀取的消息列表,每當收到消息便在列表末端添加數據
- 數據從頂端讀取,讀取處理後將其從頂端移除

-
public static class NetManager { static Socket socket; //接收緩沖區 static byte[] readBuff = new byte[1024]; //委托類型 public delegate void MsgListener(string str); //監聽列表(各個消息名對應的處理方法) private static Dictionary<string, MsgListener> listeners = new Dictionary<string, MsgListener>(); //消息隊列 static List<string> msgList = new List<string>(); //記錄消息對應的處理方法 public static void AddListener(string msgName, MsgListener listener) { listeners[msgName] = listener; } public static void Connect(string ip, int port) { socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Connect(ip, port); //同步連接 socket.BeginReceive(readBuff, 0, 1024, 0, ReceiveCallback, socket); //異步接收信息 } static void ReceiveCallback(IAsyncResult ar) { try { Socket socket = (Socket)ar.AsyncState; int count = socket.EndReceive(ar); string recvStr = System.Text.Encoding.UTF8.GetString(readBuff, 0, count); //消息隊列更新 msgList.Add(recvStr); socket.BeginReceive(readBuff, 0, 1024, 0, ReceiveCallback, socket); } catch(SocketException ex) { Debug.Log("Socket Receive Failed: " + ex.ToString()); } } public static void Send(string sendStr) { if (socket == null) { return; } if (!socket.Connected) { return; } //同步發送 byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(sendStr); socket.Send(sendBytes); } //每幀更新,持續處理消息隊列中的消息 public static void Update() { if (msgList.Count <= 0) { return; } string msgStr = msgList[0]; msgList.RemoveAt(0); string[] split = msgStr.Split('|'); string msgName = split[0]; string msgArgs = split[1]; if (listeners.ContainsKey(msgName)) { listeners[msgName](msgArgs); } } }