• HOLOLENS的SOCKET網絡通訊1

    2019/5/23      點擊(jī):
    多數開發者開發Hololens的通信功能是先想到的是system.net.socket庫裏的socket,發布UWP的時候就可能出問題,因為UWP對system庫不(bú)是完全的支持,很多方法或者類是沒有(yǒu)定義的(這是一個很常見的發布(bù)UWP的報錯)。本文用的system.net.socket裏的SAEA係(xì)列,全(quán)稱:SocketAsyncEvnetArgs,這是微軟針對高並發而(ér)設計的一(yī)套API, SAEA是異步的socket參數,使用SAEA時需要(yào)注意三點:1.緩衝區  2.IP  3.完成後的回調,這(zhè)三點是必要的,其次還有其他的SAEA參數,不(bú)是必要的,例如UserToken等,詳細可查(chá)API。
    using UnityEngine;
    using System.Net;
    using System.Net.Sockets;
    using System;
    using System.Text;
    //這個腳本是(shì)hololens端的SocketUDP腳本(běn),提供發送方法,初始化並開啟接收方法
    public class MyUdpClient : MonoBehaviour
    {
        Socket socket; //目(mù)標socket
        //發送端口
        EndPoint serverEnd; 
        IPEndPoint ipEnd; 
        //接收端口
        IPEndPoint IPLocalPoint;
        //發送用的socket異步參數
        SocketAsyncEventArgs socketAsyceArgs;
        //接收(shōu)用的socket異步參數
        SocketAsyncEventArgs reciveArgs;
        //接收SAEA用來(lái)接收的緩衝(chōng)區
        byte[] reciveArgsBuffer;        
        //初始(shǐ)化
        void InitSocket()
        {
            //定義連接的服務器ip和端口,可以是本機(jī)ip,局域網,互聯網
            ipEnd = new IPEndPoint(ipadsdress.Parse("10.100.172.226"), 8001);
            //初始化要接收的IP,ipadsdress.Any表示接收所有IP地(dì)址發來的字節流
            IPLocalPoint = new IPEndPoint(ipadsdress.Any, 8002);
            //初始化socket
            socket = new Socket(IPLocalPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);  
            //定義服務端
            IPEndPoint sender = new IPEndPoint(ipadsdress.Any, 0);
            serverEnd = (EndPoint)sender;
            //初始化發送用的SAEA
            socketAsyceArgs = new SocketAsyncEventArgs();
            //設置發送用的(de)SAEA的(de)IP
            socketAsyceArgs.RemoteEndPoint = ipEnd;
            //初始化接收用的SAEA的緩衝區,此處我設為10K
            reciveArgsBuffer = new byte[1024 * 10];
            //初始(shǐ)化接收SAEA
            reciveArgs = new SocketAsyncEventArgs();
            //設置接收SAEA的接收IP地址
            reciveArgs.RemoteEndPoint = IPLocalPoint;
            //因為SAEA係列API 是異步(bù)方法,所以設置好完成(chéng)方法後的回調
            reciveArgs.Completed += new EventHandler(CompletedRecive);
            //設置(zhì)接收緩衝(chōng)區
            reciveArgs.SetBuffer(reciveArgsBuffer, 0, reciveArgsBuffer.Length);
        }
        //異步方法完(wán)成(chéng)後的complete時間
        private void CompletedRecive(object sender, SocketAsyncEventArgs e)
        {
            //通過SAEA.LastOperation這個枚舉來判斷完成的是什麽方法,對應(yīng)不同的操作
            switch (reciveArgs.LastOperation)
            {
                //因為reciveArgs是我專門用來接收的SAEA,所以這(zhè)裏隻設置一個完成接收後用的方法
                case SocketAsyncOperation.ReceiveFrom:
                    PocessReceiveFrom(e);
                    break;       
            }
        }
        //中轉緩衝區,將數據拷貝出來給主線程用
        byte[] tempBytes;
        //用來通知主(zhǔ)線程的參數
        bool isOk=false;
        //注意:處理這個方法是輔線程,不要用Unity的類,否(fǒu)則報錯,將收(shōu)到(dào)的字節流拷貝出來,通知主線程來處(chù)理(lǐ)
        //接收完成後對(duì)應的處理方法
        public void PocessReceiveFrom(SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
            {
                //這裏會造成內存垃圾以及內存碎片化,如果頻(pín)繁的長(zhǎng)時間的接(jiē)收,建議做一個Byte池。
                tempBytes = new byte[e.BytesTransferred];     //將數據拷貝(bèi)出來保證(zhèng)可以複用
                Array.Copy(e.Buffer, e.Offset, tempBytes, 0, tempBytes.Length);
                //通知主線程(chéng)
                isOk = true;
            }
        }
        ////// 異步發送消息方法
        //////public void AsyncSend(byte[] bytes)
        {
            //設置緩衝區,緩衝區裏是發送的字節流
            socketAsyceArgs.SetBuffer(bytes, 0, bytes.Length);
            //Debug.Log("socket異步參數字節流長度 " + socketAsyceArgs.Buffer.Length);
            bool bo = socket.SendToAsync(socketAsyceArgs);
            if (!bo)
            {
                //在hololens上發現過一段(duàn)時間scoket就不會發(fā)送數(shù)據,*後這樣處(chù)理:判(pàn)斷SentToAsync方法失敗後,就重新new一個SAEA,解決socket發送(sòng)失敗的問題(tí)
                //注意初始化一個SAEA時,1.IP    2.緩衝區,3.完成後的回(huí)調事件  這三個都是必要的,
                socketAsyceArgs = new SocketAsyncEventArgs();
                socketAsyceArgs.RemoteEndPoint = ipEnd;
            }
        }
        //初始化socket並測試一下
        private void Start()
        {
            InitSocket();
            TestSocekt();
        }
        //用來測(cè)試socket的方(fāng)法,發送一個(gè)信息
        void TestSocekt() {
            int tempInt = 9999;
            byte[] tempBytes;
     
            tempBytes=BitConverter.GetBytes(tempInt);
            AsyncSend(tempBytes);
        }
        private void Update()
        {
            if (isOk)
            {
                //對tempBytes進行處理
                int temp= BitConverter.ToInt32(tempBytes, 0);
                Debug.Log("接收socket,接收到了(le)字節流,接收到的數字為(wéi) " + temp);
                isOk = false;
            }
        }
        //每隔一(yī)段時間就接(jiē)受一下
        private void FixedUpdate()
        {
            socket.ReceiveFromAsync(reciveArgs);
        }
    }
    上麵的代碼把接收模(mó)塊和發送模塊寫在一起,SAEA係(xì)列是異步的,所以使用起來對(duì)於多線程需要一些了解。
    一般的socket需求用上麵的(de)代(dài)碼足夠用的,由於(yú)上文中隻有一個(gè)接收SAEA和一個發送SAEA,所以當一個(gè)SAEA在工作時,不要(yào)再讓這個SAEA工作。

    捷徑:後(hòu)來(lái)發現(xiàn)在MixedRealTooklit裏麵有scoket組(zǔ)件,可以直接使用MRTK中Sharing文件夾中的組件,或(huò)者查看MRTK的源碼,裏麵是用Windows.Networking和(hé)Task寫的Socket,找了很長時間的SocketAPI,原來遠(yuǎn)在天邊近在眼前,感歎當時怎麽不(bú)好好看看MRTK!!

    日本中出视频|午夜免费福利在线|亚洲精品亚洲人成在线下载|国产高潮流白浆免费观看不卡|偷拍亚洲欧美|亚洲中文字幕久爱亚洲伊人|久久久久香蕉视频|国产欧美日韩一区|久久国产成人亚洲精品影院老金|久久久久中文字幕