はじめに
とある業務でゲームクライアント向けRUDP通信を今風に再実装する機会が発生しそうで、
以前実装したのが10年以上前で、もう覚えてねぇよ!どんな実装が必要なんだっけ…
ということで、復習がてら書き起こしてみた記事です
基礎知識
よくあるOSIモデルネットワーク部分についての内容なので畳んであります、興味ある方は開いてください
TCP/IP通信の基礎
- OSI参照モデル
| OSI層 | 名称 | 例 |
|---|---|---|
| 7 | アプリケーション層 | HTTP, FTP, SMTP |
| 6 | プレゼンテーション層 | 暗号化, 文字コード変換 |
| 5 | セッション層 | 接続の開始・終了 |
| 4 | トランスポート層 | TCP, UDP |
| 3 | ネットワーク層 | IP, ICMP |
| 2 | データリンク層 | Ethernet, PPP |
| 1 | 物理層 | 電気信号, 無線 |
IPアドレスの役割
-
宛先がどこかを指定する(例: 192.168.1.10)
-
経路制御をする(ルーターなどの経由)
-
パケットの分割と再構築(MTU超えた場合)
-
セットでよく見かけるポート番号は上位プロトコル側での管理になっています
-
クライアント-サーバ通信の基本の流れ
UDPとTCPの違い
TCP、UDP はどちらもトランスポート層に位置します
- TCPの特徴
| 特徴 | 説明 |
|---|---|
| コネクション型 | 通信の前に接続確立(3ウェイハンドシェイク)を行い、接続を維持してデータを送受信 |
| 信頼性保証 | パケットの順序保証・再送制御・誤り検出を行う |
| 順序制御 | 送信したデータの順番を維持し、バラバラに届いても順番通りに並び替え |
| データの再送制御 | パケットの確認応答(ACK)を利用し、未着データは自動再送 |
| フロー制御 | 相手の受信バッファサイズを考慮し、ウィンドウサイズ制御で送信量を調整 |
| 輻輳制御 | ネットワークの混雑状況を検出し、通信速度を動的に調整 |
| 全二重通信 | 同時に双方向通信が可能 |
| ストリーム型 | データをバイトストリームとして連続的に扱う(データの区切りはアプリケーション任せ) |
| ヘッダが重い | 多機能なのでヘッダが20バイト以上と大きい |
- UDPの特徴
| 特徴 | 説明 |
|---|---|
| コネクションレス型 | 接続確立なし。いきなりデータを送るだけ。応答も必須じゃない |
| 信頼性保証なし | 順序保証、再送制御、到達確認一切なし。データが消えてもそのまま |
| 順序制御なし | パケットは届いた順に処理。順番が入れ替わっても気にしない |
| データ単位は「データグラム」 | パケットごとに独立した単位。TCPのような連続ストリームではない |
| ヘッダが軽い | 送信元ポート、宛先ポート、長さ、チェックサムのみ |
| フロー制御・輻輳制御なし | ネットワーク状況に合わせた調整はしない |
| 高速 | 制御が少ない分遅延が少なく高速 |
対比
| 項目 | TCP | UDP |
|---|---|---|
| 通信の形式 | コネクション型(接続確立が必要) | コネクションレス型(接続不要) |
| 信頼性 | あり(順序保証・再送制御・誤り検出) | なし(順序保証も再送も無し) |
| 代表用途 | Web, メール, SSH | DNS, VoIP, ゲーム, 動画配信 |
| ヘッダサイズ | 大きい(20バイト以上) | 小さい(8バイト) |
| 転送速度 | 遅め(信頼性のため制御多め) | 速い(信頼性なし) |
TCPの信頼性の要素
- ACK(確認応答)
- 再送制御
- シーケンス番号
- 順序制御
- フロー制御
- 輻輳制御
ネットワーク遅延
送信元から受信先に届くまでにかかる時間
| 種類 | 説明 |
|---|---|
| 伝播遅延 | 信号が物理的に線を通って伝わる時間 |
| 転送遅延 | パケット全体が送信バッファから出るのにかかる時間 |
| 処理遅延 | ルータやホストでパケット解析などの処理にかかる時間 |
| 待ち時間 | 処理順待ちしている時間 |
パケットロス
送信されたデータパケットが途中で失われてしまい、受信側に届かない現象
| 原因 | 説明 |
|---|---|
| 帯域の逼迫 | ネットワークが混雑してキューが溢れパケットが破棄される |
| 物理的な障害 | ケーブルや機器の故障による通信エラー |
| 無線環境の不安定さ | Wi-Fiやモバイル回線での電波干渉やノイズの影響 |
| ネットワーク機器の不具合 | ルータ・スイッチのバグや誤設定による喪失 |
RUDP って何?
- UDP通信に到達信頼性を持たせ、自分の欲しい機能を付与したもの
- ReliableのR
- プロトコル定義は特にないので独自実装
- 著名なQUICなんかもRUDPの範疇ではあるかと思います
- ゲーム環境であれば通信ミドルウエアに即使えるものが用意されてます
ということで、既にあるならそれ使えばいいじゃん、みたいな流れになりそうですが、
まあ中身がどうなってるのかぐらいは知っててもいいよね、ぐらいの温かい目で見ていただけると助かります
今どき独自でRUDPを実装する動機
- 自システムに都合の良い高速な通信
- 輻輳制御の仕様をカスタムしたい(BBRv2/v3使いたい等)
- ゲーム側仕様を取り込み都合よく処理したい
- ミドルウエア、プラットフォームに実装されたものは汎用性が高すぎる傾向
- 同一キャラ内でだけシーケンシャルな通信としたいのに、
システム全体でしか順序付き通信ができない(結局独自に実装する必要がある) - 輻輳制御がどのように実装されているか不明瞭なのが正直困る
- 同一キャラ内でだけシーケンシャルな通信としたいのに、
- プラットフォームに用意された RUDP は互換性に問題
- 例えばプラットフォーム提供の異なるミドルウエア間での機能の有無、細かな動作の違い
今どきの最新ミドルウエアでは解決してる(未調査)かもしれませんが、
個人的には輻輳制御がネックに感じています
RUDPのステータス
RUDPには再送制御があるため簡易ではありますがTCPのような「状態」を持ちます
シーケンシャルなID付きで送信を行い、IDのパケットが届きましたよ、とACKを送り返す、
ACKが送り返されなければ一定期間後に同じIDで再送信を行う
といった流れです
実際は、送信先から再送信要求を実装したり、輻輳制御をしたりともう少し複雑になります
簡易図
実装するべきもの
利用する通信形態
-
UDP(Unreliable)
- 通常の通信
-
ReliableUDP
- 到達確認付き通信、パケットが到着したらACKシグナルを送信します
必須
- シーケンシャルな番号を発行
- パケットの順序制御やACK管理に利用します
- uint16_tやuint32_tのユニークなIDとして扱うことが多いです
- ACK
- 受信したことを通知するパケット、パケットを受信したら識別IDを送信しパケット到着を知らせます
- 再送処理
- Reliableな通信でACKが届かない状況では一定期間後にパケットの再送信が行われます
- NACK到着による再送信要求もここで処理します
- パケットの一括送信
- バッチング処理とも言います、複数の送信を1度のパケット送信にまとめます
- Nagleアルゴリズムなんかもバッチング処理と認識してます
- (Nagleは大幅に送信遅延させてしまったりするので中身としては全然別物ですが…)
- UDP,ReliableUDPどちらも一度にバッチング可能な実装とする
必須ではないが、有益な実装
- NACK
- 再送信要求パケットの実装
- 例えば連続して届くはずのIDに飛び番号が発生したら、届いてないよ!と送信します
- 再送信要求パケットの実装
- 順序制御
- UDPパケットの到達順序の入れ替わりが発生しないようにIDを利用して到達順序を制御します
- 破損検出
- パケットの改ざん防止も考えるなら暗号化キー付きのハッシュ
- チェックサムで十分という考え方もある
- 暗号化
- 輻輳制御
- RTT計測
- 通信往復の時間計測を行います
- 輻輳制御などでも利用します
まとめ
記憶の彼方に埋もれてる情報を引っ張り出すのは結構大変でした、
リハビリには丁度いいのかもしれません
また、最低限必要な実装と、あったらイイね(事実上必須)みたいな項目を出してみましたが
実装難易度自体はそれぞれそこまで高くない上、
結局必要とされる機能が多いので、結局全部実装することになるんじゃないかなと思います
今回のケースでは輻輳制御まわりだけ新しくできれば、
従来のものとそこまで大差ない感じがしてきました…
ネットワーク関連は本当に基礎技術へ追加される形が多いから、
ライブラリなんかの作り直しのタイミングは悩ましいですね…
今回はテスト環境を整備したい、というのもあるので作り直しは確定なのですが
今どきだとミドルウエア提供の機能をそのまま使えばいい環境も多い気がするので、
実装までやってるケースは少ないのかもしれませんが、
なんかの程度の参考にでもなれば幸いです
続きで、輻輳制御関連の記事も書こうかと思っているので、
いつになるやらわかりませんが、公開されたら見てやっていただけると嬉しいです
内容は以前やってたロスベースの実装、BBRv3のカスタム実装あたり?になりそうです
また、書籍としては以下のものがよくまとまっていて良書の予感なので読もうと思います(現段階でまだ未読)
TCP/IP技術入門
——プロトコルスタックの基礎×実装[HTTP/3, QUIC, モバイル, Wi-Fi, IoT]
追記
QUIC関連を調べたけど、BBRサポートも結構進んでて
picoquic ならBBRv3もサポートされてそう
msquicもいつの間にかBBRサポートしてる
必要な機能は揃っているし、もう独自実装を続ける必要なんて殆ど無いなぁ