TCP / UDP のヘッダ知識の再整理
背景・目的
元々アプリ側の人間だったのであまり、この辺り意識しておらず、TCP/UDPについてまじまじと学習してこなかった。。。
ただ、最近知人がAPIを実行するアプリケーションを実装する際、TCPの知識に絡むトラブルに遭遇しているのを目の当たりにし、ベースラインの知識が必要だと思い学習を開始。
備忘のために整理しようと思います。
TCP / UDP とは?
TCP(Transmission Control Protocol)とUDP(User Datagram Protocol)は、インターネットなどのIPネットワークにおいて、データ通信を制御する「トランスポート層」のプロトコル。
TCP / UDP はそれぞれ「信頼性・転送速度とリアルタイム性」といったそれぞれ異なる目的で利用されるプロトコルであり、どちらが優れているなどはなく、必要に応じて使い分けられるものである。
それぞれヘッダの特徴の概要:
- TCPヘッダ:
「信頼性と順序制御」を担保するために制御情報(20〜60バイト)を持つ - UDPヘッダ:
「転送速度とリアルタイム性」を優先するために必要最小限の情報(固定8バイト)のみを持つ
1. TCPヘッダ
TCPヘッダは信頼性の確保を優先し、通信相手とのコネクション確立(3ウェイハンドシェイク)や、欠落したパケットの再送制御を行うためのパケットの到達確認、順序の並べ替え、フロー制御を行うためのフィールドを備えている。
サイズはオプションの有無により変わる。(最小20バイト~最大60バイト)
ヘッダの構成要素
- 送信元ポート番号 (16bit):通信の返信先(送信もと)を識別。
- 宛先ポート番号 (16bit):通信先を識別。
- シーケンス番号 (32bit):送信データの順序を管理し、受信側での正しい並べ替えに使用。
- ACK番号 (32bit): 受信側が次に受け取りたいデータの開始位置を示し、データ到達の確認を行う確認応答番号。
- データオフセット (4bit): ヘッダの長さを示す(オプションが含まれる場合があるため)。
- コントロールフラグ (各1bit): 通信状態を制御する重要なフラグ群。
- SYN: 接続要求
- ACK: 確認応答
- FIN: 接続終了
- RST: 接続の強制切断
- PSH: データのプッシュ機能
- URG: 緊急データの存在
- ウィンドウサイズ (16bit): 受信可能なデータ量(バッファの空き容量)を通知し、フロー制御を行う。
- チェックサム (16bit): ヘッダとデータの整合性(エラーの有無)を検証する。
- 緊急ポインタ (16bit): URGフラグが立っている場合の緊急データの場所を示す。
- オプション (可変): MSS(最大セグメントサイズ)の通知などに使用される。
UDPヘッダ
UDPヘッダは、速度を優先し、再送制御や順序制御を行わないことでオーバーヘッドを極限まで減らし、DNSやVoIP(音声通話)、ストリーミングなどの遅延を嫌う通信に適応させるためデータを送りっぱなしにする ベストエフォート型 。
ヘッダサイズは常に8バイト固定の非常にシンプルな構造でTCPのようなパケットの到達確認、再送信は行わない。
ヘッダの構成要素
- 送信元ポート番号 (16bit): 返信が必要ない場合は省略(0)されることもある。
- 宛先ポート番号 (16bit): 通信先のアプリケーションを識別。
- UDPデータ長 (16bit): ヘッダを含むUDPパケット全体の長さを示す。
- チェックサム (16bit): データの整合性を検証(IPv4ではオプション扱いとなる場合もあるが、IPv6では必須)。
主要な違いの比較
| 項目 | TCPヘッダ | UDPヘッダ |
|---|---|---|
| 標準サイズ | 20バイト(オプションにより最大60バイト) | 8バイト(固定) |
| 主な機能 | 順序制御、再送制御、フロー制御 | ポート指定、エラー検知 |
| オーバーヘッド | 高い | 非常に低い |
| 信頼性 | 高い(確認応答あり) | 低い(確認応答なし) |
まとめ
TCPとUDPの最大の違いは、 「通信の確実性をプロトコルレベルで保証するか、それともアプリケーション側に委ねるか」 という設計思想の差。
なぜ使い分けが必要なのか
TCPは非常に多機能で信頼性が高い反面、3ウェイ・ハンドシェイクや再送制御などの「やり取り」が発生するため、オーバーヘッドが大きくなってしまう。
一方、UDPは「送りっぱなし」にする分、極限まで無駄が削ぎ落とされる。
TCPを選ぶべき時:
データの欠落が致命的なバグに直結する場合。
(API通信、データベース操作、ファイル転送)
UDPを選ぶべき時:
リアルタイム性がユーザー体験に直結し、数パケットの欠落よりも遅延の方が問題になる場合
(音声通話、ライブ配信、マルチプレイゲームの座標同期)
トラブルシューティングへの応用
アプリ開発においてネットワークトラブルに遭遇した際、ヘッダ情報の知識は強力な武器になる。
例)
- コネクションが確立しない:
TCPヘッダの「コントロールフラグ(SYN/ACK)」が正しくやり取りされているかを確認する。 - パフォーマンスが出ない:
TCPの「ウィンドウサイズ」によるフロー制御や、再送の多発を疑う。 - データが届かない:
UDPの場合、プロトコルは再送してくれないため、アプリ層でリトライ処理を実装する必要がある。
最後に
現代のアプリケーション開発において、下位レイヤーの仕組みを理解しておくことは、パフォーマンス最適化や障害発生時の「切り分け能力」に直結すると感じました。
特に、今回の学習のきっかけとなった知人の事象は、APIをジョブで大量に実行した際、Natのポート枯渇でした。APIを大量に実行するる必要があり、パフォーマンスの観点から、応答を待たずに次のAPIを実行した結果、利用し終わったポートがすぐに解放されずに枯渇していました。
コネクションプールにしたことで、事象も解消し、余計なコネクション確立通信がなくなりAPIのパフォーマンスが向上しました。
「とりあえずTCP」ではなく、通信の要件を理解した上で最適なプロトコルを選択、あるいは制御できるエンジニアを目指すことが、インフラとアプリの境界を越えた強みになると感じました。
Discussion