HOLOLENS的SOCKET网络通讯1
2019/5/23 点击:
多数开发者开发Hololens的通信功能是先想到的是system.net.socket库里的socket,发布UWP的时候就可能出问题,因为UWP对system库不是完全的支持,很多方法或者类是没有定义的(这是一个很常见的发布UWP的报错)。本文用的system.net.socket里的SAEA系列,全称:SocketAsyncEvnetArgs,这是微软针对高并发而设计的一套API, SAEA是异步的socket参数,使用SAEA时需要注意三点:1.缓冲区 2.IP 3.完成后的回调,这三点是必要的,其次还有其他的SAEA参数,不是必要的,例如UserToken等,详细可查API。
一般的socket需求用上面的代码足够用的,由于上文中只有一个接收SAEA和一个发送SAEA,所以当一个SAEA在工作时,不要再让这个SAEA工作。
using UnityEngine; using System.Net; using System.Net.Sockets; using System; using System.Text; //这个脚本是hololens端的SocketUDP脚本,提供发送方法,初始化并开启接收方法 public class MyUdpClient : MonoBehaviour { Socket socket; //目标socket //发送端口 EndPoint serverEnd; IPEndPoint ipEnd; //接收端口 IPEndPoint IPLocalPoint; //发送用的socket异步参数 SocketAsyncEventArgs socketAsyceArgs; //接收用的socket异步参数 SocketAsyncEventArgs reciveArgs; //接收SAEA用来接收的缓冲区 byte[] reciveArgsBuffer; //初始化 void InitSocket() { //定义连接的服务器ip和端口,可以是本机ip,局域网,互联网 ipEnd = new IPEndPoint(IPAddress.Parse("10.100.172.226"), 8001); //初始化要接收的IP,IPAddress.Any表示接收所有IP地址发来的字节流 IPLocalPoint = new IPEndPoint(IPAddress.Any, 8002); //初始化socket socket = new Socket(IPLocalPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); //定义服务端 IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); serverEnd = (EndPoint)sender; //初始化发送用的SAEA socketAsyceArgs = new SocketAsyncEventArgs(); //设置发送用的SAEA的IP socketAsyceArgs.RemoteEndPoint = ipEnd; //初始化接收用的SAEA的缓冲区,此处我设为10K reciveArgsBuffer = new byte[1024 * 10]; //初始化接收SAEA reciveArgs = new SocketAsyncEventArgs(); //设置接收SAEA的接收IP地址 reciveArgs.RemoteEndPoint = IPLocalPoint; //因为SAEA系列API 是异步方法,所以设置好完成方法后的回调 reciveArgs.Completed += new EventHandler(CompletedRecive); //设置接收缓冲区 reciveArgs.SetBuffer(reciveArgsBuffer, 0, reciveArgsBuffer.Length); } //异步方法完成后的complete时间 private void CompletedRecive(object sender, SocketAsyncEventArgs e) { //通过SAEA.LastOperation这个枚举来判断完成的是什么方法,对应不同的操作 switch (reciveArgs.LastOperation) { //因为reciveArgs是我专门用来接收的SAEA,所以这里只设置一个完成接收后用的方法 case SocketAsyncOperation.ReceiveFrom: PocessReceiveFrom(e); break; } } //中转缓冲区,将数据拷贝出来给主线程用 byte[] tempBytes; //用来通知主线程的参数 bool isOk=false; //注意:处理这个方法是辅线程,不要用Unity的类,否则报错,将收到的字节流拷贝出来,通知主线程来处理 //接收完成后对应的处理方法 public void PocessReceiveFrom(SocketAsyncEventArgs e) { if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { //这里会造成内存垃圾以及内存碎片化,如果频繁的长时间的接收,建议做一个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上发现过一段时间scoket就不会发送数据,*后这样处理:判断SentToAsync方法失败后,就重新new一个SAEA,解决socket发送失败的问题 //注意初始化一个SAEA时,1.IP 2.缓冲区,3.完成后的回调事件 这三个都是必要的, socketAsyceArgs = new SocketAsyncEventArgs(); socketAsyceArgs.RemoteEndPoint = ipEnd; } } //初始化socket并测试一下 private void Start() { InitSocket(); TestSocekt(); } //用来测试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; } } //每隔一段时间就接受一下 private void FixedUpdate() { socket.ReceiveFromAsync(reciveArgs); } }上面的代码把接收模块和发送模块写在一起,SAEA系列是异步的,所以使用起来对于多线程需要一些了解。
一般的socket需求用上面的代码足够用的,由于上文中只有一个接收SAEA和一个发送SAEA,所以当一个SAEA在工作时,不要再让这个SAEA工作。
捷径:后来发现在MixedRealTooklit里面有scoket组件,可以直接使用MRTK中Sharing文件夹中的组件,或者查看MRTK的源码,里面是用Windows.Networking和Task写的Socket,找了很长时间的SocketAPI,原来远在天边近在眼前,感叹当时怎么不好好看看MRTK!!
- 上一篇:Hololens官方精简教程 - 配置教程 2019/5/23
- 下一篇:UNITY3D设置VS2015调试的方法 2019/5/11