所以,我有这个用Unity编写的游戏,它应该通过UDP实时接收数据.数据将通过用
Java编写的
Android设备进行无线传输,而Unity程序则用C#编写.我的问题是,每当我尝试声明一个UdpClient对象,并在Unity的Update()方法中调用它的Receive()方法时,游戏就会挂起.这是我试图放入Update()方法的代码 –
UdpClient client = new UdpClient(9877); IPEndPoint receivePoint = new IPEndPoint(IPAddress.Parse("192.168.1.105"),9877); byte[] recData = client.Receive(ref receivePoint);
但它导致游戏停滞不前.
然后我尝试了另一种方法 – 我试图在一个单独的线程中接收数据.如果我所要做的就是接收字节数组,那就像魔法一样.没有问题.除了我还需要将接收到的数据用作实际游戏中使用的函数的参数(现在,我只想说我需要在主游戏窗口中将接收的数据字节显示为字符串).但是,我不知道Unity中的跨线程如何工作.我试过这个 –
string data = string.Empty; private IPEndPoint receivePoint; void OnGUI() { GUI.Box(new Rect(20,20,100,40),""); GUI.Label(new Rect(30,30,data); } void Start() { LoadClient(); } public void LoadClient() { client = new UdpClient(9877); receivePoint = new IPEndPoint(IPAddress.Parse("192.168.1.105"),9877); Thread startClient = new Thread(new ThreadStart(StartClient)); startClient.Start(); } public void StartClient() { try { while (true) { byte[] recData = client.Receive(ref receivePoint); System.Text.ASCIIEncoding encode = new System.Text.ASCIIEncoding(); data = encode.GetString(recData); } } catch { } }
但是如果我尝试上面的话,我的程序会挂起.那么,我到底错过了什么?
解决方法
它为你挂起的原因是因为这是接收定义的方式.它会阻止当前代码,直到网络连接上有可用数据(即底层套接字).你应该使用后台线程是正确的.
但请注意,在游戏对象脚本中创建线程可能是危险的事情,以防您例如同时将脚本附加到多个对象.您不希望同时运行此脚本的多个版本,因为它们都会尝试绑定到相同的套接字地址(这将不起作用).
如果游戏对象死亡,你还需要注意关闭线程(这不是在C#中自动完成的 – 你必须停止线程).
也就是说,当您使用多个线程时,您需要确保线程安全.这意味着您需要保护数据,以便在写入数据时无法读取数据.最简单的方法是使用C# locks:
private readonly Object _dataLock = new Object(); private string _sharedData = String.Empty; void OnGUI() { string text = ""; lock (_dataLock) text = _sharedData; } void StartClient() { // ... [snip] var data = Encoding.ASCII.GetString(recData); lock (_dataLock) _sharedData = data; }
请注意,锁定会对性能造成一定影响,尤其是频繁使用时.还有其他方法可以保护c#中更高性能(但稍微复杂一点)的数据.有关示例,请参阅Microsoft的this guideline.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。