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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#使用Protocol Buffer(ProtoBuf)进行Unity中的Socket通信

發(fā)布時間:2023/12/9 C# 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#使用Protocol Buffer(ProtoBuf)进行Unity中的Socket通信 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

From:?http://www.jb51.net/article/82795.htm


這篇文章主要介紹了C#使用Protocol Buffer(ProtoBuf)進行Unity的Socket通信的實例,Protocol Buffer是Google開發(fā)的數(shù)據(jù)格式,也是除了XML和JSON之外人氣第三高的^^需要的朋友可以參考下

首先來說一下本文中例子所要實現(xiàn)的功能:

  • 基于ProtoBuf序列化對象
  • 使用Socket實現(xiàn)時時通信
  • 數(shù)據(jù)包的編碼和解碼

下面來看具體的步驟:

一、Unity中使用ProtoBuf

導(dǎo)入DLL到Unity中,
創(chuàng)建網(wǎng)絡(luò)傳輸?shù)哪P皖?#xff1a;

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 using System; using ProtoBuf; //添加特性,表示可以被ProtoBuf工具序列化 [ProtoContract] public class NetModel { ?//添加特性,表示該字段可以被序列化,1可以理解為下標(biāo) ?[ProtoMember(1)] ?public int ID; ?[ProtoMember(2)] ?public string Commit; ?[ProtoMember(3)] ?public string Message; } using System; using ProtoBuf; ?? //添加特性,表示可以被ProtoBuf工具序列化 [ProtoContract] public class NetModel { ?//添加特性,表示該字段可以被序列化,1可以理解為下標(biāo) ?[ProtoMember(1)] ?public int ID; ?[ProtoMember(2)] ?public string Commit; ?[ProtoMember(3)] ?public string Message; }

在Unity中添加測試腳本,介紹ProtoBuf工具的使用。

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 using System; using System.IO; public class Test : MonoBehaviour { ?void Start () { ??//創(chuàng)建對象 ??NetModel item = new NetModel(){ID = 1, Commit = "LanOu", Message = "Unity"}; ??//序列化對象 ??byte[] temp = Serialize(item); ??//ProtoBuf的優(yōu)勢一:小 ??Debug.Log(temp.Length); ??//反序列化為對象 ??NetModel result = DeSerialize(temp); ??Debug.Log(result.Message); ?} ?// 將消息序列化為二進制的方法 ?// < param name="model">要序列化的對象< /param> ?private byte[] Serialize(NetModel model) ?{ ??try { ???//涉及格式轉(zhuǎn)換,需要用到流,將二進制序列化到流中 ???using (MemoryStream ms = new MemoryStream()) { ????//使用ProtoBuf工具的序列化方法 ????ProtoBuf.Serializer.Serialize<NetModel> (ms, model); ????//定義二級制數(shù)組,保存序列化后的結(jié)果 ????byte[] result = new byte[ms.Length]; ????//將流的位置設(shè)為0,起始點 ????ms.Position = 0; ????//將流中的內(nèi)容讀取到二進制數(shù)組中 ????ms.Read (result, 0, result.Length); ????return result; ???} ??} catch (Exception ex) { ???Debug.Log ("序列化失敗: " + ex.ToString()); ???return null; ??} ?} ?// 將收到的消息反序列化成對象 ?// < returns>The serialize.< /returns> ?// < param name="msg">收到的消息.</param> ?private NetModel DeSerialize(byte[] msg) ?{ ??try { ???using (MemoryStream ms = new MemoryStream()) { ????//將消息寫入流中 ????ms.Write (msg, 0, msg.Length); ????//將流的位置歸0 ????ms.Position = 0; ????//使用工具反序列化對象 ????NetModel result = ProtoBuf.Serializer.Deserialize<NetModel> (ms); ????return result; ???} ??} catch (Exception ex) {? ????Debug.Log("反序列化失敗: " + ex.ToString()); ????return null; ??} ?} } using System; using System.IO; ?? public class Test : MonoBehaviour { ?? ?void Start () { ??//創(chuàng)建對象 ??NetModel item = new NetModel(){ID = 1, Commit = "LanOu", Message = "Unity"}; ??//序列化對象 ??byte[] temp = Serialize(item); ??//ProtoBuf的優(yōu)勢一:小 ??Debug.Log(temp.Length); ??//反序列化為對象 ??NetModel result = DeSerialize(temp); ??Debug.Log(result.Message); ?? ?} ?? ?// 將消息序列化為二進制的方法 ?// < param name="model">要序列化的對象< /param> ?private byte[] Serialize(NetModel model) ?{ ??try { ???//涉及格式轉(zhuǎn)換,需要用到流,將二進制序列化到流中 ???using (MemoryStream ms = new MemoryStream()) { ????//使用ProtoBuf工具的序列化方法 ????ProtoBuf.Serializer.Serialize<NetModel> (ms, model); ????//定義二級制數(shù)組,保存序列化后的結(jié)果 ????byte[] result = new byte[ms.Length]; ????//將流的位置設(shè)為0,起始點 ????ms.Position = 0; ????//將流中的內(nèi)容讀取到二進制數(shù)組中 ????ms.Read (result, 0, result.Length); ????return result; ???} ??} catch (Exception ex) { ???Debug.Log ("序列化失敗: " + ex.ToString()); ???return null; ??} ?} ?? ?// 將收到的消息反序列化成對象 ?// < returns>The serialize.< /returns> ?// < param name="msg">收到的消息.</param> ?private NetModel DeSerialize(byte[] msg) ?{ ??try { ???using (MemoryStream ms = new MemoryStream()) { ????//將消息寫入流中 ????ms.Write (msg, 0, msg.Length); ????//將流的位置歸0 ????ms.Position = 0; ????//使用工具反序列化對象 ????NetModel result = ProtoBuf.Serializer.Deserialize<NetModel> (ms); ????return result; ???} ??} catch (Exception ex) {? ????Debug.Log("反序列化失敗: " + ex.ToString()); ????return null; ??} ?} }

二、Unity中使用Socket實現(xiàn)時時通信

通信應(yīng)該實現(xiàn)的功能:

  • 服務(wù)器可以時時監(jiān)聽多個客戶端
  • 服務(wù)器可以時時監(jiān)聽某一個客戶端消息
  • 服務(wù)器可以時時給某一個客戶端發(fā)消息
  • 首先我們需要定義一個客戶端對象
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 using System; using System.Net.Sockets; // 表示一個客戶端 public class NetUserToken { ?//連接客戶端的Socket ?public Socket socket; ?//用于存放接收數(shù)據(jù) ?public byte[] buffer; ?public NetUserToken() ?{ ??buffer = new byte[1024]; ?} ?// 接受消息 ?// < param name="data">Data.< /param> ?public void Receive(byte[] data) ?{ ??UnityEngine.Debug.Log("接收到消息!"); ?} ?// 發(fā)送消息 ?//< param name="data">Data.< /param> ?public void Send(byte[] data) ?{? ?} } using System; using System.Net.Sockets; ?? // 表示一個客戶端 public class NetUserToken { ?//連接客戶端的Socket ?public Socket socket; ?//用于存放接收數(shù)據(jù) ?public byte[] buffer; ?? ?public NetUserToken() ?{ ??buffer = new byte[1024]; ?} ?? ?// 接受消息 ?// < param name="data">Data.< /param> ?public void Receive(byte[] data) ?{ ??UnityEngine.Debug.Log("接收到消息!"); ?} ?? ?// 發(fā)送消息 ?//< param name="data">Data.< /param> ?public void Send(byte[] data) ?{? ?? ?} }


然后實現(xiàn)我們的服務(wù)器代碼

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 using System.Collections; using System.Collections.Generic; using System.Net; using System; using System.Net.Sockets; public class NetServer{ ?//單例腳本 ?public static readonly NetServer Instance = new NetServer(); ?//定義tcp服務(wù)器 ?private Socket server; ?private int maxClient = 10; ?//定義端口 ?private int port = 35353; ?//用戶池 ?private Stack<NetUserToken> pools; ?private NetServer() ?{ ??//初始化socket ??server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ??server.Bind(new IPEndPoint(IPAddress.Any, port)); ?} ?//開啟服務(wù)器 ?public void Start() ?{ ??server.Listen(maxClient); ??UnityEngine.Debug.Log("Server OK!"); ??//實例化客戶端的用戶池 ??pools = new Stack<NetUserToken>(maxClient); ??for(int i = 0; i < maxClient; i++) ??{ ???NetUserToken usertoken = new NetUserToken(); ???pools.Push(usertoken); ??} ??//可以異步接受客戶端, BeginAccept函數(shù)的第一個參數(shù)是回調(diào)函數(shù),當(dāng)有客戶端連接的時候自動調(diào)用 ??server.BeginAccept (AsyncAccept, null); ?} ?//回調(diào)函數(shù), 有客戶端連接的時候會自動調(diào)用此方法 ?private void AsyncAccept(IAsyncResult result) ?{ ??try { ???//結(jié)束監(jiān)聽,同時獲取到客戶端 ???Socket client = server.EndAccept(result); ???UnityEngine.Debug.Log("有客戶端連接"); ???//來了一個客戶端 ???NetUserToken userToken = pools.Pop(); ???userToken.socket = client; ???//客戶端連接之后,可以接受客戶端消息 ???BeginReceive(userToken); ???//尾遞歸,再次監(jiān)聽是否還有其他客戶端連入 ???server.BeginAccept(AsyncAccept, null); ??} catch (Exception ex) { ???UnityEngine.Debug.Log(ex.ToString()); ??} ?} ?//異步監(jiān)聽消息 ?private void BeginReceive(NetUserToken userToken) ?{ ??try { ???//異步方法 ???userToken.socket.BeginReceive(userToken.buffer, 0, userToken.buffer.Length, SocketFlags.None, ???????????EndReceive, userToken); ??} catch (Exception ex) { ???UnityEngine.Debug.Log(ex.ToString()); ??} ?} ?//監(jiān)聽到消息之后調(diào)用的函數(shù) ?private void EndReceive(IAsyncResult result) ?{ ??try { ???//取出客戶端 ???NetUserToken userToken = result.AsyncState as NetUserToken; ???//獲取消息的長度 ???int len = userToken.socket.EndReceive(result); ???if(len > 0) ???{ ????byte[] data = new byte[len]; ????Buffer.BlockCopy(userToken.buffer, 0, data, 0, len); ????//用戶接受消息 ????userToken.Receive(data); ????//尾遞歸,再次監(jiān)聽客戶端消息 ????BeginReceive(userToken); ???} ??} catch (Exception ex) { ???UnityEngine.Debug.Log(ex.ToString()); ??} ?} } using System.Collections; using System.Collections.Generic; using System.Net; using System; using System.Net.Sockets; ?? public class NetServer{ ?//單例腳本 ?public static readonly NetServer Instance = new NetServer(); ?//定義tcp服務(wù)器 ?private Socket server; ?private int maxClient = 10; ?//定義端口 ?private int port = 35353; ?//用戶池 ?private Stack<NetUserToken> pools; ?private NetServer() ?{ ??//初始化socket ??server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ??server.Bind(new IPEndPoint(IPAddress.Any, port)); ?? ?} ?? ?//開啟服務(wù)器 ?public void Start() ?{ ??server.Listen(maxClient); ??UnityEngine.Debug.Log("Server OK!"); ??//實例化客戶端的用戶池 ??pools = new Stack<NetUserToken>(maxClient); ??for(int i = 0; i < maxClient; i++) ??{ ???NetUserToken usertoken = new NetUserToken(); ???pools.Push(usertoken); ??} ??//可以異步接受客戶端, BeginAccept函數(shù)的第一個參數(shù)是回調(diào)函數(shù),當(dāng)有客戶端連接的時候自動調(diào)用 ??server.BeginAccept (AsyncAccept, null); ?} ?? ?//回調(diào)函數(shù), 有客戶端連接的時候會自動調(diào)用此方法 ?private void AsyncAccept(IAsyncResult result) ?{ ??try { ???//結(jié)束監(jiān)聽,同時獲取到客戶端 ???Socket client = server.EndAccept(result); ???UnityEngine.Debug.Log("有客戶端連接"); ???//來了一個客戶端 ???NetUserToken userToken = pools.Pop(); ???userToken.socket = client; ???//客戶端連接之后,可以接受客戶端消息 ???BeginReceive(userToken); ?? ???//尾遞歸,再次監(jiān)聽是否還有其他客戶端連入 ???server.BeginAccept(AsyncAccept, null); ??} catch (Exception ex) { ???UnityEngine.Debug.Log(ex.ToString()); ??} ?} ?? ?//異步監(jiān)聽消息 ?private void BeginReceive(NetUserToken userToken) ?{ ??try { ???//異步方法 ???userToken.socket.BeginReceive(userToken.buffer, 0, userToken.buffer.Length, SocketFlags.None, ???????????EndReceive, userToken); ??} catch (Exception ex) { ???UnityEngine.Debug.Log(ex.ToString()); ??} ?} ?? ?//監(jiān)聽到消息之后調(diào)用的函數(shù) ?private void EndReceive(IAsyncResult result) ?{ ??try { ???//取出客戶端 ???NetUserToken userToken = result.AsyncState as NetUserToken; ???//獲取消息的長度 ???int len = userToken.socket.EndReceive(result); ???if(len > 0) ???{ ????byte[] data = new byte[len]; ????Buffer.BlockCopy(userToken.buffer, 0, data, 0, len); ????//用戶接受消息 ????userToken.Receive(data); ????//尾遞歸,再次監(jiān)聽客戶端消息 ????BeginReceive(userToken); ???} ?? ??} catch (Exception ex) { ???UnityEngine.Debug.Log(ex.ToString()); ??} ?} }


在Unity中開啟服務(wù)器,并使用C#控制臺模擬客戶端連接、發(fā)送消息操作。測試OK了,Unity中可以時時監(jiān)聽到消息。

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 using UnityEngine; using System.Collections; public class CreateServer : MonoBehaviour { ?void StartServer () { ??NetServer.Instance.Start(); ?} } //C#控制臺工程 using System; using System.Net; using System.Net.Sockets; using System.IO; using System.Text; namespace Temp { ?class MainClass ?{ ??public static void Main (string[] args) ??{ ???TcpClient tc = new TcpClient(); ???IPEndPoint ip = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 35353); ???tc.Connect(ip); ???if(tc.Connected) ???{ ????while(true) ????{ ?????string msg = Console.ReadLine(); ?????byte[] result = Encoding.UTF8.GetBytes(msg); ?????tc.GetStream().Write(result, 0, result.Length); ????} ???} ???Console.ReadLine(); ??} ?} } using UnityEngine; using System.Collections; ?? public class CreateServer : MonoBehaviour { ?? ?void StartServer () { ??NetServer.Instance.Start(); ?} ?? } ?? //C#控制臺工程 ?? using System; using System.Net; using System.Net.Sockets; using System.IO; using System.Text; ?? namespace Temp { ?class MainClass ?{ ??public static void Main (string[] args) ??{ ???TcpClient tc = new TcpClient(); ???IPEndPoint ip = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 35353); ???tc.Connect(ip); ?? ???if(tc.Connected) ???{ ????while(true) ????{ ?? ?????string msg = Console.ReadLine(); ?????byte[] result = Encoding.UTF8.GetBytes(msg); ?????tc.GetStream().Write(result, 0, result.Length); ????} ???} ???Console.ReadLine(); ??} ?} }

三、數(shù)據(jù)包的編碼和解碼

首先,舉個例子,這個月信用卡被媳婦刷爆了,面對房貸車貸的壓力,我只能選擇分期付款。。。

那么OK了,現(xiàn)在我想問一下,當(dāng)服務(wù)器向客戶端發(fā)送的數(shù)據(jù)過大時怎么辦呢?

當(dāng)服務(wù)器需要向客戶端發(fā)送一條很長的數(shù)據(jù),也會“分期付款!”,服務(wù)器會把一條很長的數(shù)據(jù)分成若干條小數(shù)據(jù),多次發(fā)送給客戶端。

可是,這樣就又有另外一個問題,客戶端接受到多條數(shù)據(jù)之后如何解析?

這里其實就是客戶端的解碼。server發(fā)數(shù)據(jù)一般采用“長度+內(nèi)容”的格式,Client接收到數(shù)據(jù)之后,先提取出長度來,然后根據(jù)長度判斷內(nèi)容是否發(fā)送完畢。

再次重申,用戶在發(fā)送序列化好的消息的前,需要先編碼后再發(fā)送消息;用戶在接受消息后,需要解碼之后再解析數(shù)據(jù)(反序列化)。

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 using UnityEngine; using System.Collections.Generic; using System.IO; // 編碼和解碼 public class NetEncode { ?// 將數(shù)據(jù)編碼 長度+內(nèi)容 ?/// < param name="data">內(nèi)容< /param> ?public static byte[] Encode(byte[] data) ?{ ??//整形占四個字節(jié),所以聲明一個+4的數(shù)組 ??byte[] result = new byte[data.Length + 4]; ??//使用流將編碼寫二進制 ??MemoryStream ms = new MemoryStream(); ??BinaryWriter br = new BinaryWriter(ms); ??br.Write(data.Length); ??br.Write(data); ??//將流中的內(nèi)容復(fù)制到數(shù)組中 ??System.Buffer.BlockCopy(ms.ToArray(), 0, result, 0, (int)ms.Length); ??br.Close(); ??ms.Close(); ??return result; ?} ?// 將數(shù)據(jù)解碼 ?// < param name="cache">消息隊列< /param> ?public static byte[] Decode(ref List<byte> cache) ?{ ??//首先要獲取長度,整形4個字節(jié),如果字節(jié)數(shù)不足4個字節(jié) ??if(cache.Count < 4) ??{ ???return null; ??} ??//讀取數(shù)據(jù) ??MemoryStream ms = new MemoryStream(cache.ToArray()); ??BinaryReader br = new BinaryReader(ms); ??int len = br.ReadInt32(); ??//根據(jù)長度,判斷內(nèi)容是否傳遞完畢 ??if(len > ms.Length - ms.Position) ??{ ???return null; ??} ??//獲取數(shù)據(jù) ??byte[] result = br.ReadBytes(len); ??//清空消息池 ??cache.Clear(); ??//講剩余沒處理的消息存入消息池 ??cache.AddRange(br.ReadBytes((int)ms.Length - (int)ms.Position)); ??return result; ?} } using UnityEngine; using System.Collections.Generic; using System.IO; ?? // 編碼和解碼 public class NetEncode { ?? ?// 將數(shù)據(jù)編碼 長度+內(nèi)容 ?/// < param name="data">內(nèi)容< /param> ?public static byte[] Encode(byte[] data) ?{ ??//整形占四個字節(jié),所以聲明一個+4的數(shù)組 ??byte[] result = new byte[data.Length + 4]; ??//使用流將編碼寫二進制 ??MemoryStream ms = new MemoryStream(); ??BinaryWriter br = new BinaryWriter(ms); ??br.Write(data.Length); ??br.Write(data); ??//將流中的內(nèi)容復(fù)制到數(shù)組中 ??System.Buffer.BlockCopy(ms.ToArray(), 0, result, 0, (int)ms.Length); ??br.Close(); ??ms.Close(); ??return result; ?} ?? ?// 將數(shù)據(jù)解碼 ?// < param name="cache">消息隊列< /param> ?public static byte[] Decode(ref List<byte> cache) ?{ ??//首先要獲取長度,整形4個字節(jié),如果字節(jié)數(shù)不足4個字節(jié) ??if(cache.Count < 4) ??{ ???return null; ??} ??//讀取數(shù)據(jù) ??MemoryStream ms = new MemoryStream(cache.ToArray()); ??BinaryReader br = new BinaryReader(ms); ??int len = br.ReadInt32(); ??//根據(jù)長度,判斷內(nèi)容是否傳遞完畢 ??if(len > ms.Length - ms.Position) ??{ ???return null; ??} ??//獲取數(shù)據(jù) ??byte[] result = br.ReadBytes(len); ??//清空消息池 ??cache.Clear(); ??//講剩余沒處理的消息存入消息池 ??cache.AddRange(br.ReadBytes((int)ms.Length - (int)ms.Position)); ?? ??return result; ?} }

用戶接受數(shù)據(jù)代碼如下:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 using System; using System.Collections.Generic; using System.Net.Sockets; // 表示一個客戶端 public class NetUserToken { ?//連接客戶端的Socket ?public Socket socket; ?//用于存放接收數(shù)據(jù) ?public byte[] buffer; ?//每次接受和發(fā)送數(shù)據(jù)的大小 ?private const int size = 1024; ?//接收數(shù)據(jù)池 ?private List<byte> receiveCache; ?private bool isReceiving; ?//發(fā)送數(shù)據(jù)池 ?private Queue<byte[]> sendCache; ?private bool isSending; ?//接收到消息之后的回調(diào) ?public Action<NetModel> receiveCallBack; ?public NetUserToken() ?{ ??buffer = new byte[size]; ??receiveCache = new List<byte>(); ??sendCache = new Queue<byte[]>(); ?} ?// 服務(wù)器接受客戶端發(fā)送的消息 ?// < param name="data">Data.< /param> ?public void Receive(byte[] data) ?{ ??UnityEngine.Debug.Log("接收到數(shù)據(jù)"); ??//將接收到的數(shù)據(jù)放入數(shù)據(jù)池中 ??receiveCache.AddRange(data); ??//如果沒在讀數(shù)據(jù) ??if(!isReceiving) ??{ ???isReceiving = true; ???ReadData(); ??} ?} ?// 讀取數(shù)據(jù) ?private void ReadData() ?{ ??byte[] data = NetEncode.Decode(ref receiveCache); ??//說明數(shù)據(jù)保存成功 ??if(data != null) ??{ ???NetModel item = NetSerilizer.DeSerialize(data); ???UnityEngine.Debug.Log(item.Message); ???if(receiveCallBack != null) ???{ ????receiveCallBack(item); ???} ???//尾遞歸,繼續(xù)讀取數(shù)據(jù) ???ReadData(); ??} ??else ??{ ???isReceiving = false; ??} ?} ?// 服務(wù)器發(fā)送消息給客戶端 ?public void Send() ?{ ??try { ???if (sendCache.Count == 0) { ????isSending = false; ????return; ???} ???byte[] data = sendCache.Dequeue (); ???int count = data.Length / size; ???int len = size; ???for (int i = 0; i < count + 1; i++) { ????if (i == count) { ?????len = data.Length - i * size; ????} ????socket.Send (data, i * size, len, SocketFlags.None); ???} ???UnityEngine.Debug.Log("發(fā)送成功!"); ???Send (); ??} catch (Exception ex) { ???UnityEngine.Debug.Log(ex.ToString()); ??} ?} ?public void WriteSendDate(byte[] data){ ??sendCache.Enqueue(data); ??if(!isSending) ??{ ???isSending = true; ???Send(); ??} ?} } using System; using System.Collections.Generic; using System.Net.Sockets; ?? // 表示一個客戶端 public class NetUserToken { ?//連接客戶端的Socket ?public Socket socket; ?//用于存放接收數(shù)據(jù) ?public byte[] buffer; ?//每次接受和發(fā)送數(shù)據(jù)的大小 ?private const int size = 1024; ?? ?//接收數(shù)據(jù)池 ?private List<byte> receiveCache; ?private bool isReceiving; ?//發(fā)送數(shù)據(jù)池 ?private Queue<byte[]> sendCache; ?private bool isSending; ?? ?//接收到消息之后的回調(diào) ?public Action<NetModel> receiveCallBack; ?? ?? ?public NetUserToken() ?{ ??buffer = new byte[size]; ??receiveCache = new List<byte>(); ??sendCache = new Queue<byte[]>(); ?} ?? ?// 服務(wù)器接受客戶端發(fā)送的消息 ?// < param name="data">Data.< /param> ?public void Receive(byte[] data) ?{ ??UnityEngine.Debug.Log("接收到數(shù)據(jù)"); ??//將接收到的數(shù)據(jù)放入數(shù)據(jù)池中 ??receiveCache.AddRange(data); ??//如果沒在讀數(shù)據(jù) ??if(!isReceiving) ??{ ???isReceiving = true; ???ReadData(); ??} ?} ?? ?// 讀取數(shù)據(jù) ?private void ReadData() ?{ ??byte[] data = NetEncode.Decode(ref receiveCache); ??//說明數(shù)據(jù)保存成功 ??if(data != null) ??{ ???NetModel item = NetSerilizer.DeSerialize(data); ???UnityEngine.Debug.Log(item.Message); ???if(receiveCallBack != null) ???{ ????receiveCallBack(item); ???} ???//尾遞歸,繼續(xù)讀取數(shù)據(jù) ???ReadData(); ??} ??else ??{ ???isReceiving = false; ??} ?} ?? ?// 服務(wù)器發(fā)送消息給客戶端 ?public void Send() ?{ ??try { ???if (sendCache.Count == 0) { ????isSending = false; ????return; ???} ???byte[] data = sendCache.Dequeue (); ???int count = data.Length / size; ???int len = size; ???for (int i = 0; i < count + 1; i++) { ????if (i == count) { ?????len = data.Length - i * size; ????} ????socket.Send (data, i * size, len, SocketFlags.None); ???} ???UnityEngine.Debug.Log("發(fā)送成功!"); ???Send (); ??} catch (Exception ex) { ???UnityEngine.Debug.Log(ex.ToString()); ??} ?} ?? ?public void WriteSendDate(byte[] data){ ??sendCache.Enqueue(data); ??if(!isSending) ??{ ???isSending = true; ???Send(); ??} ?} }

ProtoBuf網(wǎng)絡(luò)傳輸?shù)竭@里就全部完成了。

您可能感興趣的文章:

  • python如何通過protobuf實現(xiàn)rpc
  • 基于Protobuf C++ serialize到char*的實現(xiàn)方法分析
  • 通過Java來測試JSON和Protocol Buffer的傳輸文件大小
  • 使用Protocol Buffers的C語言拓展提速Python程序的示例
  • Protocol Buffer技術(shù)深入理解(C++實例)
Tags:ProtoBuf ProtocolBuffer

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的C#使用Protocol Buffer(ProtoBuf)进行Unity中的Socket通信的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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