2011-09-13 77 views
2

我正在製作一個遊戲,要求位置(2D)和許多其他數據的數據流量很大。 我用一個很簡單的類來幫助我監聽8080端口(UDP),和一個方法來發送數據報:高流量的C#UDP網絡

public static void SendToHostUDP(string Msg) 
{ 
    UdpClient udpClient = new UdpClient(); 
    udpClient.Connect(Main.HostIP, 8080); 
    byte[] sdBytes = Encoding.ASCII.GetBytes(Msg); 
    udpClient.BeginSend(sdBytes, sdBytes.Length, CallBack, udpClient); 
    Main.UDPout += sdBytes.Length/1000f; 
} 
public static void SendToClientUDP(string Msg, IPAddress ip) 
{ 
    UdpClient udpClient = new UdpClient(); 
    udpClient.Connect(ip, 8080); 
    byte[] sdBytes = Encoding.ASCII.GetBytes(Msg); 
    udpClient.BeginSend(sdBytes, sdBytes.Length, CallBack, udpClient); 
    Main.UDPout += sdBytes.Length/1000f; 
} 
public static void CallBack(IAsyncResult ar) 
{ 

} 

監聽器類只是一個很簡單的一個:

public class NetReciever 
{ 
    public TcpListener tcpListener; 
    public Thread listenThread; 
    private Action actionToPerformTCP; 
    private Action actionToPerformUDP; 
    public UdpClient udpClient; 
    public Thread UDPThread; 
    TimerAction UDPPacketsCounter; 
    int UDPPacketsCounts; 
    private BackgroundWorker bkgUDPListener; 
    string msg; 
    public NetReciever(IPAddress IP) 
    { 
     this.tcpListener = new TcpListener(IPAddress.Any, 25565); 
     this.udpClient = new UdpClient(8080); 
     this.UDPThread = new Thread(new ThreadStart(UDPListen)); 
     this.listenThread = new Thread(new ThreadStart(ListenForClients)); 
     this.listenThread.Start(); 
     UDPPacketsCounter = new TimerAction(CountUDPPackets, 1000, false); 
     this.UDPThread.Start(); 
    } 
    public void CountUDPPackets() 
    { 
     UDPPacketsCounts = 0; 
    } 
    public void Abort() 
    { 
     UDPThread.Abort(); 
     udpClient.Close(); 
     listenThread.Abort(); 
     tcpListener.Stop(); 
    } 
    public void UDPListen() 
    { 
     while (true) 
     { 
      IPEndPoint RemoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0); 
      byte[] receiveBytesUDP = udpClient.Receive(ref RemoteIPEndPoint); 
      if (receiveBytesUDP != null) 
      { 
       UDPPacketsCounts++; 
       Main.UDPin += receiveBytesUDP.Length/1000f; 
      } 
      if (Main.isHost) 
      { 
       Main.Server.processUDP(Encoding.ASCII.GetString(receiveBytesUDP), RemoteIPEndPoint.Address.ToString()); 
      } 
      else 
      { 
       if (RemoteIPEndPoint.Address.ToString() == Main.HostIP) 
       { 
        Program.game.ProcessUDP(Encoding.ASCII.GetString(receiveBytesUDP)); 
       } 
      } 
     } 
    } 

所以基本上當有一名玩家時,會有大約60包/ s的IN和60包/ s的輸出。

它就像這樣:

  1. 偵聽分組。
  2. 驗證數據包。
  3. 處理數據包的數據 - >像存儲一些位置的,發回一些數據包...

所以它只是循環這樣。

及存在的問題在這裏:

首先,當有2名球員(主機+ 1Client),會有一些顯著FPS下降在某些時候,主機會經歷所有音頻的口吃(如藍色屏幕)片刻。其次,當有2個以上的玩家(主持人+ 1 +客戶端)時,主機FPS將下降到5-20,並且會滯後+滯後+滯後+滯後但並不凍結。

我讀過一些關於異步的文章,而且這已經是線程化的了?

而且還BeginRecieveEndRecieve,我真的不明白如何以及爲什麼我需要使用它。

有人可以提供一些例子來解釋如何處理這些數據併發送/接收數據包嗎?我真的不想使用庫,因爲我想知道發生了什麼。

P.S:Terraria的網絡系統如何工作?它使用TCP,但它很流暢!怎麼樣?
PSS:什麼是緩衝?爲什麼我需要設置緩衝以及如何?它有什麼變化?
PSSS:我認爲在發送數據包時有一些需要調整和改變的地方,因爲它看起來很簡單。

+1

「贏得比賽的唯一方法是根本不玩。」您不應該用大量數據淹沒網絡 - 只能在實際更改值時發送數據。此外,速率限制和客戶預測被用來避免這個非常相同的問題。老實說,在谷歌上2分鐘就會告訴你 - 給你個例子。 –

+0

爲什麼你的回調是空的?至少你應該調用'udpClient.EndSend'來完成異步操作。這不是你昨天問過的基本相同的問題嗎? – spender

+0

什麼是'ListenForClients'?它不在你的代碼中。 – spender

回答

1

異步概念絕對是你想在這裏看到的東西。可能的問題是,對於在同一線程中運行的所有內容,某些UI操作(如圖形呈現(您的fps丟失)或播放聲音(您的口吃))可能正在等待程序的其他方面,例如網絡通信。

通常情況下,您會將線程分離出來,以便事物的UI和聲音邊可以獨立處理,而不依賴於其他任何東西。有一些MSDN線程的例子讀,然後嘗試把在一個單獨的線程的長時間運行過程中,從你的用戶界面,看看如何幫助:

http://msdn.microsoft.com/en-us/library/aa645740(v=vs.71).aspx

+0

非常感謝! 當我在使用iTunes或Skype時,聲音的口吃是全球性的,當我在遊戲關閉後大約1分鐘開始遊戲時,也會出現口吃,只有我的電腦出問題了? 謝謝! 所以基本上我在我的服務器類上啓動一個新的線程,那會更好嗎?還使用beginrecieve而不是接收? – Live0les

+0

但是,我可以遵循一些例子嗎?再次感謝! – Live0les

1

如果你真的想在那裏建立一個網絡遊戲到目前爲止,您將無法瞭解有關網絡編程的更多信息。

一個好的開始是http://gafferongames.com/networking-for-game-programmers/sending-and-receiving-packets/。雖然這是針對C++的(我認爲,但是如果我記得有人將它引入C#,也許:P),所有這一切背後的理論都得到了很好的解釋。

在WinAPI套接字編程中讀取它也可能是值得的。這將比閱讀關於如何在C#中進行網絡編程的教程更具技術性,但它也會比使用混淆真實場景背後的包裝器更清晰。

編輯:

基本上它取決於你的天氣,您使用化背景線程監聽包或使用BeginReceive有一個AsyncCallback方法。後者的缺點是您最終需要調用EndReceive,直到實際接收完成時,它仍會阻止您的應用程序。創建自己的線程並使用阻塞模式顯然不會阻塞您的UI /業務邏輯(主線程)線程,但您需要自己編寫跨線程通信部分。

我還發現了一個使用線程和阻止模式的UDP-Client-Server應用程序的簡單教程here

+0

我已閱讀文章,但我仍然無法找到我的問題,我是否使用線程來偵聽UDP數據包(阻止模式)或只是BeginRecieve?謝謝! – Live0les

+0

@Live:查看我原始帖子的編輯。 –

+0

非常感謝!我會閱讀鏈接=) – Live0les