👌

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」ではなく、通信の要件を理解した上で最適なプロトコルを選択、あるいは制御できるエンジニアを目指すことが、インフラとアプリの境界を越えた強みになると感じました。

Appendix.TCPコネクションからTCPヘッダを理解する

TCPコメクション確立時(3ウェイハンドシェイク)

TCPコネクションクション切断時(4ハンドシェイク)

4ハンドシェイクはまとめられるケースがある。

Discussion