TCPをリアルタイムコマンドに使用する:Nagleアルゴリズムは大きな遅延を引き起こします。どうすればよいですか?
-
05-07-2019 - |
質問
ソケットサーバーとフラッシュゲームクライアントを作成しています。ゲームには、移動や回転などのリアルタイムコマンドが必要です。これらのコマンドは、サーバーからクライアントにできるだけ早く送信することが重要です。そうしないと、他のクライアントは移動/回転するクライアントと多くの非同期化を行うからです。
これは、Nagle算術が原因の問題の例です。
注:これらのコマンドの意味を理解したい場合は、以下のコマンド表を参照してください。
最初の船は私が移動した船です(前方に移動+右、前方は受信されましたが、右側は受信されませんでした)
コマンドを送信するクライアント:
84796: Sending data: 2#4
84796: Sending data: 2#2
84904: Sending data: 2#3
84904: Sending data: 2#0
86187: Sending data: 2#4
86188: Sending data: 2#2
86374: Sending data: 2#3
86404: Sending data: 2#0
コマンドを受信するクライアント:
79244: Raw receive: 3#3#4$
79244: New command: 3#3#4
79398: Raw receive: 3#3#2$3#3#3$3#3#0$
79399: New command: 3#3#2
79399: New command: 3#3#3
79399: New command: 3#3#0
80635: Raw receive: 3#3#4$
80635: New command: 3#3#4
80908: Raw receive: 3#3#2$3#3#3$3#3#0$
80908: New command: 3#3#2
80908: New command: 3#3#3
80908: New command: 3#3#0
"モーメント"私が言いたいことを意味しない奇妙な用語です、 しかし、ここでは、前のコマンドからミリ秒単位の時間の長さのようです
-
前に進む クライアントAが送信(瞬間:0)、クライアントBが受信(瞬間:0)
-
右折 クライアントAが送信(モーメント:0)、クライアントBが受信(モーメント:155)
-
移動を停止 クライアントAが送信(瞬間:108)、クライアントBが受信(瞬間:0)
-
回転を停止 クライアントAが送信(瞬間:0)、クライアントBが受信(瞬間:0)
-
前に進む クライアントAが送信(瞬間:1283)、クライアントBが受信(瞬間:1236)
-
右折 クライアントAが送信(瞬間:1)、クライアントBが受信(瞬間:273)
-
動きを止める クライアントAが送信(瞬間:186)、クライアントBが受信(瞬間:0)
-
回転を停止 クライアントAが送信(瞬間:30)、クライアントBが受信(瞬間:0)
これは、コマンドに対応するコマンドテーブルです。
クライアント->サーバー
2# (movement info)
0) now not turning
1) now turning left
2) now turning right
3) now not moving
4) now moving forward
サーバー->クライアント
3# (movement info)
[shipId]#
0) now not turning
1) now turning left
2) now turning right
3) now not moving
4) now moving forward
つまり、「Nagle」のためにコマンドが完全に設計解除されていることがわかります。これにより、移動の開始コマンドと同時に他のクライアントが移動の停止コマンドを受信し、そのプレイヤーがまったく移動しないようにします。
これが、これらのコマンドをリアルタイムで、TCPサーバーによって可能な限り高速で送信する必要がある理由です。簡単な修正方法は、単にNagleを無効にすることです。ただし、 googled を持っています(tcpに関する彼の提案に注意してください)メッセージパーシャルは私のシステムに実装されていますが、タイミングとは関係ありません)、Nagleを無効にすることは絶対にお勧めしないことに気付きました。
この原因でNagleアルゴリズムを無効にせず、代わりに他の解決策を探す必要があるのは本当ですか?なぜ(そうではない)?
事前に感謝します。 -トム
解決
TCP_NODELAYを使用して、そのソケットのnagleアルゴリズムをオフにします。最新のOSにはシステム全体で無効にする設定があり、それは IS を嫌っていますが、低レイテンシが必要なことがわかっているソケットでそれを行うべきではない理由はありません。
他のヒント
可能な限り高速にする必要がある場合は、UDPを使用する必要があります。
ただし、TCPは配信と順序を保証しますが、UDPは何も提供しません。
この点は、このアプリケーションでは非常に重要な点であるように思われるため、独自の確認/再試行コマンドの順序付けメカニズムを上に重ねる必要があります。
TCPを使用したい場合は、TCP__NODELAYが役立ちます。ゲームが進むにつれて、TCPがTCP_NODELAYなしで適しているデータストリームが必要になる場合があります。
RFC1006は、TCPストリームを介してパケットを送信するためのメカニズムを形式化します。
スイッチ、ルーター、ISPのswithcgear ....などもすべて、黒い小さな内臓を外に出すことに注意してください。汚れた小さな獣はパケットを読み取ることができるので、自由を取り、時々書き換えます。
より多くのネットワークで生き残るためのアプローチについては、RTP(UDP上で実行)をご覧ください。
船が全員の画面で同じことをするようにすることを目標とする場合、位置の更新を送信する必要があります。クライアントAが行ったという理由だけでそれを想定することはできません:
- 左折
- 待機時間100ミリ秒
- 回転を停止
クライアントBは、まったく同じ100ミリ秒の遅延を確認します。 Nagleバッファリングはこれをさらに極端にしますが、常にジッターとさまざまな遅延があります。
本当に次のようなものを送信する必要があります:
- (位置X1、Y1にZ1の見出しがあります)左折
- (位置X2、Y2にZ2の見出しがあります)回転を停止
クライアントが継続的に再同期するように。
Windowsは遅延ACK とNagleを実装していることに注意してください。これにより、個々のTCPメッセージでさらに200ミリ秒の遅延が発生する可能性があります。私の知る限り、Windowsでレジストリキー(および場合によってはレジストリキーを有効にするホットパッチ)を除いてこれを変更することはできません。