UDPを使用した確認応答の信頼性


16

UDPについて質問があります。コンテキストでは、リアルタイムアクションゲームに取り組んでいます。

私はUDPとTCPの違いについてかなり読みましたが、私はそれらをかなりよく理解していると感じていますが、正しいと感じたことのない作品が1つあります。それは信頼性、特に承認です。UDPはデフォルトでは信頼性を提供しないことを理解しています(つまり、パケットがドロップされたり、順番どおりに到着しないことがあります)。ある程度の信頼性が必要な場合、私が見た解決策(概念的には理にかなっています)は、確認応答を使用することです(つまり、サーバーはクライアントにパケットを送信し、クライアントがそのメッセージを受信すると、確認応答をサーバーに送り返します) 。

確認応答がドロップされるとどうなりますか?

上記の例(1つのサーバーが1つのクライアントにパケットを送信する)では、サーバーはパケットの確認応答が受信されるまでフレームごとにパケットを再送信することにより、潜在的なパケット損失を処理します。それでも帯域幅または順序が乱れたメッセージの問題に遭遇する可能性がありますが、純粋にパケット損失の観点から、サーバーはカバーされます。

ただし、クライアントが到着しない確認応答を送信すると、サーバーは最終的にそのメッセージの送信を停止せざるを得なくなり、そのパケットに含まれる情報が必要な場合、ゲームが中断する可能性があります。サーバーに対して同様のアプローチをとることができます(つまり、ACKに対するACKを受信するまで確認応答を送信し続けますか?)等々)。

ここで私の基本的なロジックは正しいと思うので、2つの選択肢があります。

  1. 単一の確認応答パケットを送信し、最善を期待します。
  2. 少数の確認応答パケット(おそらく3〜4)を送信し、すべてがドロップされるわけではないと仮定して、最善を期待します。

この問題に対する答えはありますか?基本的に何かを誤解していますか?知らないUDPを使用する保証はありますか?私は自分の論理が健全であると納得するまで、あまりにも多くのネットワークコードを使って前進することをheします。


11
おそらく、「タイムアウト」と「再試行」のアイデアを見逃しています。
Kromsterは、サポートモニカ

きっとそうかもしれません。あなたは私のロジックが正しいことを示唆しているので、ネガティブに聞こえないようにしていますが、ネットワークプログラミング中に、ネットワーク化された情報のほとんどすべてについて保証することはできません。リアルタイムゲームの過程では、大量の情報が失われる可能性がありますが、これは問題ありませんが、問題を確実に理解したいだけです。
グリメリオ

10
保証は一切ありません。正しい。アルゴリズムに「希望」を含めないでください。不運な組み合わせを処理する必要があります。PS信頼性の高い通信(ロックステップシミュレーション用)が必要なため、RTSでTCPに切り替えました。
Kromsterは、サポートモニカ

5
信頼性が必要な場合はTCPを使用し、重要でない場合はUDPを使用します。たとえば、プレーヤーの座標は、UDPを介してゲームで送信されます。補間とスムージングを使用して、欠落しているパケットを滑らかにします。魅力のように機能します。本当に信頼できる必要があるが、少し遅くなる可能性があるものは、TCP経由で送信されます。新しい状態が古い状態を無効にする状態がある場合は、UDPが適切な選択です。なぜなら、間にあるものがいつドロップされたかは問題ではないからです。プレーヤーの位置)。
ポリノーム

これはあなたの質問に対する直接的な答えではありませんが、リアルタイムゲームで絶対に必要な場合(最初の接続時など)にのみ承認を要求することを強くお勧めします。クライアントとサーバーの両方を設計し、可能な場合はステートレスシステムで新しいパケットを取得するまで「持っているものを使用する」ように設計する方がはるかに簡単です(堅牢です)。Quake 3は、スナップショットベースのシステムでこれを非常にうまく行いました。あなたが本当にそれを必要とするときもEnetモジュールのようなライブラリは、これらの例のために、確実にだけ、特定のパケットを送信することができます
JRH

回答:


32

これは、Two Generals Problemの形式であり、あなたの言うとおりです。再試行の数は、受信を完全に保証するのに十分ではありません。

実際のゲームでは、たとえ技術的に確実に到着したとしても、通常はそれを超える情報は重要ではない期間があります。見つけるのと同じように、2秒前に完璧なヘッドショットが並んでいました。プレーヤーがその情報を使用するには遅すぎます。

パケット損失が非常に大きいため、必要な情報をタイトなリアクションウィンドウ内で定期的に取得できない場合、リアルタイムゲームでは、プレーヤーを蹴って他の場所でより良いマッチを見つけようとするよりも、信頼性の高い接続をエミュレートするためにパケットを送信しようとし続けます。

このため、一部のゲーム複製システムは、確認と再試行を完全にスキップし、できるだけ頻繁に最新の更新をスパムすることを選択します。落としたり遅れたりした場合は、あまりにもひどいので、スキップして次のものを取り上げて、予測と補間システムに頼ってギャップを滑らかにし、プレーヤーに見えるしゃっくりを最小限に抑えます。

私は突然、過去の問題を無視し、現在の瞬間に生きようとすることから、この「シンバレプリケーション」と呼び始めたいと思います。;)

ラフィキは、その人生哲学についていくつかの反論的な不条理を定めた

ハイブリッドソリューションは、新しいアップデートの送信に先んじてレースをすることです(ゲームの状態のアップデートは多くの場合非常に小さく/ 圧縮可能であるため)、最後のアップデートもパックインします。おそらくクライアントがそれらを逃した場合に備えて、それを見つけて修正するために完全な往復時間を待つ必要はありません。ほとんどの場合、クライアントはこれをすでに見ているため、この方法で冗長データがありますが、見逃したメッセージを修正するための待ち時間は短くなります。クライアントの更新には、最新の連続更新のインデックス番号を含めることができるため、次の更新パケットに含める古い更新の数を最小限に抑えることができます。

また、2層システムを別のタイプのハイブリッドとして実装することもできます。この場合、短命の状態は信頼性の低いラピッドファイア方式でレプリケートされ、長期の状態はTCPまたは独自の信頼性の実装を使用して高いリトライで確実に同期されますカウント。ただし、2つのメッセージングシステムを維持する必要があり、2つのスナップショットが互いに同期しなくなり、まったく新しいクラスのエッジケースが追加されるため、管理がより複雑になります。


1
+1、よく書かれています。これは、アクション/リアルタイムゲームにより関連していることを強調したいと思います。TBSおよびRTSゲーム(および一部のアクションゲームのイベント)は、「情報が実際に重要ではない時間の地平線」について異なる見解を持っています。
Kromsterは、サポートモニカ

3
ええ、ターンベースのゲームでは、UDPの上に自分の信頼性レイヤーをロールしようとするのではなく、TCPを使用すると思います。;)厳密な時間範囲を持つゲームプレイのタイプとしてRTSのマイクロを分類しますが、そのハイブリッドアプローチがうまくいくかもしれません。リソース支出などの重大な見逃されたイベントを遡及的に処理するためのセーフティネット。
DMGregory

それは非常に役に立ち、私の最初の懸念を裏付けています。どうもありがとうございました。
グリメリオ

2
前方誤り訂正に言及することも有用かもしれません。次のパケットが受信されたときにパケットがドロップされたことを受信者が独自に把握できるようにプロトコルを設計し、必要な補間をスムーズにするために追加データを追加します。これは、UDPパケットがとにかくいっぱいになっていないことが多く、遅延を抑えるために、より小さなパケットをより頻繁に送信するだけなので、便利です。余分なバイトを追加してもレイテンシーは損なわれず、帯域幅はこれらのケースでは問題になりません。
–MSalters

@MSaltersあなたがそれをしているなら、それ自身の答えで詳しく説明する価値があると思います。賛成です。:)
DMGregory

9

TCPが使用するアプローチは、送信者が確認応答を受信するまでパケットを再送信し続けることです。受信者は重複パケットを無視しますが、それらの確認応答を送信します。送信者は、重複する確認応答を無視します。

パケットが失われると、送信者は既に知っているようにパケットを再送します。
確認応答が失われると、送信者は元のパケットを再送信し、受信者は確認応答を再送信します。

特定の時間内(おそらく60秒、または20回の再試行)に確認が受信されない場合、プレーヤーはゲームから切断されたと見なされます。何らかのタイムアウトルールを実装する必要あります。そうしないと、ネットワークケーブルを外したプレーヤーがサーバー上のリソースを永久に使い果たしてしまいます。


TCPの本質的な機能は、送信者が特定のパケットが確認されたかどうかを気にする必要はないが、ほとんどが「最高水準点」と最高水準点が移動せずにパケットがどれだけ長く残っているかを気にする必要があることです。
-supercat

1
@supercatそれは必須だとは言いません。最適化のようなものです。
user253751

括弧内のもの(既に取得したパケットにACKを送信する)については、括弧で囲むのではなく、実際に強調する必要があると思います。OPの理解(または少なくともその説明)に欠けているようです。
モニカを

@Angewが完了しました。
user253751

6

TCPを再発明する場合は、最初にTCP調べるのが理にかなっています。これは、説明する正確な問題を処理します(解決策の一部は、再試行とタイムアウトにユーザー定義の値を使用することです)。

TCPチャネル(信頼性の高い通信用)とUDP(低遅延通信用)チャネルの2つのチャネルを使用するソリューションは珍しくありません。

一部のソリューションは、クライアントが長すぎる情報を欠落していることを検出し、UDPまたはTCPを使用する再同期を開始します。

別の一般的なアプローチは、確認応答にまったく依存しないようにコミュニケーションを設計することですが、それは質問の範囲外です。


3

RTSでは、TCPのようなプロトコルを実際に使用することはできません。また、UDPの信頼性を高めることもできません。しようとすると、ネットワークが接続されるたびにゲームがフリーズします。

代わりに、失われたパケットがあまり問題にならないようにプロトコルを設計します。

ショートバージョンは、他のプレイヤーがどこにいるかを知っている限り、他のプレイヤーが最後のフレームにいたことを気にしないということです。長いバージョンはより複雑です。

質問は次のようになります。パケットが失われたらどうしますか?そして答えは...あなたが推測します。プレイヤーはおそらくまっすぐに動いているでしょう?それらをその線に沿ってさらに1ステップ移動します。...ないRTS選手を除き、これまで直線で移動します。そして、衝突検出があります。

これはきつい。多くのゲームが間違っています。これには正しい答えはなく、トレードオフできるのはさまざまな間違いだけだと主張することができます。

これらのゲームが非常にうまく機能する理由は、これらの問題について長く熱心に考えているだけでなく、インターネットがかなり信頼できるようになったからです。ほとんどすべてのUDPパケットは、実際にタイムリーに宛先に到達します。(ファイアウォールのような永続的な問題がない限り)


Warcraft 3はTCPを使用します。
fsp
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.