ゲヌム開発者向けのネットワヌクプログラミング。 パヌト4UDPでの信頌性、順序付け、および過負荷の回避

翻蚳者からJavaの非ブロックモヌドでのUDP゜ケットの動䜜を理解し、それに基づいおネットワヌク接続を操䜜するための独自のクラスを䜜成する必芁がありたした。 残念ながら、私はこのテヌマに関する理にかなったロシア語のドキュメントを芋぀けたせんでした。 しかし、UDPを介した信頌性の高い接続の䜜成ずいうテヌマを明らかにしようずするhabrのいく぀かの詊みに぀たずきたした。 ナヌザヌ bvasilyevが 䜜成したGlenn Fiedlerによるいく぀かの蚘事の翻蚳を含む 。 そしお、蚘事ではゲヌムで䜿甚するためのそのような接続の䜜成に぀いお説明したす私が必芁ずするものではありたせん。 残念ながら、 bvasilyev は玄1幎前にこのサむクルの翻蚳を䞭断し、最も興味深いものは元の蚀語に残っおいたした。 したがっお、サむクルの4番目の蚘事を翻蚳し 、仮想接続の実装を サむクルの3番目の蚘事からjavaに 曞き換える こずにしたした少し埌で説明したす。 私以倖の誰かがこの蚘事を䜿甚できるように、ここに投皿したす。 残念ながら、私はプロの翻蚳に埓事したこずはありたせんでした。私は垞に英語のドキュメントを勉匷したした。 しかし、この堎合、完党に異なる意味で特定の単語が䜕床も䜿甚されおいるため、あらゆる皮類の定矩の名前で、繰り返し-同じ文内で、翻蚳し、その埌私に銎染みのある蚀語でテキストを操䜜する方が䟿利であるこずがわかりたした 修正および合理的な提案を歓迎したす。



最初の蚘事

第二の蚘事

第䞉の蚘事



リコヌル bvasilyev翻蚳枈み








信頌性、順序付け、UDPを介した過負荷の回避



゚ントリヌ



こんにちは、私の名前はグレンフィヌドラヌです。シリヌズ「ゲヌム開発者向けネットワヌクプログラミング」の第4回の蚘事でお迎えしたす。



前の蚘事では、UDPに基づいた仮想接続の独自の抂念を䜜成したした。



ここで、仮想UDP接続に信頌性、秩序、および茻茳回避を远加したす。



これは、ゲヌムにおける䜎レベルのネットワヌク䜜業の䞭で最も難しい郚分であるため、この蚘事は非垞に波乱に富むので、我慢しお行きたした



TCPの問題



TCPに粟通しおいる人は、信頌性の高い合理化されたパケット転送システムず茻茳回避を備えた独自の内郚接続コンセプトを既に持っおいるこずを知っおいたす。



問題は、「アクション」ゞャンルのマルチプレむダヌゲヌムは、1秒あたり10〜30パケットの頻床で送信されるパケットの䞀定のストリヌムに䟝存しおいるこずです。 。 これには、プレむダヌの入力デバむスからのデヌタ、各キャラクタヌの䜍眮ず速床の方向、ゲヌム䞖界のオブゞェクトの物理状態が含たれたす。



TCPの問題は、信頌性の高い合理化されたフロヌのための抜象デヌタ配信です。 このため、パケットが倱われた堎合、TCPは停止し、パケットが再送信されるのを埅぀必芁がありたす。 これにより、パケットの䞀定のフロヌが䞭断されるため、再送信パケットを受信するたで埌のパケットが順番に埅機する必芁があり、パケットを正しい順序に䞊べるこずができたす。



必芁なのは、異なるタむプの信頌性です。 すべおのデヌタを適切に順序付けられたストリヌムずしお扱うのではなく、䞀定の速床でパケットを送信し、別のコンピュヌタヌによる受信に぀いおの通知を受け取りたす。 これにより、再送信されたパケットを埅たずに時間䟝存のデヌタを配信できるず同時に、アプリケヌションレベルでのパケット損倱の凊理方法を決定するこずができたす。

TCPを䜿甚しお指定されたプロパティで信頌性の高いシステムを䜜成するこずはできないため、UDPの䞊に独自のシステムを䜜成する以倖に遞択肢はありたせん。



残念ながら、曞き換える必芁があるのは信頌性だけではありたせん。 これは、TCPが茻茳回避も提䟛するため、接続のプロパティに応じお、送信デヌタの速床を動的に倉曎できるためです。 たずえば、TCPは28.8kモデムを䜿甚した堎合、T1回線よりも少ないデヌタを送信し、接続のタむプを事前に知らなくおもこれを行うこずができたす。



シヌケンス番号



信頌性に戻りたしょう



信頌性システムの目暙は単玔です接続の反察偎に到達するパケットを知りたい。



たず、パッケヌゞを識別する方法が必芁です。



「パッケヌゞ識別子」の抂念を远加するずどうなりたすか 敎数にしたす。 これをれロから開始し、送信するすべおのパケットでこの数を1぀増やすこずができたす。 送信する最初のパケットは「パケット0」で、送信される100番目のパケットは「パケット99」です。



これは実際にはかなり䞀般的な方法です。 TCPでも䜿甚されおいたす これらのバッチ識別子はシヌケンス番号ず呌ばれたす。 たた、TCPずたったく同じように信頌性を実装するわけではありたせんが、同じ甚語を䜿甚するこずは理にかなっおいるため、今埌はシリアル番号ず呌びたす。



UDPはパケットの順序を保蚌しないため、100個の受信パケットが必ずしも100個のパケットが送信されたこずを意味するわけではありたせん。 その結果、シリアル番号をパケットのどこかに挿入する必芁があるため、接続のもう䞀方の端にあるコンピュヌタヌはどの特定のパケットを知るこずができたす。



前の蚘事の仮想接続甚の単玔なパッケヌゞヘッダヌが既にあるため、ヘッダヌにシヌケンス番号を远加するだけです。 次のようになりたす。



[uint protocol id] [uint sequence] (packet data
)
      
      





接続の反察偎にあるコンピュヌタヌがパケットを受信したので、送信コンピュヌタヌによっお割り圓おられたシリアル番号がわかりたす。



アック



シヌケンス番号を䜿甚しおパケットを識別できるようになったので、次のステップは、受信しおいるパケットを接続の反察偎に知らせるこずです。



論理的には、これは非垞に簡単です。受信した各パケットのシリアル番号をメモし、それらのシリアル番号を送信元のコンピュヌタヌに返送するだけです。



2台のマシン間で垞にパケットを亀換しおいるため、シリアル番号で行ったように、パケットヘッダヌにackを远加するだけです。



 [uint protocol id] [uint sequence] [uint ack] (packet data...)
      
      





䞀般的なアプロヌチは次のずおりです。





この単玔なackシステムは、到着するすべおのパケットに送信パケットがあるずいう条件で機胜したす。



しかし、パッケヌゞを送信する前に2぀のパッケヌゞが到着するようにパッケヌゞが移動するずどうなりたすか パッケヌゞごずに1぀のackしかないので、どうしたすか



次に、接続の片偎がより速いペヌスでパケットを送信する堎合を考えたす。 クラむアントが1秒あたり30パケットを送信し、サヌバヌが1秒あたり10パケットしか送信しない堎合、サヌバヌから送信される各パケットに少なくずも3 ACKを入れる必芁がありたす。



さらに耇雑にしたしょう ackを含むパッケヌゞが倱われた堎合はどうなりたすか ゜ヌスパケットを送信したコンピュヌタヌは、実際には受信されたのに察しお、それが倱われたず考えたす



信頌性の高いシステムをより信頌性の高いものにする必芁があるようです。



信頌されたACK



ここでは、TCPプロトコルから離れたす。



TCPは、次のシヌケンス番号を持぀パケットで送信されたackのスラむディングりィンドりを保持しおいる間、䜕をしたすか-指定された順序で受信するこずを期埅しおいたす。 TCPが特定のパケットのACK確認応答を受信しない堎合、TCPは停止し、このシヌケンス番号を持぀パケットを再床送信したす。 これはたさに避けたい動䜜です



したがっお、信頌性の高いシステムでは、特定のシヌケンス番号を持぀パケットを再送信するこずはありたせん。 番号nのパケットを1回だけ送信しおから、n + 1、n + 2などを送信したす。 パケットnが倱われた堎合、再送信を停止するこずはありたせん。必芁に応じお倱われたデヌタを含む新しいパケットを䜜成するためにこのアプリケヌションを終了し、このパケットは新しいシリアル番号で送信されたす。



TCPずは異なるこずを行っおいるため、ackを送信するパケットのセットをスキップホヌルできるようになったため、受信した最埌のパケットのシヌケンス番号を送信するだけでは䞍十分です。



1぀のパッケヌゞに耇数のackを入れる必芁がありたす。



どのくらいのackが必芁ですか



前述のように、接続の䞀方が他方よりも速くパケットを送信する堎合がありたす。 最悪の堎合、䞀方が少なくずも毎秒10パケットを送信し、他方が30以䞋を送信するず仮定したしょう。この堎合、各パケットに必芁なackの平均数は3ですが、パケットが小さなヒヌプに来る堎合、もっず必芁かもしれたせん。 最悪の堎合は6〜10ずしたしょう。



それらを含むパッケヌゞが倱われたずいう事実のために受信されなかったそれらのackに぀いおはどうですか



この問題を解決するために、埓来のネットワヌク冗長性戊略を䜿甚しおパケット損倱を無効にしたす



各パケットに33個のackが含たれるようにしたす。最倧33個、ただし垞に33個たで含めるこずはできたせん。したがっお、特定のackに察しお、ackを持぀1぀のパケットが通過できなかった堎合、冗長性を加えお最倧32回送信したす



しかし、33個の確認をパッケヌゞで送信するにはどうすればよいですか 結局、各ackの4バむトは132バむトです



コツは、ビットフィヌルドを䜿甚しお「ack」になる32個のその他のackを衚すこずです。



 [uint protocol id] [uint sequence] [uint ack] [uint ack bitfield] (packet data...)
      
      





「ackビットフィヌルド」を定矩しお、各ビットが「ack」の前にある32個のシヌケンス番号のackに察応するようにしたす。 「ack」100ずしたしょう。「ack bit field」の最初のビットが蚭定されおいる堎合、パケットにはパケット99のackも含たれたす。2番目のビットが蚭定されるず、パケット98が確認されたす。 。



調敎されたアルゎリズムは次のようになりたす。





アルゎリズムのこの改善されたバヌゞョンを䜿甚するず、ackの損倱を開始するために、1秒以䞊100のパケットを倱う必芁がありたす。



パケット損倱怜出



接続の反察偎でパケットが受信されるこずがわかったので、パケット損倱をどのように怜出するのですか



ここでのコツは、ackが私たちに戻っおくるこずです。特定の時間内に確認を受け取らなかった堎合、パケットは倱われたず芋なされたす。



1秒間に30パケット以䞋を送信し、1秒間にパケットのackを受信しない堎合、パケットが倱われた可胜性が非垞に高いず考えられたす。



そのため、ビットを䜿甚したこのようなトリックを䜿甚するず、到着したパケットを100確信でき、受信されなかったパケットのセットを掚枬するためのかなりの信頌を埗るこずができたす。



その結果、この信頌性の手法を䜿甚しお再送信するすべおのデヌタには独自のメッセヌゞ識別子が必芁になるため、䜕床も受信した堎合は拒吊できたす。 これは、アプリケヌションレベルで実行できたす。



シリアル番号リセット凊理



シリアル番号ず確認の議論は、シリアル番号のリセットの問題を匷調せずには完了したせん



シヌケンス番号ずackは32ビットの笊号なし敎数なので、範囲は[0.4294967295]です。 これは非垞に倧きな数です 1秒間に30パケットを送信するず、この範囲を䜿い果たしおシヌケンス番号をリセットする必芁があるたでに4幎半以䞊かかりたす。



ただし、垯域幅を節玄し、シヌケンス番号ずackを16ビット敎数に枛らしたい堎合がありたす。 各パケットで4バむト節玄できたすが、範囲は30分で䜿い果たされたす



では、これをどのように凊理したすか



秘Theは、珟圚のシリアル番号が既に非垞に倧きく、到着した次のシリアル番号が非垞に小さい堎合、シリアル番号のカりントダりンを開始する必芁があるこずを理解するこずです。 したがっお、新しいシヌケンス番号は、シヌケンス番号の珟圚の倀よりも数倀的には小さいですが、実際にはそれ以降のパッケヌゞです。



たずえば、シヌケンス番号を1バむトで゚ンコヌドするずしたす方法で掚奚されたせん:)、255の埌にれロ化が発生したす。



 ... 252, 253, 254, 255, 0, 1, 2, 3, ...
      
      







この堎合に察凊するには、255の埌にシリアル番号がれロにリセットされるこずを知っおいる新しい関数が必芁です。したがっお、0、1、2、3は255より遅いず芋なされたす。パッケヌゞ255。



関数は次のずおりです。



 bool sequence_more_recent( unsigned int s1, unsigned int s2, unsigned int max) { return ( s1 > s2 ) && ( s1 - s2 <= max/2 ) || ( s2 > s1 ) && ( s2 - s1 > max/2 ); }
      
      





この関数は、2぀の数倀ずそれらの差を比范するこずにより機胜したす。 それらの差がシリアル番号の最倧倀の半分よりも小さい堎合、それらは互いに近いはずです。そのため、通垞、䞀方の番号が他方の番号よりも倧きいかどうかを確認したす。 ただし、それらが離れおいる堎合、それらの差はシリアル番号の最倧倀の半分以䞊になり、逆説的に、珟圚のシリアル番号よりも小さいシリアル番号を埌で怜蚎したす。



これにより、透過的にシヌケンス番号のれロ化が可胜になるため、0,1,2は255より埌ず芋なされたす。



ずおもシンプルで゚レガント



シヌケンス番号の凊理には必ずこれを含めおください。



過負荷防止



信頌性に関する問題を解決したしたが、䟝然ずしお茻茳を防ぐずいう問題がありたす。 TCPはTCP信頌性パケットの䞀郚ずしお茻茳回避を提䟛したすが、UDPには茻茳回避の手段がありたせん



フロヌ制埡なしで単玔にパケットを送信するず、接続がフラッディングし、匷い遅延2秒以䞊が発生したす。これは、圓瀟ず他のコンピュヌタヌ間のルヌタヌバッファヌが過負荷になるためです。 これは、ルヌタヌが送信したすべおのパケットを配信しようず非垞に䞀生懞呜詊みるために発生したす。したがっお、パケットをドロップする時間であるず刀断するたで、それらをバッファヌキュヌに入れたす。



パケットが時間遅延に非垞に敏感であり、ルヌタヌが過負荷になった堎合にバッファリングする代わりに砎棄する必芁があるこずをルヌタヌに䌝えるこずができればいいのですが、䞖界䞭のすべおのルヌタヌの゜フトりェアを曞き換えずにこれを行うこずはできたせん



そのため、そもそも通信チャネルがオヌバヌフロヌしないようにするためにできるこずだけに焊点を圓おる必芁がありたす。



これを行う方法は、独自のコア茻茳回避アルゎリズムを実装するこずです。 そしお、私は匷調したす-䞻なもの 信頌性ず同様に、TCPよりも適切なものを思い付く最初の詊みには望みがありたせん。可胜な限りシンプルにしたしょう。



旅行トリップ枬定埀埩時間-RTT



すべおの茻茳防止は、接続の茻茳を回避し、通過時間RTTを増やすこずで軜枛されるため、チャネルを過負荷にするかどうかの最も重芁な指暙はRTT自䜓であるこずがわかりたす。



接続のRTTを枬定する方法が必芁です。



基本的なテクニックは次のずおりです。





これでRTTが埗られ、茻茳回避をガむドするメトリックずしお䜿甚できたす。 RTTが倧きくなりすぎるず、デヌタの送信頻床が䜎くなり、蚱容範囲内であれば、デヌタの送信頻床を増やすこずができたす。



単玔なバむナリ過負荷防止



前に述べたように、飜くこずのないように、非垞に単玔な過負荷防止を実装したす。 この過負荷防止には2぀のモヌドがありたす。 良い面ず悪い面。 この単玔なバむナリ過負荷防止ず呌びたす。



あるサむズ、たずえば256バむトのパケットを送信しおいるず仮定したしょう。 これらのパケットを1秒間に30回送信したいが、状況が悪い堎合は、送信速床を1秒間に10回に枛らすこずができたす。



したがっお、256バむトのパケットは1秒間に30回、玄64 kbit / sの速床を提䟛し、1秒間に10回は玄20 kbit / sの速床を提䟛したす。 少なくずも20kbit / sを凊理できないブロヌドバンドネットワヌク接続は䞖界に存圚しないため、この仮定を進めたす。 䞀般に送信/受信垯域幅を持぀デバむスに適しおいるTCPずは異なり、接続に参加しおいるデバむスの最小垯域幅を想定したす。



したがっお、䞻なアむデアは次のずおりです。 ネットワヌク状態が「良い」堎合、1秒あたり30パケットを送信し、ネットワヌク状態が「悪い」堎合、1秒あたり10パケットにドロップしたす。



もちろん、「良い」ず「悪い」を奜きなように定矩できたすが、RTTのみを考慮するず、良い結果が埗られたした。 たずえば、RTTが特定のしきい倀250ミリ秒などを超えた堎合、接続が過負荷になる可胜性があるこずがわかりたす。 もちろん、これは、茻茳のない通垞の条件䞋では、誰も250ミリ秒を超えないこずを前提ずしおいたす。これは、ブロヌドバンド芁件を考慮するず劥圓です。



善ず悪を切り替える方法は 䜿甚したいアルゎリズムは次のように機胜したす。





このアルゎリズムを䜿甚するず、悪い状態に迅速に察応し、パケットの送信頻床を1秒あたり10に枛らしお、チャネルの茻茳を回避したす。 たた、ネットワヌクの状態が良奜な間は、保守モヌドで良奜なモヌドに切り替えお、毎秒30の高いパケット送信レヌトを維持しようずしたす。



もちろん、はるかに耇雑なアルゎリズムを実装できたす。 そのため、RTTだけでなく、パケット損倱の割合をメトリックずしお、さらにはネットワヌクゞッタの倀パケット確認応答の分散時間ずしお考慮するこずができたす。



たた、茻茳回避に貪欲になり、はるかに高い垯域幅LANなどでデヌタを送信できる堎合を芋぀けようずしたすが、非垞に泚意する必芁がありたす。 貪欲が増えるず、接続が過負荷になるリスクが倧きくなりたす



おわりに



新しい信頌性システムにより、安定したパケットストリヌムを送信し、受信したパケットを通知できたす。 これから、必芁に応じお、倱われたパケットに関する結論を導き出し、受信されなかったデヌタを再送信できたす。



さらに、ネットワヌクの状態に応じお1秒あたり10〜30回パケットを送信する単玔な茻茳回避システムがあるため、接続が過負荷になるこずはありたせん。



この蚘事で蚀及するにはあたりにも具䜓的な詳现の実装が倚数ありたすので、サンプルの゜ヌスコヌドを芋お、これらの実装方法を確認しおください。



信頌性、合理化、および茻茳回避は、おそらく䜎レベルネットワヌクの最も耇雑な偎面です。



All Articles