TCP の考えを UDP に当てはめるべきではない理由


- [ ] TCP の考えを UDP に当てはめるべきではない理由
# なぜ TCP の考えを UDP に当てはめるべきではないのか?

## 構造の違い

![TCP ヘッダー](https://s2.loli.net/2023/06/30/ndPGpzMRX1L4Q6D.png)  
![UDP ヘッダー](https://s2.loli.net/2023/06/30/ofdBYKb6iqaICA9.png)

TCP には多くの概念があります: 接続の確立, リソース使用, データ転送, 信頼性の高い転送, 累積確認に基づく再送, タイムアウト再送, チェックサム, フロー制御, 混雑制御, 最大セグメントサイズ, 選択的確認, TCP ウィンドウスケーリングオプション, TCP タイムスタンプ, 強制データ配信, 接続の終了.

これらの機能のほとんどは UDP にはありません. UDP はリンク層に比べてアプリケーション層の宛先を区別する能力がわずかに追加されているだけです. UDP は十分にシンプルであるため, 十分に柔軟です.

## 起こり得ることがあれば, 必ず起こる

マーフィーの法則:

> 何かを行う方法が複数存在し, そのうちの一つが災難を引き起こす場合, 必ず誰かがその方法を選ぶ.

通常, UDP はゲーム/音声/動画などのシナリオに適していると紹介されます. 少量のエラーパケットは業務に影響しません.
なぜ UDP がこれらのシナリオに適しているのでしょうか? UDP がこれらのシナリオで使用できることは, それがこれらのシナリオの最適なソリューションであることを意味しません. 必然的に TCP では解決できない問題があるため, これらのサービスが機能的に簡素な UDP プロトコルを選択したのです. エラーパケットが業務に影響しないというのは, TCP プロトコルがエラーパケットを気にするのに対し, UDP は気にしないということです. よりリアルタイム性/連続性を重視しているのです. UDP の特徴は, TCP が気にする要素を気にしないことであり, これらの要素がリアルタイム性に影響を与えます.

コードの実装上, UDP はソケットを作成し, ポートにバインドするだけで, すぐに送受信を開始できます. 通常, ソケットを使用すると, ポートも同時に使用されます.

したがって, 私は次のように UDP を使用できます:

1. 任意の IP の任意のポートにランダムなパケットを送信し, どのポートが応答するかを確認する
1. 甲が A ポートから乙の B ポートに要求パケットを送信する. 乙が C ポートから甲の D ポートに応答パケットを送信する
1. 甲が A ポートから乙の B ポートに要求パケットを送信する. 乙が丙に委託して C ポートから甲の D ポートに応答パケットを送信する
1. 甲が A ポートから乙の B ポートに要求パケットを送信するが, 送信元 IP を丙の IP に変更する. 乙は応答パケットを丙に送信する
1. 両者がそれぞれ 10 個の UDP ポートを使用して, 同時に受信と送信を行う

これらの方法は TCP では自然に通用しませんが, UDP プロトコルでは可能であれば, 必ず誰かがそうします. したがって, TCP の考えを UDP に当てはめることは理想主義であり, 実際の状況は私たちが列挙しきれるものではありません.

UDP のパケットは非常にシンプルで, 使用も非常に柔軟です. 元々接続の概念はありませんので, UDP 接続を自分で定義する必要があります. いくつかの定義方法を試してみましたが, 接続方向の判断意図を完全に正確に達成することはできませんでした. このとき, ある程度の容赦を受入れる必要があります. 元々 UDP 接続の定義がなかったので, 各者が UDP 接続の定義が一致しないときに, 必然的に予期しない行動が生じます.

## クライアントの視点から見た UDP

音声/動画などの業務では, よくパケットロスが発生しますが, パケットロスの方法が異なると業務への影響も異なります. 例えば, 30%のパケットロスが均等に発生するのと, ある特定の時間帯に全てロスするのでは, 体験への影響に明らかな違いがあります. 明らかに, 私たちはより均等なパケットロスを期待しています. しかし, UDP にはフロー制御の防止方法がありませんので, パケットロスの方法にはいくつかの方法があります. UDP 通信はしばしば"ベストエフォート"と表現されますが, 異なる"ベストエフォート"の方法は異なる効果をもたらします.

## サービスプロバイダーの視点から見た UDP

TCP 攻撃の場合, クライアントは接続の作成や維持に一定のオーバーヘッドがかかります. つまり, 攻撃者は一定の代償を払う必要があります. しかし, UDP 攻撃では, 攻撃者が払う代償ははるかに小さくなります. 攻撃者が消費したいのがサービス側の帯域幅流量であれば, UDP は非常に良い方法です. 例えば, サービスが 100GB の無制限速度の流量を購入し, 処理能力は 10MB/秒しかなく, 受信速度は 1GB/秒あるとします. すると, 90%の要求流量が無効ですが, これらの流量は無料ではありません. サービス側はこのような状況を回避すべきです.

## キャリアの視点から見た UDP

通信を完了するには複数の端末と通信チャネルが必要で, 常に注目されるのはサーバとクライアントですが, キャリアの視点も同様に重要です. DDoS 攻撃では, サーバ側のリソース消費状況を気にしますが, 実際にはキャリアのリソースも限られています. サーバが単純に要求に応答しないだけで, 受信流量はすでに帯域幅を消費していますが, このリソースは通常キャリアに属しています. 私たちは圧力テストでよく"パケットロス率"という指標を使用しますが, この指標は完全な通信チェーンでのパケットロスを表しており, サーバ側のパケットロスだけではありません. キャリアもパケットロスします. キャリアの視点では, サービス側は 1MB/s の帯域幅しか購入していないが, クライアントは 1GB/s の速度で送信している場合, 両者は無駄な流量に対して課金されず, キャリアがこの帯域幅の代償を負担しています. そのため, キャリアは必然的にこのような流量を遮断しようとします. つまり, UDP の QoS です. TCP には混雑制御がありますが, UDP では, キャリアはパケットロスによって流量を制御できます. 実際の状況では, キャリアはよりシンプルで乱暴な方法を使い, 長時間使用されるポートの流量を直接遮断します. つまり, UDP のポート遮断です. WeChat 通話の実際のテストでは, 各通話でクライアントは複数のポートを使用し, そのうち 1 つの UDP ポートが同じサーバの 6 つの UDP ポートと通信していることがわかりました. これはキャリアのポート遮断に対応するためのものだと推測されます.

## まとめ

UDP の柔軟性は, 目標を実現する際に, 複数の実装方法があり, すべて合法であることを意味します. 最終的に安定した通信を実現できれば, TCP とは大きく異なる実装であっても, "存在するものは合理的である" です. したがって, 私たちは TCP の概念を完全に UDP に当てはめることはできません. 製品設計のために新しい UDP 接続定義を作成したとしても, エラーを予期し, 許容できるべきです. 結局のところ, "エラーを許容する" ことが UDP の核心機能であり, これは UDP の利点であり, 欠点ではありません. サービスが主体的に選択したプロトコルの核心能力であり, 不得已に受け入れた欠点ではありません.

## 更なる読書

- [2 万字で QoS の原理を学びましょう](https://cloud.tencent.com/developer/article/1708535)
- [Transmission Control Protocol](https://zh.wikipedia.org/wiki/%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE)
- [User Datagram Protocol](https://zh.wikipedia.org/wiki/%E7%94%A8%E6%88%B7%E6%95%B0%E6%8D%AE%E6%8A%A5%E5%8D%8F%E8%AE%AE)