socket傳輸protobuf位元組流的執行個體介紹

來源:互聯網
上載者:User
上一篇講到了資料的處理,這一篇主要講使用多線程收發訊息

//建立訊息資料模型  2//正式項目中,訊息的結構一般是訊息長度+訊息id+訊息主體內容  3 public class Message  4 {      public IExtensible protobuf;   public int messageId;  7 }  8   9 public class SocketClientTemp : MonoBehaviour 10 { 11       const int packageMaxLength = 1024; 12  13     Socket mSocket; 14     Thread threadSend; 15       Thread threadRecive; 16     Queue<Message> allMessages = new Queue<Message>(); 17       Queue<byte[]> sendQueue = new Queue<byte[]>();  public bool Init() 20       { 21         //建立一個socket對象 22           mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 23            return SocketConnection("此處是ip", 1111); 24     } 25  26     void Update() 27     { 28           AnalysisMessage(); 29     } 30  31     /// <summary> 32     /// 建立伺服器串連 33     /// </summary> 34        /// <param name="ip">伺服器的ip地址</param> 35     /// <param name="port">連接埠</param> 36        bool SocketConnection(string ip, int port) 37     { 38         try 39         { 40                IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ip), port); 41               //同步串連伺服器,實際使用時推薦使用非同步串連,處理方式會在下一篇講斷線重連時講到 42               mSocket.Connect(ipep); 43             //串連成功後,建立兩個線程,分別用於發送和接收訊息 44               threadSend = new Thread(new ThreadStart(SendMessage)); 45             threadSend.Start(); 46               threadRecive = new Thread(new ThreadStart(ReceiveMessage)); 47             threadRecive.Start(); 48               return true; 49         } 50         catch (Exception e) 51         { 52               Debug.Log(e.ToString()); 53             Close(); 54             return false; 55           }      }         #region ...發送訊息 59      /// <summary> 60     /// 添加資料到發送隊列 61      /// </summary> 62     /// <param name="protobufModel"></param> 63      /// <param name="messageId"></param> 64     public void AddSendMessageQueue(IExtensible protobufModel, int messageId) 65     { 66         sendQueue.Enqueue(BuildPackage(protobufModel, messageId)); 67     } void SendMessage() 70     { 71         //迴圈擷取發送隊列中第一個資料,然後發送到伺服器 72          while (true) 73         { 74             if (sendQueue.Count == 0) 75             { 76                  Thread.Sleep(100); 77                 continue; 78             } 79             if (!mSocket.Connected) 80             { 81                 Close(); 82                 break; 83             } 84             else 85                 Send(sendQueue.Peek());//發送隊列中第一條資料 86         } 87     } 88  89     void Send(byte[] bytes) 90     { 91         try 92          { 93             mSocket.Send(bytes, SocketFlags.None); 94              //發送成功後,從發送隊列中移除已發送的訊息 95             sendQueue.Dequeue(); 96          } 97         catch (SocketException e) 98         { 99              //如果錯誤碼為10035,說明伺服器緩衝區滿了,所以等100毫秒再次發送100              if (e.NativeErrorCode == 10035)101             {102                 Thread.Sleep(100);103                 Send(bytes);104              }105             else106                  Debug.Log(e.ToString());107         }108     }109     #endregion110 111      #region ...接收訊息112     /// <summary>113     /// 解析收到的訊息114      /// </summary>115     void AnalysisMessage()116     {117          while (allMessages.Count > 0)118         {119              int id = allMessages.Dequeue().messageId;120              switch (id)121             {122                 //根據訊息id做不同的處理123             }124         }125     }126 127      /// <summary>128     /// 接收資料129     /// </summary>130      void ReceiveMessage()131     {132         while (true)133          {134             if (!mSocket.Connected)135                  break;136             byte[] recvBytesHead = GetBytesReceive(4);137              int bodyLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(recvBytesHead, 0));138              byte[] recvBytesBody = GetBytesReceive(bodyLength);139 140              byte[] messageId = new byte[4];141              Array.Copy(recvBytesBody, 0, messageId, 0, 4);142              byte[] messageBody = new byte[bodyLength - 4];143              Array.Copy(recvBytesBody, 4, messageBody, 0, bodyLength - 4);144 145              if (BitConverter.IsLittleEndian)146                  Array.Reverse(messageId);147              FillAllPackages(BitConverter.ToInt32(messageId, 0), messageBody);148          }     }  /// <summary>152       /// 填充接收訊息佇列153     /// </summary>154        /// <param name="messageId"></param>155     /// <param name="messageBody"></param>156     void FillAllPackages(int messageId, byte[] messageBody)157     {158         switch (messageId)159         {160             //根據訊息id處理訊息,並添加到接收訊息佇列161             case 1:162                 allMessages.Enqueue(new Message() 163                 {164                     protobuf = ProtobufSerilizer.DeSerialize<TestTemp>(messageBody), 165                     messageId = messageId 166                 });167                 break;168         }169     }170 171     /// <summary>172     /// 接收資料並處理173     /// </summary>174     /// <param name="length"></param>175     /// <returns></returns>176     byte[] GetBytesReceive(int length)177     {178         byte[] recvBytes = new byte[length];179         while (length > 0)180         {181             byte[] receiveBytes = new byte[length < packageMaxLength ? length : packageMaxLength];182             int iBytesBody = 0;183             if (length >= receiveBytes.Length)184                 iBytesBody = mSocket.Receive(receiveBytes, receiveBytes.Length, 0);185             else186                 iBytesBody = mSocket.Receive(receiveBytes, length, 0);187             receiveBytes.CopyTo(recvBytes, recvBytes.Length - length);188             length -= iBytesBody;189         }190         return recvBytes;191     }192     #endregion193 194     /// <summary>195     /// 構建訊息資料包196     /// </summary>197     /// <param name="protobufModel"></param>198     /// <param name="messageId"></param>199     byte[] BuildPackage(IExtensible protobufModel, int messageId)200     {201         byte[] b;202         if (protobufModel != null)203             b = ProtobufSerilizer.Serialize(protobufModel);204         else205             b = new byte[0];206         //訊息長度(int資料,長度4) + 訊息id(int資料,長度4) + 訊息主體內容207         ByteBuffer buf = ByteBuffer.Allocate(b.Length + 4 + 4);208         //訊息長度 = 訊息主體內容長度 + 訊息id長度209         buf.WriteInt(b.Length + 4);210         buf.WriteInt(messageId);211 212         if (protobufModel != null)213             buf.WriteBytes(b);214         return buf.GetBytes();215     }216 217     void OnDestroy()218     {219          //停止運行後,如果不關閉socket多線程,再次運行時,unity會卡死220         Close();221     }222 223      /// <summary>224     /// 關閉socket,終止線程225     /// </summary>226     public void Close()227      {228         if (mSocket != null)229         {230              //微軟官方推薦在關閉socket前先shutdown,但是經過測試,發現網路斷開後,shutdown會無法執行231              if (mSocket.Connected)232                 mSocket.Shutdown(SocketShutdown.Both);233              mSocket.Close();234             mSocket = null;235         }236         //關閉線程237          if (threadSend != null)238             threadSend.Abort();239         if (threadRecive != null)240             threadRecive.Abort();241         threadSend = null;242         threadRecive = null;243     }244 }

到這裡,使用socket處理訊息的收發就基本結束了,但是,某些項目為了增強體驗,可能還會增加斷線重連的功能,這個功能會在下一篇講到

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.