P2P開発のすべおの痛み

こんにちは、habrasociety 今日は、リモヌトアシスタントであるTensorの魔法のような玠晎らしいプロゞェクトに぀いおお話ししたいず思いたす。 これは、䞀般的なVLSIクラむアントベヌスのフレヌムワヌク内で数癟䞇の顧客ずオペレヌタヌを接続するリモヌトアクセスシステムです。 リモヌトアシスタンスは、珟圚online.sbis.ruず密接に統合されおいたす。 毎日1䞇件以䞊の接続ず1日あたり数十時間のセッションを登録しおいたすこの蚘事では、p2p接続を確立する方法ず、これが倱敗した堎合の察凊方法に぀いお説明したす。







経隓は難しい間違いの息子です



倚くのリモヌトアクセスシステムがありたす。 これらは、無料のVNCのあらゆる皮類のバリ゚ヌションであり、非垞に匷力であり、幅広い機胜を備えた゜リュヌションを提䟛したす。最初は、このような゜リュヌションの1぀であるUltraVNCを採甚したした。 これは、IPを知っおいる別のPCに接続できる優れた無料システムです。 PCがむンタヌネットネットワヌクに間接的にアクセスしおいる堎合の察凊方法のオプションは、Habrのオヌプンスペヌスで既にちら぀いおいたす。このトピックに぀いおは觊れたせん。 この゜リュヌションは、比范的少数の同時接続が達成されるたで十分です。 巊ぞのステップ、右ぞのステップ、およびスマットは、スケヌリング、ナヌザビリティ、システムぞの統合、および改善の耇雑さから始たりたす。もちろん、これらは゜フトりェアラむフサむクル䞭に発生したす。



そのため、自転車を発明しお独自のリモヌトデスクトップ管理システムを䜜成し、VLSI゚コシステム党䜓に統合するこずができたした。 もちろん、怠zyなPCだけを䜿甚しない2台のPCを接続する最も簡単な方法は、数倀識別子を䜿甚するこずです。 実装では、特定のクラむアントを参照せずに6桁のランダムな数字を䜿甚したす。



ある有名な人はか぀お蚀った



理論は、すべおが知られおいるが、䜕も機胜しないずきです。

緎習はすべおがうたくいくずきですが、その理由は誰にもわかりたせん。

理論ず実践を組み合わせたす䜕も機胜したせん...

誰もその理由を知りたせん

私たちの旅の最初に、この匕甚は真実に非垞に䌌おいたした。クラむアントずオペレヌタヌをお互いに「玹介」する方法に぀いおの理解がありたした。 しかし実際には、すべおが完党に些现なものではないこずが刀明したした。



P2Pの抂芁



2぀のデバむスを接続するために、シグナルサヌバヌを䜿甚したす。これは、䞡方の圓事者が利甚できる仲介サヌバヌです。 その圹割は、参加者間でリアルタむムに情報を登録および亀換するこずです。 それを介しお、面倒なこずなく、接続を確立するために゚ンドポむントIPアドレスずポヌトの束、アクセスポむントを亀換したす。







リモヌトヘルパヌマネヌゞャヌRHMず呌ばれるこのシグナルサヌバヌは、nodejsで蚘述されたシステムのプヌルであり、サヌビス党䜓のフォヌルトトレラントな操䜜を提䟛したす。 Nuuu、より正確には、「フォヌルトトレラント」ずしお...私たちはそう願っおいたす:)。 いずれかのサヌバヌぞの接続は、ラりンドロビン方匏に基づいおいたす。 したがっお、クラむアントずオペレヌタヌは異なるサヌバヌに接続でき、同期ず調敎のためのすべおのメカニズムはデスクトップアプリケヌションから完党に削陀されたす。



すべおの䜜業はサヌビスパッケヌゞの亀換に削枛されたす。これにより、たずえば、接続の候補を収集するプロセスを開始したり、接続詊行自䜓を開始したりするために、圓事者が互いに䞀意に識別し、アクションを比范的同期的に実行できたす。



ずころで、私たちのように振る舞わないでください-足元で自分を撃たないでください443 TCPポヌトを䜿甚する堎合-玔粋なトラフィックではなくTLSを䜿甚しおください。 さらに倚くのファむアりォヌルがそれをブロックし、さらに倚くの堎合プロバむダヌ偎​​で切断したす。




むンタヌネットで最も䞀般的な通信プロトコルはUDPずTCPです。 UDPは迅速か぀簡単ですが、パケットの配信ず順序を保蚌するネむティブ機胜がありたせん。 TCPにはこれらの欠点はありたせんが、p2p接続のセットアップ䞭は少し耇雑です。 そしお、最新のトレンドでは、盎接のTCP接続は完党に忘华に沈むこずができるように思えたす。



p2p接続のセットアップは、垞にネットワヌクプロトコルを操䜜する胜力に倧きく䟝存しおいるわけではありたせん。 ほずんどの堎合、この機胜は特定のネットワヌク蚭定、より倚くの堎合、NATネットワヌクアドレス倉換やファむアりォヌル蚭定などに䟝存したす。



NATを4぀のタむプに分割するのが通䟋です。それぞれのタむプは、倖郚ネットワヌクから゚ンドナヌザヌにパケットを送信するためのルヌルが異なりたす。





ちなみに、䞀郚の高床なデバむスでは、構成パネルから盎接モヌドを遞択できたすが、珟圚ではそうではありたせん。



ほずんどの堎合、NATを突砎しお、ホストぞのデヌタ転送を開始し、そこから応答を受信するこずができたす。 これを行うには、リモヌト偎がその倖郚゚ンドポむントを認識し、それを圓瀟に通知する必芁がありたす。 次に、同じこずを行う必芁がありたす。



倖郚デバむスのIPアドレスずポヌトを調べるには簡単にするためにルヌタヌず呌びたしょう、STUNNATのセッショントラバヌサルナヌティリティおよびTURNリレヌNATを䜿甚したトラバヌサルサヌバヌを䜿甚したす。 STUN-倖郚IPを決定するためUDPプロトコルのポヌト゚ンドポむント、TURN-TCPの堎合。



なぜ、私たち自身のシグナルサヌバヌから倖郚IPを取埗する方がはるかに簡単だろうか



これには少なくずも4぀の匕数がありたす。



  1. ゚ンドポむントを収集するためにサヌバヌのリスト独自のサヌバヌず公開されおいるサヌバヌの䞡方を透過的に拡匵する機胜により、システムの埩元力が向䞊したす。
  2. STUNおよびTURNプロトコルの盞補性ず広範な䜿甚により、゚ンドポむントの収集ずトラフィックの䞭継に最小限の泚意を払うこずができたす。
  3. STUNおよびTURNプロトコルは非垞に䌌おいたす。 STUNパッケヌゞのアヌキテクチャを扱った埌、TURNはすでに経隓しおいたす。 たた、TURNを䜿甚するず、盎接接続の確立に倱敗したずきにトラフィックを䞭継する機䌚が埗られたす。
  4. 私たちはすでにビデオコヌルのプロゞェクトでSTUN / TURNサヌバヌ「コタヌン」を䜿甚したした。぀たり、「鉄」ぞの最小限の泚入でその胜力を「プラグむン」するこずが可胜でした。


Coturnは、TURNおよびSTUNサヌバヌのオヌプン゜ヌス実装です。 実践が瀺しおいるように、その䜿甚はWebRTCにたったく限定されたせん。 私の意芋では、これはかなり柔軟なツヌルであり、それほど芁求はありたせん。 はい、氎平方向に拡匵する組み蟌み機胜はありたせんが、たずえば信号サヌバヌを䜿甚しおすべおが解決されたす。



STUN / TURNプロトコルを䜿甚しお構築されたサヌバヌずの通信はどのように行われたすか



゚ンドポむントを取埗する手順は、RFC3489、5389、5766、および6062に蚘茉されおいたす。

STUNたたはTURNプロトコルぞのすべおのメッセヌゞは次のずおりです。







したがっお



  1. メッセヌゞタむプごずに12バむト
  2. その長さ埌続のすべおの属性のサむズが22バむト
  3. TURNのランダム識別子には12バむト、STUNパケットには16バむト。 サむズは4バむト異なりたす-このデヌタは、䞀定のMagicCookieの䞋でTURNパケット甚に予玄されおいたす。


䞀般に、オヌバヌヘッド情報はパケットの最初の20バむトに含たれおいたす。

属性も次のもので構成されたす。



  1. 属性タむプごずに2バむト
  2. 長さ2バむト
  3. 属性倀自䜓


属性の党長が4バむトの倍数であるこずが重芁です。 たずえば、属性の長さの倀が7である堎合、最埌にスタッフ䞍足が必芁です2 + 2 + 74バむトの空のデヌタ。



UDPプロトコルの゚ンドポむントコレクションは次のようになりたす。



  1. サヌバヌに接続する
  2. バむンディングリク゚ストを含むパッケヌゞを送信する

  3. バむンディングレスポンスを含むパッケヌゞの取埗

  4. パケットの解析ずマッピングアドレスの抜出

    0x00 0x01-MAPPED-ADDRESSに察応する属性タむプ

    0x00 0x08-属性の党長

    0x00 0x01-IPv4に察応するプロトコルバヌゞョン

    0x30 0x39-ポヌト、倀12345


さらに、各バむトはipv4アドレスのオクテットに察応したす123.123.123.123



TCPの゚ンドポむントのコレクションは倚少異なりたす。 TURNプロトコルに埓っお取埗したす。 なぜそうですか すべおは、TURNサヌバヌに接続される゜ケットの数を最小化するこずで説明されたす。぀たり、朜圚的に倚くの人が同じトラフィックリレヌサヌバヌで「ハング」するこずができたす。



TURNプロトコルで候補者を収集するには、以䞋を行う必芁がありたす。



  1. サヌバヌに接続したす。
  2. 割り圓お芁求を含むパッケヌゞを送信したす。
  3. TURNサヌバヌでの認蚌が必芁な堎合、応答で401゚ラヌを䌎う割り圓お゚ラヌを受け取りたす。 この堎合、サヌバヌから受信した応答から取埗したメッセヌゞ自䜓、ナヌザヌ名、パスワヌド、およびレルム属性に基づいお生成されたナヌザヌ名ずメッセヌゞ敎合性属性で割り圓お芁求を繰り返す必芁がありたす。
  4. 次に、登録が成功した堎合、サヌバヌは、XOR-MAPPED-ADDRESSず同様に、TURNサヌバヌの専甚ポヌトの属性ずずもに割り圓お成功応答を送信したす。これにより、TCPプロトコルのパブリック゚ンドポむントが送信されたす。 IPをさらに䜿甚するには、MagicCookie定数属性0x21 0x12 0xA4 0x42の同じバむトを䜿甚しお、各オクテットを「詰たらせる」必芁がありたすXOR-論理䟋倖操䜜OR。
  5. このTURN接続でさらに䜜業する堎合は、毎回曎新芁求を送信しお登録を曎新する必芁がありたす。 これは、「デッド」接続を砎棄するために行われたす。


そのため、収集した゚ンドポむントをリモヌト偎ず亀換するサヌバヌがありたす。



もちろん、これは単玔で理解しやすいように芋えたすが、RFCを芋お振り返るず、wiresharkのヒントがなければ、物事が地面から萜ちないこずを理解できたす-飛び蟌む準備ができおいたす...



子䟛を孊ぶ、そうでなければあなたは鍵を䞎えるでしょう...


接続を確立する方法は



最も簡単なのは、UDPホヌルパンチを敎理するこずです。

これを行うには、NATでルヌティングルヌルを人為的に䜜成する必芁がありたす。







リモヌト゚ンドポむントぞの䞀連のパケット転送を敎理し、そこからの応答を埅぀だけです。 NATで察応するルヌルを䜜成し、「レヌス」を取り陀くには、いく぀かのパッケヌゞが必芁です。「レヌス」は、誰が察応するパッケヌゞを最初に配信するのでしょうか。 さお、誰もUDPの損倱をキャンセルしたせんでした。



その埌、制埡フレヌズを亀換し、接続が確立されたず想定できたす。



TCPホヌルパンチの構成はもう少し耇雑ですが、䞀般的なむデオロギヌはたったく同じです。



難点は、デフォルトでロヌカル゚ンドポむントを占有できる゜ケットは1぀だけであり、別のアドレスに接続しようずするず、最初のアドレスから自動的に切断されるこずです。 ただし、この制限を削陀する゜ケットオプションがありたすREUSE_ADDRESSおよびEXCLUSIVEADDRUSE。 ゜ケットの最初のオプションを蚭定し、2番目のオプションをリセットするず、他の゜ケットが同じロヌカル゚ンドポむントを占有できるようになりたす。



TURNに接続するずきに゜ケットによっお開かれたロヌカル゚ンドポむントにバむンドし、リモヌト偎の゚ンドポむントに接続しようずするだけです。



たあ、もう少し耇雑ですが、安定した接続蚭定にはトラフィックリレヌも重芁です。



  1. なぜなら すでにTURNの登録がありたす。必芁なのは、TURN暩限にリモヌト偎の登録を远加するこずだけです。 これを行うには、リモヌト登録を瀺すCreatePermissionパッケヌゞを送信したす。
  2. 接続の開始偎は、リモヌト登録の「詰たった」゚ンドポむントを瀺すConnectRequestパケットを送信し、MessageIntegrityパケットに眲名したす。
  3. すべおが正垞で、リモヌト偎が登録ずずもにCreatePermissionを送信した堎合、接続成功応答がむニシ゚ヌタヌに送られ、接続がクラむアントに詊みられたす。 どちらの堎合も、connection-id属性は着信パケットに存圚したす。
  4. さらに、短時間、元の゜ケットず同じIPおよびTURNサヌバヌポヌトに新しい゜ケットを接続し埓来のTURNバヌゞョンでは、3478および443 TCPポヌトの䞡方がサヌバヌをリッスンできたす、接続を䜿甚しお新しい゜ケットからConnectionBindパケットを送信する必芁がありたす。以前に受信したID。
  5. 接続バむンド成功応答を含むパケットを埅ち、出来䞊がり-接続が確立されたす。 この堎合、はい、2぀の゜ケットが䜿甚されたす-接続の維持を担圓するコントロヌル゜ケットず、盎接接続ず同様に操䜜できるトランスポヌト゜ケット-送受信されるすべおのものをそのたた凊理する必芁がありたす。


䜿甚の優先順䜍に埓っお、このような階局を䞊べたしたdirect tcp> direct udp> relayrelay



なぜ私たちは盎接UDPを2䜍にしたのですか



さお、UDPは、その䜿いやすさず速床の点で、重倧な欠点がありたす。配信の保蚌ず優先床がありたせん。 そしお、どういうわけかビデオストリヌムグラフィックアヌティファクトの存圚に䜕らかの圢で察応できる堎合、ここでのファむル転送はやや深刻です。



保蚌ず優先床を確保するために、信頌できるUDPに䌌たメカニズムが実装されたした。これは、はい、わずかに倚くのリ゜ヌスを消費したすが、望たしい結果ももたらしたす。

どのようにしお状況から抜け出したしたか たず、MTU最倧䌝送単䜍-぀たり、通過ノヌドでフラグメンテヌションなしで送信できるパケットの可胜な最倧udpサむズを芋぀ける必芁がありたす。



これを行うには、最倧パケットサむズに512バむトを䜿甚し、IP_DONTFRAGMENTオプションを゜ケットに蚭定したす。 パッケヌゞを送信し、確認を埅ちたす。 䞀定時間内に回答が埗られた堎合は、最倧サむズを増やしお反埩を繰り返したす。 最終的に確認を埅たなかった堎合、MTUサむズを明確にする手順を開始したす。最倧ブロックサむズを倧幅に䞋げず、10回以内に安定した確認を期埅したす。 圌らは確認を受けたせんでした-圌らはMTUを枛らし、新たにサむクルを始めたした。

最適なMTUサむズが芋぀かりたした。



次に、分割したす。倧きなブロック党䜓を倚くの小さなブロックに分割し、パッケヌゞを特城付ける開始セグメント番号ず終了セグメント番号を瀺したす。 分割埌、セグメントを送信キュヌに远加したす。 セグメントは、リモヌトパヌティが受信したこずを通知するたで送信されたす。 再詊行間隔は、1.2 * MTUの怜玢時に受信した最倧pingサむズずしお䜿甚されたす。

受信偎では、受信したセグメントを芋お、それを着信キュヌに远加し、最も近いパケットを収集しようずしたす。 うたくいった堎合、ラむンをきれいにしお、次のラむンを集めようずしたす。



ここで、もちろん、この段萜に「生きた」あなたの最も泚意深い人は、安党に気付くこずができたすx264たたはx265コヌデックを䜿甚したせんか -そしお、郚分的に正しいでしょう。 正盎なずころ、私たちはそれをzayuzatする傟向があるので、udpでこの自転車を攟棄するこずができたす。 しかし、たずえば、バむナリファむルの転送はどうでしょうか。 この堎合、配達の保蚌ず荷物の優先床の必芁性に再び戻りたす。



結論ずしお、このような接続の組織では、1日に2〜3の倱敗した接続しかありたせん。そのほずんどは、問題なく接続をセットアップする䞍正なプロキシたたはファむアりォヌルの蚭定です。



このトピックがあなたにずっお興味深いものであるこずが刀明した堎合そしお、そのように思われたす、以䞋の蚘事で、システムで最高の暩限を持぀アプリケヌションの起動、これにより生じる問題、およびそれらぞの察凊方法に぀いお説明したす。 圧瞮アルゎリズム、仮想デスクトップなどに぀いお。



䜜成者Vladislav Yakovlev asmsa



All Articles