1. 程式人生 > >【轉】Unity3d中的Tcp socket通訊(開源)

【轉】Unity3d中的Tcp socket通訊(開源)

轉自:https://blog.csdn.net/hiramtan/article/details/72621787

HiSocket_unity

如何使用

可以從此連結下載最新的unity package: Github Releases

功能

  • Tcp socket
  • Udp socket
  • 可伸縮位元組表
  • 高效能位元組塊緩衝區
  • 訊息註冊和回撥
  • 二進位制位元組訊息封裝
  • Protobuf訊息封裝
  • AES訊息加密

詳情

  • Tcp和Udp都是採用主執行緒非同步連線的方式(避免主執行緒阻塞).
  • 啟動傳送執行緒和接收執行緒處理資料傳輸(提高效能).
  • 供使用者呼叫傳送或接受資料的API在主執行緒中(方便直接操作unity的元件)
  • 監聽連線事件獲得當前的連線狀態.
  • 監聽接收事件獲得接收的資料.
  • 存在位元組陣列佇列,方便用來測試和資料重發.
  • 高效能位元組緩衝區避免記憶體空間重複申請,減少GC.
  • 如果使用Tcp協議需要實現IPackage介面處理粘包拆包.
  • Ping介面因為mono底層的bug會在.net2.0平臺報錯(.net 4.6 沒有問題,或者也可以使用unity的介面獲得Ping,工程中有示例程式碼)

細節

    • Tcp connection 
      Tcp協議傳輸位元組流,使用者需要分割位元組流獲得正確的資料包,當建立一個tcp協議的socket時,需要傳入一個Package物件來封包和解包.

      private IPackage _packer = new Packer();
      void Test()
      {
       _tcp = new
      TcpConnection(_packer); } public class Packer : IPackage { public void Unpack(IByteArray reader, Queue<byte[]> receiveQueue) { //add your unpack logic here } public void Pack(Queue<byte[]> sendQueue, IByteArray writer) { // add your pack logic here } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    • 連線

      _tcp.Connect("127.0.0.1", 7777);
      • 1
    • 斷開連線 
      當不再執行時需要主動呼叫介面斷開與伺服器的連線(比如響應unity的onapplicationquit執行時)

      void OnApplicationQuit()
      {
          _tcp.DisConnect();
      }
      • 1
      • 2
      • 3
      • 4
    • 連線狀態變化 
      如果想獲取當前的連線狀態,可以訂閱連線狀態事件.

      void Test()
      {
          _tcp.StateChangeEvent += OnState;
      }
      void OnState(SocketState state)
      {
          Debug.Log("current state is: " + state);
          if (state == SocketState.Connected)
          {
              Debug.Log("connect success");
              //can send or receive message
          }
          else if (state == SocketState.DisConnected)
          {
              Debug.Log("connect failed");
          }
          else if (state == SocketState.Connecting)
          {
              Debug.Log("connecting");
          }
      }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
    • 傳送訊息

      void Test()
      {
          var bytes = BitConverter.GetBytes(100);
          _tcp.Send(bytes);
      }
      • 1
      • 2
      • 3
      • 4
      • 5
    • 接受訊息 
      You can regist receiveevent and when message come from server, this event will be fire.

          void Test()
          {
              _tcp.ReceiveEvent += OnReceive;
          }
          void OnReceive(byte[] bytes)
          {
              Debug.Log("receive msg: " + BitConverter.ToInt32(bytes, 0));
          }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • 封包和解包 
      最初建立連線時我們定義了一個packer來分割資料包,當傳送訊息時我們在資料頭部插入訊息長度/當接收到訊息時我們根據頭部的訊息長度獲得資料包的大小.

      private bool _isGetHead = false;
      private int _bodyLength;
      public void Unpack(IByteArray reader, Queue<byte[]> receiveQueue)
      {
          if (!_isGetHead)
          {
              if (reader.Length >= 2)//2 is example, get msg's head length
              {
                  var bodyLengthBytes = reader.Read(2);
                  _bodyLength = BitConverter.ToUInt16(bodyLengthBytes, 0);
              }
              else
              {
                  if (reader.Length >= _bodyLength)//get body
                  {
                      var bytes = reader.Read(_bodyLength);
                      receiveQueue.Enqueue(bytes);
                      _isGetHead = false;
                  }
              }
          }
      }
      public void Pack(Queue<byte[]> sendQueue, IByteArray writer)
      {
          var bytesWaitToPack = sendQueue.Dequeue();
          UInt16 length = (UInt16)bytesWaitToPack.Length;//get head lenth
          var bytesHead = BitConverter.GetBytes(length);
          writer.Write(bytesHead);//write head
          writer.Write(bytesWaitToPack);//write body
      }
      • 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
  • Udp

    • Udp connection 
      如果建立upd連線,需要指定傳送接收緩衝區大小.

      _udp = new UdpConnection(1024);
      • 1
  • Ping

    public int PingTime;
    private Ping p;
    private float timeOut = 1;
    private float lastTime;
    void Start()
    {
        StartCoroutine(Ping());
    }
    IEnumerator Ping()
    {
        p = new Ping("127.0.0.1");
        lastTime = Time.realtimeSinceStartup;
        while (!p.isDone && Time.realtimeSinceStartup - lastTime < 1)
        {
            yield return null;
        }
        PingTime = p.time;
        p.DestroyPing();
        yield return new WaitForSeconds(1);
        StartCoroutine(Ping());
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 訊息註冊
  • Protobuf
  • 位元組訊息
  • 加密

Tcp Example

Tcp 協議提供可靠有序的流位元組傳輸,使用者需要自己分割資料,在這個框架中可以繼承IPackage介面來實現.

    private ITcp _tcp;
    private IPackage _packer = new Packer();
    // Use this for initialization
    void Start()
    {
        _tcp = new TcpConnection(_packer);
        _tcp.StateChangeEvent += OnState;
        _tcp.ReceiveEvent += OnReceive;
        Connect();
    }
    void Update()
    {
        _tcp.Run();
    }

    void Connect()
    {
        _tcp.Connect("127.0.0.1", 7777);
    }
    // Update is called once per frame

    void OnState(SocketState state)
    {
        Debug.Log("current state is: " + state);
        if (state == SocketState.Connected)
        {
            Debug.Log("connect success");
            Send();
        }
        else if (state == SocketState.DisConnected)
        {
            Debug.Log("connect failed");
        }
        else if (state == SocketState.Connecting)
        {
            Debug.Log("connecting");
        }
    }
    void OnApplicationQuit()
    {
        _tcp.DisConnect();
    }
    void Send()
    {
        for (int i = 0; i < 10; i++)
        {
            var bytes = BitConverter.GetBytes(i);
            Debug.Log("send message: " + i);
            _tcp.Send(bytes);
        }
    }
    void OnReceive(byte[] bytes)
    {
        Debug.Log("receive msg: " + BitConverter.ToInt32(bytes, 0));
    }
    public class Packer : IPackage
    {
        public void Unpack(IByteArray reader, Queue<byte[]> receiveQueue)
        {
            //add your unpack logic here
            if (reader.Length >= 1024)//1024 is example, it's msg's length
            {
                var bytesWaitToUnpack = reader.Read(1024);
                receiveQueue.Enqueue(bytesWaitToUnpack);
            }
        }

        public void Pack(Queue<byte[]> sendQueue, IByteArray writer)
        {
            var bytesWaitToPack = sendQueue.Dequeue();
            // add your pack logic here
            //

            writer.Write(bytesWaitToPack);
        }
    }
  • 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

Udp Example

Udp協議提供不可靠的報文訊息,使用者無法知道當前連線狀態,但是訊息包時完整的.

    private UdpConnection _udp;
    // Use this for initialization
    void Start()
    {
        _udp = new UdpConnection(1024);
        _udp.ReceiveEvent += OnReceive;
        Connect();
        Send();
    }
    void Connect()
    {
        _udp.Connect("127.0.0.1", 7777);
    }
    // Update is called once per frame
    void Update()
    {
        _udp.Run();
    }
    void Send()
    {
        for (int i = 0; i < 10; i++)
        {
            var bytes = BitConverter.GetBytes(i);
            _udp.Send(bytes);
            Debug.Log("send message: " + i);
        }
    }
    private void OnApplicationQuit()
    {
        _udp.DisConnect();
    }
    void OnReceive(byte[] bytes)
    {
        Debug.Log("receive bytes: " + BitConverter.ToInt32(bytes, 0));
    }
  • 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

Message Registration Example

    void RegistMsg()
    {
        MsgRegister.Regist("10001", OnMsg_Bytes);
        MsgRegister.Regist("10002", OnMsg_Protobuf);
    }

    void OnMsg_Bytes(IByteArray byteArray)
    {
        var msg = new MsgBytes(byteArray);
        int getInt = msg.Read<int>();
    }

    void OnMsg_Protobuf(IByteArray byteArray)
    {
        var msg = new MsgProtobuf(byteArray);
        GameObject testClass = msg.Read<GameObject>();//your class's type
        var testName = testClass.name;
    }

相關推薦

Unity3dTcp socket通訊開源

轉自:https://blog.csdn.net/hiramtan/article/details/72621787HiSocket_unity如何使用可以從此連結下載最新的unity package: 功能Tcp socketUdp socket可伸縮位元組表高效能位元組塊

QtQt之程序間通訊QProcess

簡述 前幾節裡,分享了程序通訊的幾種方式:Windows訊息機制、Shared Memory(共享記憶體),本節講解下關於程序通訊的另外一種方式-QProcess。 簡述 命令列讀取 說明 實現 更多參考 命令列引數啟動 說明 程序A-帶參啟動

QtQt之程序間通訊IPC

簡述 程序間通訊,就是在不同程序之間傳播或交換資訊。那麼不同程序之間存在著什麼雙方都可以訪問的介質呢?程序的使用者空間是互相獨立的,一般而言是不能互相訪問的,唯一的例外是共享記憶體區。但是,系統空間卻是“公共場所”,所以核心顯然可以提供這樣的條件。除此以外,那就是雙方都可以訪問的外設了。在這個意義上,兩

深入淺出理解決策樹演算法-ID3演算法與C4.5演算法

從深入淺出理解決策樹演算法(一)-核心思想 - 知乎專欄文章中,我們已經知道了決策樹最基本也是最核心的思想。那就是其實決策樹就是可以看做一個if-then規則的集合。我們從決策樹的根結點到每一個都葉結點構建一條規則。 並且我們將要預測的例項都可以被一條路徑或者一條規則所覆蓋。 如下例:假設我

深入淺出理解決策樹演算法-核心思想

演算法思想 決策樹(decision tree)是一個樹結構(可以是二叉樹或非二叉樹)。 其每個非葉節點表示一個特徵屬性上的測試,每個分支代表這個特徵屬性在某個值域上的輸出,而每個葉節點存放一個類別。 使用決策樹進行決策的過程就是從根節點開始,測試待分類項中相應的特徵屬性,並按照其值選擇

QT TCP socket通訊

TCP即Transmission Control Protocol,傳輸控制協議。與UDP不同,它是面向連線和資料流的可靠傳輸協議。也就是說,它能使一臺計算機上的資料無差錯的發往網路上的其他計算機,所以當要傳輸大量資料時,我們選用TCP協議。 TCP協議的程式使用的是客

深入理解Java:註解Annotation--註解處理器

display 枚舉 lec con null cto run toolbar int https://www.cnblogs.com/peida/archive/2013/04/26/3038503.html   如果沒有用來讀取註解的方法和工作,那麽註解也就

js15個常用的正則表達式

顏色 字符 8.4 特殊字符 cnp 浮點數 == div mail 1 用戶名正則 //用戶名正則,4到16位(字母,數字,下劃線,減號) var uPattern = /^[a-zA-Z0-9_-]{4,16}$/; //輸出 true console.log(uPa

VS2010 C++創建DLL圖解

-a rar cls ret ria endif -s pan 項目 標簽: dllc++2010threadlibraryc 本文章已收錄於: .embody { padding: 10px 10px 10px; margin: 0 -20px; b

QTQWidget、QDialog及QMainWindow的區別

屏幕 編輯 派生 標記 裝飾 按鈕 set 沒有 idg QWidget類是所有用戶界面對象的基類。 窗口部件是用戶界面的一個基本單元:它從窗口系統接收鼠標、鍵盤和其它事件,並且在屏幕上繪制自己。每一個窗口部件都是矩形的,並且它們按Z軸順序排列。一個窗口部件可以被它的父窗口

C#的兩把雙刃劍:抽象類和接口

實例 可維護 對象 為什麽不使用 程序 一定的 代碼 方式 索引 轉:http://www.cnblogs.com/djzxjblogs/p/7587735.html 第一次面試的時候, 面試官問我,抽象類和接口的區別。 本人也是,按照面試寶典上的回答,說了一大堆。

C++const在函數名前面和函數後面的區別

const成員函數 調用 參數傳遞 成員 指向 int 區別 ... urn 一、概念   當const在函數名前面的時候修飾的是函數返回值,在函數名後面表示是常成員函數,該函數不能修改對象內的任何成員,只能發生讀操作,不能發生寫操作。 二、原理:   我們都知道在調用

瀏覽器輸入url後發生了什麽

正常 工作 orb 問題: serve es2017 背景 ace perm 原文地址:http://www.jianshu.com/p/c1dfc6caa520 在學習前端的過程中經常看到這樣一個問題:當你在瀏覽器中輸入url後發生了什麽?下面是個人學習過程中的總結,供個

js的事件委托或是事件代理詳解

ava 程序 fff 員工 我們 cnblogs 上傳 on() 類型 起因: 1、這是前端面試的經典題型,要去找工作的小夥伴看看還是有幫助的; 2、其實我一直都沒弄明白,寫這個一是為了備忘,二是給其他的知其然不知其所以然的小夥伴們以參考; 概述: 那什麽叫

SQL的取整函數FLOOR、ROUND、CEIL、TRUNC、SIGN

log rec 截取 符號 floor 個數 clas 絕對值 sign --------------------------------------------------------------------------1 trunc(value,precision)按精

AppDomain 詳解二-C#動態加載和卸載DLL

all created 新版本 odin generic reflect 可能 params 詳細 在C++中加載和卸載DLL是一件很容易的事,LoadLibrary和FreeLibrary讓你能夠輕易的在程序中加載DLL,然後在任何地方 卸載。在C#中我們也能使用Asse

Python操作mysql的pymysql模塊詳解

定義 padding 參數化查詢 finall 支持 順序 執行sql mysq syntax Python中操作mysql的pymysql模塊詳解 前言 pymsql是Python中操作MySQL的模塊,其使用方法和MySQLdb幾乎相同。但目前pymysql支持p

CSS的浮動和清除浮動

但是 spa 下拉 而已 ges 推薦 授權 自己的 -c 以下轉自《CSS中的浮動和清除浮動,梳理一下!》 浮動到底是什麽? 浮動核心就一句話:浮動元素會脫離文檔流並向左/向右浮動,直到碰到父元素或者另一個浮動元素。請默念3次! 浮動最初設計的目

C#Func與Action的理解

.net ring UNC 簡單 代碼 操作 不必要 返回值 tps 原文地址:https://www.cnblogs.com/ultimateWorld/p/5608122.html Action 與 Func是.NET類庫中增加的內置委托,以便更加簡潔方便的使用委托。最

android開發學習 ------- android的單例模式 詳解

lan post tail -- and 使用 href details android開發 https://blog.csdn.net/u011418943/article/details/60139644 這篇文章 前因後果 都說出來了 ,值得學習。 htt