2011-09-13 18 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) 
{ 

} 

リスナークラスは、ちょうど1つの非常に単純です:

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)); 
       } 
      } 
     } 
    } 

だから基本的に1人のプレイヤーがいるときは、約60パケット/秒と60パケット/秒があります。それは、このような役割を果たし

  1. は、パケットのために聞いてください。
  2. パケットを検証します。
  3. プロセスパケットデータ - > ...、ポジションの一部を保存するいくつかのパケットを送り返すよう

だから、このような単なるループ。

まず、2人のプレイヤー(ホスト+ 1Client)がある場合、いくつかの重要なFPSはいくつかの点で低下があるでしょう、そしてホストはブルーのようにすべてのオーディオの吃音を(経験します:

そして、問題はここにあります画面)を表示します。

第2に、2人以上のプレイヤー(ホスト+ 1 +クライアント)がいる場合、ホストFPSは5-20に低下し、ラグ+ラグ+ラグ+ラグではなくフリーズします。

私はasyncに関するいくつかの記事を読んでいますが、これは既にスレッド化されていますか?

また、BeginRecieveEndRecieveでも、どうやってそれを使用する必要があるのか​​よく分かりません。

これらの種類のデータを処理してパケットを送受信する方法を説明するためにいくつかの例がありますか?何が起こっているのか知りたいので、私は本当に図書館を使いたくない。

P.S:Terrariaのネットワークシステムはどのように機能しますか?それはTCPを使用しますが、それはスムーズです!どうやって?
PSS:バッファリングとは何ですか?なぜバッファリングを設定する必要がありますか?何が変わるのですか?
PSSS:パケットを送信する際に調整して変更するものがあると思います。

+1

"ゲームに勝つ唯一の方法は、まったく遊ばないことです。"大量のデータをネットワークに流すべきではありません。値が実際に変更されたときにのみデータを送信します。さらに、この非常に同じ問題を回避するために、レート制限とクライアント予測が使用されています。正直なところ、Googleで2分間はあなたに言いました - そして例を挙げましょう。 –

+0

コールバックが空白なのはなぜですか?少なくとも、udpClient.EndSendを呼び出して非同期操作を完了させる必要があります。これは基本的にあなたが昨日尋ねたのと同じ質問ですか? – spender

+0

'ListenForClients'とは何ですか?どこのコードにもない。 – spender

答えて

1

非同期的なコンセプトは、あなたがここで調べたいものです。何が問題になるかは、すべてのスレッドが同じスレッド上で実行されている場合、グラフィックレンダリング(fps損失)やサウンド再生(あなたの吃音)などの特定のUIアクションが、ネットワークのようなプログラムの他の面を待っている可能性がありますコミュニケーション

通常は、スレッドの出力を分離することで、UIとサウンドサイドが他のものに依存することなく、独自に処理できるようにします。MSDNのスレッドの例のいくつかの読み取りを持って、そしてあなたのUIから別々のスレッド上で、あなたの長い実行中のプロセスを入れて試してみて、それがどのように役立つかを参照してください。あなたが本当にそこに、ネットワークゲームを作成したい場合は

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

+0

ありがとう! 音声の吃音はグローバルです。iTunesやSkypeを使用していたときに、ゲームが終了して約1分後にゲームを開始したときに吃音が発生しました。 THanks! 基本的に、私はServerクラスで新しいスレッドを開始します。それが正しいでしょうか?また、recieveではなくbeginrecieveを使用しますか? – Live0les

+0

もう一度、私はそれに続くことができるいくつかの例がありますか?もう一度ありがとう! – Live0les

1

あなたがこれまでに知っていたよりも、ネットワークプログラミングについてもっと学ぶことはまったくありません。

良いスタートはhttp://gafferongames.com/networking-for-game-programmers/sending-and-receiving-packets/です。これはC++のためですが(私は思っていますが、誰かがそれをC#に移植したことを覚えていれば、おそらく:P)、この背後にある理論は非常にうまく説明されています。

また、WinAPIソケットプログラミングについて読む価値があるかもしれません。これは、C#でネットワークプログラミングを行う方法に関するチュートリアルを読むよりも技術的ですが、実際に何が起こっているのかを難読化するラッパーを使用するよりも明確になります。

編集:

基本的にはあなたにそのアップはあなたがパケットを受信するためにbackgroudのスレッドを使用するか、AsyncCallbackメソッドでBeginReceiveを使用して乗り切ります。後者の欠点は、最終的にEndReceiveを呼び出す必要があることです。実際の受信が終了するまでは、アプリケーションをブロックします。独自のスレッドを作成してブロッキングモードを使用すると、明らかにUI /ビジネスロジック(メイン)スレッドをブロックすることはありませんが、クロススレッド通信部分を自分でプログラムする必要があります。

また、スレッドとブロッキングモードhereを使用して、UDPクライアントサーバーアプリケーションの簡単なチュートリアルも見つかりました。

+0

私は記事を読んだが、私はまだ私の問題を見つけることができません、私はUDPパケット(ブロッキングモード)を聞くためのスレッドを使用するか、単にBeginRecieve?ありがとう! – Live0les

+0

@Live:オリジナルの投稿の編集をご覧ください。 –

+0

ありがとう!私はリンクを読むでしょう=) – Live0les