2012-05-29 350 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地址上使用相同的端口? –