Unity 游戏内无法接收 UDP 数据包
Posted
技术标签:
【中文标题】Unity 游戏内无法接收 UDP 数据包【英文标题】:Cannot receive UDP packets inside Unity game 【发布时间】:2012-06-03 09:34:27 【问题描述】:所以,我有这个用 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);
但这会导致游戏挂起。
然后我尝试了另一种方法 - 我尝试在单独的线程中接收数据。就像魔术一样工作如果我所要做的就是接收byte
数组。没有问题。除了我还需要将接收到的数据用作实际游戏中使用的函数的参数(现在,假设我需要在主游戏窗口中将接收到的数据字节显示为字符串)。但是,我不知道 Unity 中的跨线程是如何工作的。我试过这个 -
string data = string.Empty;
private IPEndPoint receivePoint;
void OnGUI()
GUI.Box(new Rect(20, 20, 100, 40), "");
GUI.Label(new Rect(30, 30, 100, 40), 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
但是如果我尝试上述方法,我的程序就会挂起。那么,我到底错过了什么?
【问题讨论】:
【参考方案1】:它挂起的原因是因为 Receive
是这样定义的。它会阻止您当前的代码,直到网络连接(即底层套接字)上有可用数据。您应该为此使用后台线程是正确的。
但请注意,在游戏对象脚本中创建线程可能会很危险,例如,如果您同时将脚本附加到多个对象上。您不希望同时运行此脚本的多个版本,因为它们都会尝试绑定到同一个套接字地址(这不起作用)。 如果游戏对象死亡,您还需要注意关闭线程(这在 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 获取一些示例。
【讨论】:
谢谢。但是,当我这样做时,我得到了这个异常 -SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted. System.Net.Sockets.Socket.Bind (System.Net.EndPoint local_end) System.Net.Sockets.UdpClient.InitSocket (System.Net.EndPoint localEP) System.Net.Sockets.UdpClient..ctor (Int32 port) UDPTest.LoadClient () (at Assets/Scripts/UDPTest.cs:46) UDPTest.Start () (at Assets/Scripts/UDPTest.cs:35)
那个错误是由于我在第二段中解释的。如果您将脚本添加到多个游戏对象,您将获得它的多个副本同时执行(因此,多个套接字尝试打开相同的地址)
实际上,即使我在独立的 C# 程序中使用它也会发生错误,而不仅仅是在 Unity 中。可能是因为服务器和监听器都在同一个IP地址上使用同一个端口?
取决于您如何定义“相同端口”.. 他们都在监听(即在同一个 IPEndPoint 上执行Receive()
)然后是的 - 这是不允许的。每个 host:port 只允许一个监听器。以上是关于Unity 游戏内无法接收 UDP 数据包的主要内容,如果未能解决你的问题,请参考以下文章