【实战】Unity3d实战之Unity3d网络游戏实战篇(9):协议
Unity3d實戰之Unity3d網絡游戲實戰篇(9):協議
學習書籍《Unity3d網絡游戲實戰》 羅培羽著 機械工業出版社
本文是作者在學習過程中遇到的認為值得記錄的點,因此引用的代碼等資源基本出資羅培羽老師的書籍,如有侵權請聯系,必刪。
一套通用的服務端框架要支持不同游戲所使用的各種協議格式。所謂協議就是通信規則,例如:如果發送端直接發送一串數值數據給接收端,接收端并不知道這一串數據到底是用來做什么的,里面的數據代表了什么信息。而協議就是解決這一問題的一套規則,一套發送端和接收端都知道的規則。在要發送的數據前添加某些標志,發送端和接收端共同規定帶有這個標志的數據的用途。這樣,兩端就可以對接收到的數據進行解析,并根據兩者共同定立的規則來分辨所接收到的數據的用途。
所有的協議都有相同的方法:解碼、編碼、獲取協議名等等,以此為基礎,我們可以編寫一個協議的基類:
根據需要可以定義不同類型的協議,不同類型的協議的編碼解碼方式不同,如字符串協議會議字符串形式解析接收到的協議,字節流協議會以字節方式解析協議。下面給出字節流代碼:
using System; using System.Linq;namespace Server {/// <summary>/// Bytes Protocol/// Protocol Format:/// [protocollength][protocol name][data1][data2].../// protocollength: Int32 -> byte/// protocol name: byte/// data: byte/// </summary>public class ProtocolBytes : ProtocolBase{public byte[] bytes;public override ProtocolBase Decode (byte[] readBuff, int start, int length){ProtocolBytes proto = new ProtocolBytes ();proto.bytes = new byte[length];Array.Copy (readBuff, start, proto.bytes, 0, length);return (ProtocolBase)proto;}public override byte[] Encode (){return bytes;}public override string GetName (){return GetString (0);}public override string GetDesc (){if (bytes == null)return "";string str = "";for (int i = 0; i < bytes.Length; i++) {int t = (int)bytes [i];str += t.ToString () + " ";}return str;}#region Help Function#region String Operation/// <summary>/// convert the str into bytes and connect it behind the protocol./// </summary>/// <param name="str">the connected string</param>public void AddString(string str){Int32 length = str.Length;byte[] lenBytes = BitConverter.GetBytes (length);byte[] strBytes = System.Text.Encoding.UTF8.GetBytes (str);if (bytes == null)bytes = lenBytes.Concat (strBytes).ToArray ();elsebytes = bytes.Concat (lenBytes).Concat (strBytes).ToArray ();}/// <summary>/// Get a complete string from start to end./// </summary>/// <returns>string</returns>/// <param name="start">start index</param>/// <param name="end">end index</param>public string GetString(int start, ref int end){if (bytes == null)return "";if (bytes.Length < start + sizeof(Int32))return "";Int32 strLen = BitConverter.ToInt16 (bytes, start);if (bytes.Length < start + sizeof(Int32) + strLen)return "";string str = System.Text.Encoding.UTF8.GetString (bytes, start + sizeof(Int32), strLen);end = start + sizeof(Int32) + strLen;return str;}/// <summary>/// Get a complete string begin at start./// </summary>/// <returns>string</returns>/// <param name="start">start index</param>public string GetString(int start){int end = 0;return GetString (start, ref end);}#endregion#region Int32 Operation/// <summary>/// convert the Int32 into bytes and connect it behind the protocol./// </summary>/// <param name="num">Number.</param>public void AddInt32(Int32 num){byte[] numBytes = BitConverter.GetBytes (num);if (bytes == null)bytes = numBytes;elsebytes = bytes.Concat (numBytes).ToArray ();}/// <summary>/// Get a complete Int32 num from protocol's start to end./// </summary>/// <returns>Int32</returns>/// <param name="start">start index</param>/// <param name="end">end index</param>public Int32 GetInt32(int start, ref int end){if (bytes == null)return 0;if (bytes.Length < start + sizeof(Int32))return 0;end = start + sizeof(Int32);return BitConverter.ToInt32 (bytes, start);}/// <summary>/// Get a complete Int32 num from protocol's start./// </summary>/// <returns>Int32.</returns>/// <param name="start">start index</param>public Int32 GetInt(int start){int end = 0;return GetInt (start, ref end);}#endregion#region Float Operation/// <summary>/// convert the float into bytes and connect it behind the protocol./// </summary>/// <param name="num">float number</param>public void AddFloat(float num){byte[] numBytes = BitConverter.GetBytes (num);if (bytes == null)bytes = numBytes;elsebytes = bytes.Concat (numBytes).ToArray ();}/// <summary>/// Get a complete float num from protocol's start to end./// </summary>/// <returns>The float.</returns>/// <param name="start">start index</param>/// <param name="end">end index</param>public float GetFloat(int start, ref int end){if (bytes == null)return 0;if (bytes.Length < start + sizeof(float))return 0;end = start + sizeof(float);return BitConverter.ToSingle (bytes, start);}/// <summary>/// Get a complete float num from protocol's start./// </summary>/// <returns>The float.</returns>/// <param name="start">start index</param>public float GetFloat(int start){int end = 0;return GetFloat (start, ref end);}#endregion#endregion} } 使用Help Function中的方法可以對協議進行一定的操作,如添加協議名、添加數據等。
我一開始在這里陷入了混亂,為什么添加String時需要打包string長度,而添加int和float時就不需要在數據前添加數據長度,后來發現這是因為string的長度是不確定的,而int和float的長度都是確定的,如Int32的長度為4byte,在獲取Int時,BitConverter可以直接獲取start位置往后4byte的數據并將它轉化為Int32類型,顯然string就不行,因此它需要添加數據長度信息。
在完成協議后,我們就可以使用協議進行通信了,在發送協議時記得要給在發送的數據包前加上整條協議的長度信息。
總結
以上是生活随笔為你收集整理的【实战】Unity3d实战之Unity3d网络游戏实战篇(9):协议的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爱情测试MySQL存储_当爱情的剧本,多
- 下一篇: eNSP RIP协议