Hololens开发笔记:UDP接收数据
Hololens的应用需要与其他设备通信的时候,UDP是比较方便的一种方式,Unity3d 2017.3 C#开发的时候可以用Windows.Networking.Sockets.DatagramSocket 类来接收、发送UDP消息,简单快捷。
.net 的System.net.Socket对象应该也可以,但是只支持部分方法,一开始没走通所以我没继续测试下去。
开发的时候注意两个地方:
1、DatagramSocket.MessageReceived 事件不在主线程运行,所以在这个事件中不能操作UI的东西,比如给文本框赋值,否则报错。
2、Unity Build的时候Player Settings要勾选 PrivateNetworkClientServer,注意跟InternetClientServer不一样。因为我是在局域网测试,一开始只是勾选了InternetClientServer,结果无法接收消息。
---------------------------------------
下面是网上找的一个UDP收发消息的类:
using UnityEngine;
using System;
using System.IO;
using System.Text;
using System.Linq;
using HoloToolkit.Unity;
using System.Collections.Generic;
using UnityEngine.Events; #if !UNITY_EDITOR
using Windows.Networking.Sockets;
using Windows.Networking.Connectivity;
using Windows.Networking;
#endif [System.Serializable]
public class UDPMessageEvent : UnityEvent<string, string, byte[]>
{ } public class UDPCommunication : Singleton<UDPCommunication>
{
[Tooltip("port to listen for incoming data")]
public string internalPort = "12345"; [Tooltip("IP-Address for sending")]
public string externalIP = "192.168.17.110"; [Tooltip("Port for sending")]
public string externalPort = "12346"; [Tooltip("Send a message at Startup")]
public bool sendPingAtStart = true; [Tooltip("Conten of Ping")]
public string PingMessage = "hello"; [Tooltip("Function to invoke at incoming packet")]
public UDPMessageEvent udpEvent = null; private readonly Queue<Action> ExecuteOnMainThread = new Queue<Action>(); #if !UNITY_EDITOR //we've got a message (data[]) from (host) in case of not assigned an event
void UDPMessageReceived(string host, string port, byte[] data)
{
Debug.Log("GOT MESSAGE FROM: " + host + " on port " + port + " " + data.Length.ToString() + " bytes ");
} //Send an UDP-Packet
public async void SendUDPMessage(string HostIP, string HostPort, byte[] data)
{
await _SendUDPMessage(HostIP, HostPort, data);
} DatagramSocket socket; async void Start()
{
if (udpEvent == null)
{
udpEvent = new UDPMessageEvent();
udpEvent.AddListener(UDPMessageReceived);
} Debug.Log("Waiting for a connection..."); /**
*关键点一:创建使用UDP的网络通信对象:DatagramSocket,然后添加接收消息的事件MessageReceived
*/
socket = new DatagramSocket();
socket.MessageReceived += Socket_MessageReceived; HostName IP = null;
try
{
var icp = NetworkInformation.GetInternetConnectionProfile(); IP = Windows.Networking.Connectivity.NetworkInformation.GetHostNames()
.SingleOrDefault(
hn =>
hn.IPInformation?.NetworkAdapter != null && hn.IPInformation.NetworkAdapter.NetworkAdapterId
== icp.NetworkAdapter.NetworkAdapterId);
/**
* 关键点二:绑定IP和监听端口,IP如果传null好像不行。
*/
await socket.BindEndpointAsync(IP, internalPort);
}
catch (Exception e)
{
Debug.Log(e.ToString());
Debug.Log(SocketError.GetStatus(e.HResult).ToString());
return;
} if (sendPingAtStart)
SendUDPMessage(externalIP, externalPort, Encoding.UTF8.GetBytes(PingMessage)); } private async System.Threading.Tasks.Task _SendUDPMessage(string externalIP, string externalPort, byte[] data)
{
using (var stream = await socket.GetOutputStreamAsync(new Windows.Networking.HostName(externalIP), externalPort))
{
using (var writer = new Windows.Storage.Streams.DataWriter(stream))
{
writer.WriteBytes(data);
await writer.StoreAsync(); }
}
} #else
// to make Unity-Editor happy :-)
void Start()
{ } public void SendUDPMessage(string HostIP, string HostPort, byte[] data)
{ } #endif static MemoryStream ToMemoryStream(Stream input)
{
try
{ // Read and write in
byte[] block = new byte[0x1000]; // blocks of 4K.
MemoryStream ms = new MemoryStream();
while (true)
{
int bytesRead = input.Read(block, 0, block.Length);
if (bytesRead == 0) return ms;
ms.Write(block, 0, bytesRead);
}
}
finally { }
} // Update is called once per frame
void Update()
{
/**
* 关键点四:由主线程触发事件,避免外面调用的类可能出错。
*/
while (ExecuteOnMainThread.Count > 0)
{
ExecuteOnMainThread.Dequeue().Invoke(); }
} #if !UNITY_EDITOR
private void Socket_MessageReceived(Windows.Networking.Sockets.DatagramSocket sender,
Windows.Networking.Sockets.DatagramSocketMessageReceivedEventArgs args)
{
Debug.Log("GOT MESSAGE FROM: " + args.RemoteAddress.DisplayName);
//Read the message that was received from the UDP client.
Stream streamIn = args.GetDataStream().AsStreamForRead();
MemoryStream ms = ToMemoryStream(streamIn);
byte[] msgData = ms.ToArray(); /**
* 关键点三:接收到数据用事件发送出去,这里只是把触发事件的代码放到队列ExecuteOnMainThread中。
* 是因为接收函数是多线程的,跟Unity主线程不一样,自己开发的时候如果在这里给文本框赋值会报错!
*/
if (ExecuteOnMainThread.Count == 0)
{
ExecuteOnMainThread.Enqueue(() =>
{
Debug.Log("ENQEUED ");
if (udpEvent != null)
udpEvent.Invoke(args.RemoteAddress.DisplayName, internalPort, msgData);
});
}
} #endif
}
然后是Player Settings截图:

Hololens开发笔记:UDP接收数据的更多相关文章
- iOS开发- 蓝牙后台接收数据(BLE4.0)
最近在做一个蓝牙相关的项目, 需要在应用进入后台, 或者手机属于锁屏状态的情况下, 仍然保持蓝牙连接, 并且能正常接收数据. 本来以后会很麻烦, 但是学习了下..发现就2步而已.简单的不能再简单了. ...
- Hololens开发笔记之连接PC实现资源共享
官网原文介绍:https://developer.microsoft.com/en-us/windows/holographic/using_the_windows_device_portal Hol ...
- Hololens开发笔记之使用Unity开发一个简单的应用
一.Hololens概述 Hololens有以下特性 1.空间映射借助微软特殊定制的全息处理单元(HPU),HoloLens 实现了对周边环境的快速扫描和空间匹配.这保证了 HoloLens能够准确地 ...
- Hololens开发笔记之Gesture手势识别(手势检测反馈)
本文实现当使用者手出现在Hololens视野范围内时,跟踪手并给出反馈的效果. 1.在Manager上添加HandsManager脚本组件,用于追踪识别手 HandsManager.cs如下(直接使用 ...
- HoloLens开发笔记之Gesture input手势输入
手势是HoloLens三个首要输入形式之一.一旦你使用凝视定位了一个全息图像,手势允许你与它交互.手势输入允许你使用手或者点击器原生地与全息图像交互. 手势之外,你也可以在应用中使用语音输入来交互. ...
- Hololens开发笔记之Gesture手势识别(单击,双击)
本文使用手势识别实现识别单击及双击手势的功能,当单击Cube时改变颜色为蓝色,当双击Cube时改变颜色为绿色. 手势识别是HoloLens交互的重要输入方法之一.HoloLens提供了底层API和高层 ...
- Hololens开发笔记之Gesture手势识别(基本介绍)
手势识别是HoloLens交互的重要输入方法之一.HoloLens提供了底层API和高层API,可以满足不同的手势定制需求.底层API能够获取手的位置和速度信息,高层API则借助手势识别器来识别预设的 ...
- Hololens开发笔记之Gaze凝视射线
凝视是HoloLens首要输入方式,形式功能类似于桌面系统的光标,用于选择操作全息对象.然而在Unity中并没有明确的Gaze API或者组件. 概念上来说,Gaze是通过用户头部两眼之间发出一条向前 ...
- ThinkPHP开发笔记-前后端数据交互
此处就是 Controller 和 View 相互传数据. 1.Controller 向 View 的页面传数据.在控制器中把变量传递给模板,使用 assign 方法对模板变量赋值.例如: 在Cont ...
随机推荐
- 部署到docker容器后图片验证码显示不出来
Dockerfile如下: FROM openjdk:8-jre-alpineARG JAR_FILECOPY ${JAR_FILE} app.jarENTRYPOINT ["java&qu ...
- C 语言调试信息输出宏定义
C 语言经常在实际的调试过程中,使用最基本的调试方法printf,我们可以使用__FILENAME__.__FUNCTION__.__LINE__,增加自己的输出宏定义: #define DVR_PR ...
- FileRecv VNCViewer 使用方法
版本 区别 一路点点点 . 就ok了 看到这个页面 点击 vnc viewer 输入 老师 会告诉你 IP地址 点击 就ok
- (转)如何在CentOS / RHEL 7上安装Elasticsearch,Logstash和Kibana(ELK)
原文:https://www.howtoing.com/install-elasticsearch-logstash-and-kibana-elk-stack-on-centos-rhel-7 如果你 ...
- C++中的名字重整技术
C++ 一直为人诟病之一的原因是他的二进制模块兼容性不好,即ABI(Application Binary Interface)问题.对于同一源代码,不同编译器,甚至同一编译器不同版本都不兼容,其编译出 ...
- javac的访问者模式
这一篇重点来总结下javac的访问者模式,其定义的访问者接口为JCTree.Visitor,具体如下: /** A generic visitor class for trees. */ public ...
- OpenJDK编译运行
获取OpenJDK源码有两种方式,其中一种是通过Mercurial代码版本管理工具从Repository中直接取得源码(Repository地址:http://hg.openjdk.java.net/ ...
- WPF中使用TextBlock的Inlines属性来完成复杂的文字内容
参考:http://blog.csdn.net/zhangjiyehandsom/article/details/5498845 1. 需求:要在一行内容中显示不同颜色以及粗细不一的字体, 解决办法: ...
- 使用VMware安装CentOS7详请
话不多说直接开车,乘客坐稳了 准备资料: CentOS-7-x86_64-Everything-1611 点击下载CentOS 对,资料就这些 第一步. 点击文件 再点击新建虚拟机 第二步 .点击 ...
- mysql-5.6.31安装(单实例 Linux)
安装版本:mysql-5.6.31 安装环境:Linux RHEL6.5.x86 安装要求:单实例,端口为默认:3306 (1) 要求安装Mysql数据库版本号及包名为:my ...