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