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