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