1

私は、C# と XNA を使用して、小さなオンライン マルチプレイヤー ポン ゲームに取り組んでいます。

ソケットを使用して、個人用 LAN 上の 2 台のコンピューター間でデータを転送しています。それは正常に動作します。

問題は速度にあります。転送が遅いです。

2 番目のコンピューターに ping を実行すると、2 ミリ秒の遅延が示されます。コード内に小さなタイマーを設定すると、約 200 ミリ秒のレイテンシーが表示されます。サーバーとクライアントが同じコンピューター (127.0.0.1 を使用) にある場合でも、遅延は約 15 ミリ秒です。これは遅いと思います。

ここに私のコードの一部があります:

server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Any, port));
server.Listen(1);
// Begin Accept
server.BeginAccept(new AsyncCallback(ClientAccepted), null);

ClientAccepted で、NetworkStream、StreamReader、および StreamWriter をセットアップしました。これは、プレーヤーの場所を更新したいときにメッセージを送信する方法です。

string message = "P" + "\n" + player.Position + "\n";
byte[] data = Encoding.ASCII.GetBytes(message);
ns.BeginWrite(data, 0, data.Length, new AsyncCallback(EndUpdate), null);

EndUpdate が行う唯一のことは、EndWrite を呼び出すことです。これは私がデータを受け取る方法です:

message = sr.ReadLine();

2 番目のスレッドにあるため、ゲームをブロックしません。

これらは私が試したものです: - TCPの代わりにIPを使用してください - テキストの代わりにバイナリメッセージを使用してください - IPv4の代わりにIPv6を使用してください 本当に何も役に立ちませんでした.

レイテンシーを改善する方法について何か考えはありますか?

ありがとうございました

4

4 に答える 4

9

表示されている遅延は、TCP を使用して多数の小さなパケットを送信する際の効率を向上させるために使用されるNagle のアルゴリズムが原因である可能性が最も高いです。基本的に、TCP スタックは小さなパケットを集めて、送信前に大きなパケットに結合します。これは明らかに、出力バッファーで待機しているものを送信する前に、さらにデータが送信されるかどうかを確認するために、最大 200 ミリ秒の短い間隔で遅延することを意味します。

そのため、ソケットでNoDelayプロパティを true に設定して、Nagle をオフにしてみてください。

ただし、ソケットに大量の小さな書き込みを行うと、TCP ヘッダーのオーバーヘッドと各パケットの処理のためにパフォーマンスが低下する可能性があることに注意してください。その場合、可能であれば、書き込みをまとめてバッチにまとめたいと思うでしょう。

于 2009-01-08T01:04:25.927 に答える
2

考慮すべき他のいくつかのメタ問題があります。

  1. タイマーの精度: 多くのシステム タイマーは、15 ミリ秒ごとにしか更新されません。正確な値は覚えていませんが、タイミングが常に約 15 ミリ秒の倍数である場合は、タイマーの精度が高くないのではないかと疑ってください。これは「おそらく」あなたの問題ではありませんが、覚えておいてください。

  2. 同じコンピューターでテストを行っていて、シングル コア マシンのみを実行している場合、スレッド/プロセスの切り替え頻度が ping 時間の大半を占めます。やることはあまりありませんが、Sleep(0) 呼び出しを追加して、データ送信後にスレッド/プロセスのスワップを許可してみてください。

  3. TCP/IP 送信設定。SocketOptionName.NoDelay で前述したように。また、前述のように、状態を継続的に更新する場合は UDP を検討してください。順序は保証されませんが、揮発性データの場合、パケットの欠落は受け入れられます。いずれにせよ、状態はすぐに上書きされるからです。古いパケットの使用を避けるには、増分値をパケットに追加し、現在の状態より前にラベル付けされたパケットを決して使用しないでください。tcp と udp の違いは 200 ミリ秒を考慮すべきではありませんが、他の要因の組み合わせにより可能です。

  4. ポーリングと選択。受信したデータをポーリングしている場合、ポーリングの頻度は当然受信速度に干渉します。専用のネットワーク スレッドで Socket.Select を使用して、着信データを待機し、できるだけ早く処理します。

于 2009-01-08T01:07:50.817 に答える
2

ほとんどのネットワーク ゲームは、通信に TCP ではなく UDP を使用します。その問題は、データが簡単に削除される可能性があることです。これは、考慮しなければならないことです。

TCP では、順序付けられた方法でデータを保証するために、ホスト/サーバー間に多数の相互作用があります (UDP を使用する場合、データが順序付けされていないという事実を考慮する必要があります)。

その上、コード内のタイマーは、バイトがアンマネージ ソケット レイヤーからアンマネージ コードなどを介してバブルアップするまで待機する必要があります。克服できないオーバーヘッドが発生します。 (アンマネージドからマネージドへの移行)。

于 2009-01-08T00:54:29.330 に答える
0

あなたは「IP」を試したと言いましたが、おそらくProtocolType.Ipを指定してそれを行いましたが、それを組み合わせると、それが実際に何を意味するのかわかりません(つまり、「内部」でどのプロトコルが選択されているのかわかりません) SocketType.Stream を使用します。

casperOne が言ったことと同様に、TCP を使用している場合は、SocketOptionName.NoDelay を設定することで違いが生じるかどうかを確認してください。

于 2009-01-08T00:59:43.267 に答える