2012-05-29 151 views
4

所以,我有这款游戏是用Unity编写的,它应该可以通过UDP实时接收数据。数据将通过以Java编写的Android设备无线传输,而Unity程序则使用C#编写。我的问题是,每当我尝试声明一个UdpClient对象,并在Update()方法中调用它的Receive()方法时,游戏就会挂起。这里是我想要放入我的Update()方法中的代码 -无法在Unity游戏内接收UDP数据包

UdpClient client = new UdpClient(9877); 
IPEndPoint receivePoint = new IPEndPoint(IPAddress.Parse("192.168.1.105"), 9877); 
byte[] recData = client.Receive(ref receivePoint); 

但它导致游戏挂起。

然后我尝试了另一种方法 - 我尝试在单独的线程中接收数据。像魔术一样工作如果我所要做的就是收到bytearray。没有问题。除了我还需要收到的数据作为实际游戏中使用的函数的参数(现在,我们只需说我需要在主游戏窗口中将接收到的数据字节显示为字符串)。但是,我不了解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 { } 
} 

但是,如果我尝试了上面我的程序挂起。那么,我在这里错过了什么?

回答

2

它挂在你身上的原因是因为这是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

+0

谢谢。然而,当我这样做时,我得到这个异常 - 'SocketException:通常只允许使用每个套接字地址(协议/网络地址/端口)。 (System.Net.EndPoint local_end) System.Net.Sockets.UdpClient..ctor(Int32)System.Net.Sockets.UdpClient.InitSocket(System.Net.EndPoint localEP) System.Net.Sockets.UdpClient..ctor(Int32端口) UDPTest.LoadClient()(在资产/脚本/ UDPTest.cs:46) UDPTest.Start()(在资产/脚本/ UDPTest.cs:35)' –

+0

这个错误是由于我在解释第二段。如果您将脚本添加到多个游戏对象中,您将同时获得多个副本(因此,多个套接字尝试打开相同的地址)。 –

+0

实际上,即使我在独立的C#程序,而不仅仅是Unity。可能是因为服务器和侦听器在同一个IP地址上使用相同的端口? –