TCP/IPへの疑問 その1
本記事では、これまで扱ってきたTCP/IPに関する「よくある疑問」をまとめ、各疑問ごとに本質的な解説と具体例を交えて解説します。
1. UDPは最近でも使われている?
結論:TCPに比べ信頼性は低いものの、リアルタイム性や軽量性が重視される用途では今なお広く活用されています。
1.1 利用例
- オンラインゲーム(FPSやMMORPG)
- 音声・映像通話(VoIP/WebRTC)
- ライブストリーミング(Twitch、SRT)
- IoTデバイス(CoAP)
- DNS、DHCP などの制御プロトコル
1.2 なぜ今もUDP?
- コネクション確立不要で高速
- パケット損失を許容し、即時性優先
- アプリケーション層で必要な信頼性を補完可能
2. UDPの信頼性が低い問題への現代的アプローチ
結論:アプリ/中間プロトコル層で再送・誤り訂正を追加し、必要な信頼性を担保します。
アプローチ | 説明 | 代表例 |
---|---|---|
アプリ再送・順序管理 | 自前でシーケンス番号やACK/NACKを実装 | 独自UDPプロトコル |
FEC(前方誤り訂正) | パケット再送せず誤り訂正で復元 | WebRTC |
QUIC | UDP上にTCP+TLSを実装、HTTP/3 | HTTP/3 |
SRT | 映像向け再送制御+ジッター処理 | ライブ配信 |
3. ICMPではping以外に何がある?
結論:ping(Echo Request/Reply)のほか、経路探索や到達不能通知など、多種多様なメッセージタイプがあり、ネットワークの制御や障害解析に使われます。
3.1 ICMPメッセージタイプ一覧
メッセージタイプ | 名前 | 内容・用途 |
---|---|---|
Type 0 / 8 | Echo Reply / Echo Request | pingコマンドで使用。ネットワークの疎通確認。 |
Type 3 | Destination Unreachable | 宛先やポートが到達不能な場合に送信。 |
Type 4 | Source Quench(廃止) | パケットの流量制御を目的に使用されたが、現在は非推奨。 |
Type 5 | Redirect | ルーターがより適切な経路をホストに通知。 |
Type 9 / 10 | Router Advertisement / Solicitation | 自動ルーター検出に使用(主にIPv4)。 |
Type 11 | Time Exceeded | TTLが0になった場合に送信。tracerouteで使用。 |
Type 12 | Parameter Problem | パケットヘッダに異常がある場合に通知。デバッグ用。 |
Type 13 / 14 | Timestamp Request / Reply | タイムスタンプ同期確認。 |
3.2 よく使うコマンド例
目的 | コマンド例 |
---|---|
ネットワーク疎通確認 (ping) | ping example.com |
経路探索 (traceroute) |
traceroute example.com (Unix系)、tracert example.com (Windows) |
到達不能通知確認 |
ping -c 1 192.0.2.1 で"Destination unreachable"を確認 |
ヘッダ異常検出 (Parameter) |
Wireshark で icmp.type==12 をフィルタ |
タイムスタンプ確認 (Timestamp) | hping3 --icmp ts |
4. TCP/IPでパケットの順番を意識するのはどこ?
結論:順序制御はトランスポート層のTCPが担い、IPやUDPは順序を意識しません。
4.1 TCPの順序制御メカニズム
- シーケンス番号
- ACK(確認応答)
- 再送制御
- 受信バッファでの並べ替え
4.2 なぜTCP?
Webコンテンツやファイル転送の正確性担保に不可欠
5. UDPで順番をどう管理するか
結論:シーケンス番号やタイムスタンプ、バッファリング、NACK/再送制御などをアプリ層で実装します。
# 送信側(シーケンス番号付与例)
seq = 0
while True:
data = f"{seq}:payload".encode()
sock.sendto(data, addr)
seq += 1
# 受信側(順序バッファリング例)
buf = {}
expected = 0
while True:
data, _ = sock.recvfrom(1024)
seq, payload = data.decode().split(':',1)
buf[int(seq)] = payload
while expected in buf:
process(buf[expected])
del buf[expected]
expected += 1
6. TCPはルートを保証しているから順番通り届く?
結論:TCPは経路を固定するわけではなく、IP層が選択する多様なルートを通ることがあります。そのため、受信側にパケットが必ず順番に届くとは限らず、TCP自身が受信バッファで並べ替えと再送制御を行って「順序を保証」します。
7. アプリケーション層のヘッダが壊れたらどこでエラーとなる?
結論:下位層は中身を解釈せず通過させるため、受信側アプリケーション層でパースエラーや独自チェックで検出します。
7.1 各層のチェック範囲
- データリンク層:CRCでフレーム全体の整合性
- ネットワーク層:IPヘッダのみ
- トランスポート層:TCP/UDPヘッダ+チェックサム
- アプリ層:独自フォーマット検証
8. 再送要求の仕組みは同じ?
結論:TCPはACK/タイムアウトで自動再送。UDPは仕様上なし。必要ならアプリ層でACK/NACKとタイマーを実装します。
特性 | TCP | UDP |
---|---|---|
再送制御 | 自動 | なし(アプリ実装可) |
利用例 | Web, FTP | ゲーム, VoIP |
9. バラバラの順番に届いたパケットの「終了判定」は?
質問:到着したパケットが順不同のとき、いつ「全部届いた」と判断するか?最後を示すフラグはあるのか?
9.1 TCPの場合
- 終了判定:TCPはコネクションの終了を示すFINフラグを持つ。相手がFINを送信すると“もう送るデータはない”と判断。
- FIN取得後、双方のACKが完了すればセッション終了。
- 補足:バイトストリームの長さは明示的には示されず、FINで終了を通知。順不同の整理はTCPの並べ替えバッファで処理。
9.2 UDPの場合
-
終了判定:UDP自体には終了フラグがない。
-
アプリ層で以下のように実装する必要がある:
- 固定数のパケット数を事前合意し、全seq到達で完了と判断
- 最後のパケットに専用フラグ(例:
is_last
ビット)を付加 - 長さ情報(総バイト長や総パケット数)を最初のパケットで伝える
# UDPで最後を示すフラグ例
packet = {
'seq': seq,
'is_last': seq == total_packets - 1,
'payload': data
}
10. アプリケーション層のヘッダ破損時のエラー検出
✅ 結論:
アプリケーション層のヘッダが壊れた場合、エラーは
👉 受信側のアプリケーション層で検出されるのが基本です。
理由:
下位層(トランスポート層やネットワーク層)は、アプリケーション層の「意味ある中身」には関与しないためです。
11. TCPとUDPの違いまとめ
TCPとUDPは、どちらもトランスポート層のプロトコルですが、目的や特徴が大きく異なります。用途に応じて正しく使い分けることが重要です。
観点 | TCP | UDP |
---|---|---|
通信方式 | コネクション型(接続の確立が必要) | コネクションレス(接続不要) |
信頼性 | 高い(順序保証、再送、誤り検出あり) | 低い(順序保証なし、再送なし) |
アプリが受け取る順序 | 保証される(送信順に並べ替えて渡す) | 保証されない(届いた順に渡す) |
再送制御 | 自動(ACKと再送機構あり) | なし(必要ならアプリで実装) |
オーバーヘッド | 大きい(ヘッダ20バイト以上、処理負荷高) | 小さい(ヘッダ8バイト、軽量) |
遅延 | 高め(信頼性確保のため) | 低い(即時送信) |
スループット安定性 | 高い(輻輳制御あり) | 低い(制御なし) |
利用例 | Web、メール、ファイル転送、APIなど | ゲーム、VoIP、動画配信、DNSなど |
補足:データ順序とは?
「データ順序」とは、受信側のアプリケーションがデータを受け取る順番を指します。
-
送る順序:送信アプリケーションがデータを送った順番(1→2→3)
-
届く順序:ネットワークの都合でバラバラに到着することがある(例:1→3→2)
-
受け取る順序:アプリケーションが受け取る順番
- TCP:並び替えてから渡す → 順序保証あり
- UDP:届いたまま渡す → 順序保証なし
補足:データ順サンプル
プロトコル | データ送信順 | 到着順 | アプリが受け取る順 |
---|---|---|---|
TCP | 1 → 2 → 3 | 1 → 3 → 2(など) | 1 → 2 → 3(並び替えて渡す) |
UDP | 1 → 2 → 3 | 1 → 3 → 2(など) | 1 → 3 → 2(届いた順に渡す) |
- 前のデータが届いていないために、後ろのデータまで処理が止まる現象が発生する
- これを「ヘッド・オブ・ライン・ブロッキング(HOL blocking)」と呼ぶ