日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【实战】Unity3d实战之Unity3d网络游戏实战篇(9):协议

發(fā)布時(shí)間:2024/3/26 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【实战】Unity3d实战之Unity3d网络游戏实战篇(9):协议 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Unity3d實(shí)戰(zhàn)之Unity3d網(wǎng)絡(luò)游戲?qū)崙?zhàn)篇(9):協(xié)議

學(xué)習(xí)書籍《Unity3d網(wǎng)絡(luò)游戲?qū)崙?zhàn)》 羅培羽著 機(jī)械工業(yè)出版社
本文是作者在學(xué)習(xí)過程中遇到的認(rèn)為值得記錄的點(diǎn),因此引用的代碼等資源基本出資羅培羽老師的書籍,如有侵權(quán)請聯(lián)系,必刪。

 一套通用的服務(wù)端框架要支持不同游戲所使用的各種協(xié)議格式。所謂協(xié)議就是通信規(guī)則,例如:如果發(fā)送端直接發(fā)送一串?dāng)?shù)值數(shù)據(jù)給接收端,接收端并不知道這一串?dāng)?shù)據(jù)到底是用來做什么的,里面的數(shù)據(jù)代表了什么信息。而協(xié)議就是解決這一問題的一套規(guī)則,一套發(fā)送端和接收端都知道的規(guī)則。在要發(fā)送的數(shù)據(jù)前添加某些標(biāo)志,發(fā)送端和接收端共同規(guī)定帶有這個(gè)標(biāo)志的數(shù)據(jù)的用途。這樣,兩端就可以對接收到的數(shù)據(jù)進(jìn)行解析,并根據(jù)兩者共同定立的規(guī)則來分辨所接收到的數(shù)據(jù)的用途。
 
 所有的協(xié)議都有相同的方法:解碼、編碼、獲取協(xié)議名等等,以此為基礎(chǔ),我們可以編寫一個(gè)協(xié)議的基類:
 

using System;namespace Server {public class ProtocolBase{/// <summary>/// Decode the readBuff from start to start+length. Package readBuff as a protocol and return it./// </summary>/// <param name="readBuff">Read buff.</param>/// <param name="start">Type: int, decode begin from start.</param>/// <param name="length">Type: int, decode from begin to start+length.</param>public virtual ProtocolBase Decode(byte[] readBuff, int start, int length){return new ProtocolBase ();}/// <summary>/// Encode the protocol's content to binary array./// </summary>public virtual byte[] Encode(){return new byte[] { };}/// <summary>/// Return the protocol's name./// </summary>/// <returns>The name.</returns>public virtual string GetName(){return "";}/// <summary>/// Return the protocol's description./// </summary>/// <returns>The desc.</returns>public virtual string GetDesc(){return "";}} }

 根據(jù)需要可以定義不同類型的協(xié)議,不同類型的協(xié)議的編碼解碼方式不同,如字符串協(xié)議會(huì)議字符串形式解析接收到的協(xié)議,字節(jié)流協(xié)議會(huì)以字節(jié)方式解析協(xié)議。下面給出字節(jié)流代碼:

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中的方法可以對協(xié)議進(jìn)行一定的操作,如添加協(xié)議名、添加數(shù)據(jù)等。
 我一開始在這里陷入了混亂,為什么添加String時(shí)需要打包string長度,而添加int和float時(shí)就不需要在數(shù)據(jù)前添加數(shù)據(jù)長度,后來發(fā)現(xiàn)這是因?yàn)閟tring的長度是不確定的,而int和float的長度都是確定的,如Int32的長度為4byte,在獲取Int時(shí),BitConverter可以直接獲取start位置往后4byte的數(shù)據(jù)并將它轉(zhuǎn)化為Int32類型,顯然string就不行,因此它需要添加數(shù)據(jù)長度信息。

 在完成協(xié)議后,我們就可以使用協(xié)議進(jìn)行通信了,在發(fā)送協(xié)議時(shí)記得要給在發(fā)送的數(shù)據(jù)包前加上整條協(xié)議的長度信息。

總結(jié)

以上是生活随笔為你收集整理的【实战】Unity3d实战之Unity3d网络游戏实战篇(9):协议的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。