TCP
番号付きのセグメントと確認応答で作る、信頼できるバイトストリーム。
SYN のヘッダ
すべての TCP 接続の最初のセグメントを、フィールドごとに見ます。フラグのバイトに注目してください。8 つのスイッチのうち 1 つだけが入っています。
フレーム全体
C8 22 00 50 00 00 03 E8 00 00 00 00 60 02 FA F0 D2 EB 00 00 02 04 05 B4: ポート 51234 からポート 80 へ、シーケンス 1000 から始めて、1460 バイトのセグメントを受け取れる、という接続の開始要求です。
| フィールド | 位置 | 例の値 | 意味 |
|---|---|---|---|
| 送信元ポート | 0–1 バイト目 | 0xC822 = 51234 | クライアントのエフェメラルポートです。両者の IP アドレスと宛先ポートとの組(4 つ組)で、この接続を一意に識別します。 |
| 宛先ポート | 2–3 バイト目 | 0x0050 = 80 (HTTP) | 接続先のサービスです。80 は HTTP(443 なら HTTPS、22 は SSH、25 は SMTP)。 |
| シーケンス番号 | 4–7 バイト目 | 1000 (ISN) | 送ったバイトには 1 つ 1 つ番号が付きます。SYN では「初期シーケンス番号(ISN)」を知らせます。SYN 自身も番号を 1 つ消費します。実際の OS は ISN をランダムに選びますが、ここでは読みやすさのため 1000 にしています。 |
| 確認応答番号 | 8–11 バイト目 | 0(未使用、ACK フラグは 0) | 「ここまで受け取った。次はこの番号のバイトを送って」という意味です。最初の SYN では意味がないので 0 で、ACK フラグも立てません。 |
| データオフセット | 12 バイト目の bits 7–4 | 6 ワード = 24 バイト | ヘッダ長(32 ビットワード単位)で、データがどこから始まるかを示します。6 × 4 = 24 バイト。基本ヘッダ 20 バイトにオプション 4 バイトが付いています。 |
| 予約 | 12 バイト目の bits 3–0 | 0 | 将来のための予約領域で、0 で送ります。 |
| フラグ | 13 バイト目 | 0x02 = SYN | セグメントの種類を示す 8 つの 1 ビットスイッチです。SYN セグメントは SYN だけが立っています。 |
| ウィンドウサイズ | 14–15 バイト目 | 0xFAF0 = 64240 | フロー制御です。あと何バイト受け取れるかを示します。送信側は、確認応答の来ていないバイトをこれ以上は送り出してはいけません。 |
| チェックサム | 16–17 バイト目 | 0xD2EB (✓) | 疑似ヘッダ(送信元・宛先 IP、プロトコル 6、TCP 長)、ヘッダ、データを対象にします。ここでは実際に計算した 0xD2EB です。IPv4 の UDP と違い、必須です。 |
| 緊急ポインタ | 18–19 バイト目 | 0 | URG が立っているときだけ意味を持ちます。実際にはほぼ使われません。 |
| オプション種別 | 20 バイト目 | 2 = MSS | オプションは「種別・長さ・値」の形です。種別 2 は Maximum Segment Size(最大セグメント長)。 |
| オプション長 | 21 バイト目 | 4 | オプション全体で 4 バイト(種別・長さ・値 2 バイト)です。 |
| MSS の値 | 22–23 バイト目 | 0x05B4 = 1460 | 「1 セグメントで受け取れる最大のペイロード」です。1460 = Ethernet の MTU 1500 から IP の 20 と TCP の 20 を引いた値です。 |
概要
IP はパケットを失い、重複させ、順序を入れ替えます。TCP はそれを隠します。すべてのバイトに番号を付け、受信側に届いたものを確認応答させ、届かなかったものを再送し、順序どおりに組み立て直します。アプリケーションからは、バイトを確実に運ぶ筒に見えます。
接続は 3 ウェイハンドシェイクで始まり、FIN で終わります。その間、ウィンドウサイズ(フロー制御)と輻輳ウィンドウ(輻輳制御)が、送信側の速度を決めます。
基本情報
- ヘッダ
- 20 バイト(最大 60)
- IP プロトコル番号
- 6
- 配送
- 信頼・順序保証
- 接続
- 3 ウェイで開き、4 ウェイで閉じる
- 識別
- (送信元 IP・ポート、宛先 IP・ポート)
- 規格
- RFC 9293
接続を開く
3 つのセグメントで接続を作り、そのあとデータとその確認応答が続きます。シーケンス番号を追ってください。
やり取りの全体
接続を開くのに 3 セグメント。そのあとはすべてのバイトに番号が付き、すべてのセグメントが確認応答されます。この帳簿づけが、信頼できないパケット網を、信頼できるバイトストリームに変えています。
11. SYN: 話しませんか?
クライアントが初期シーケンス番号(1000)を選び、接続を開きたいと伝えます。サーバはすでにポート 80 で待ち受けています。
22. SYN-ACK: はい、こちらの番号はこれです
サーバは 1001 を確認応答し(SYN が 1000 を消費したので次は 1001 を期待)、同時に自分の初期シーケンス番号 5000 を知らせます。1 つのセグメントで両方をこなします。
33. ACK: 接続成立
クライアントが 5001 を確認応答します。両側が相手の開始番号と、相手に声が届いていることを確認できました。接続は成立し、双方向にデータを流せます。
4最初のデータ: HTTP リクエスト
クライアントが 100 バイト(たとえば HTTP の GET)を送ります。シーケンス番号 1001〜1100 を占めます。PSH は、すぐアプリケーションに渡すよう求めています。
5ACK: 100 バイトとも受け取った
ack=1101 は「1100 までのすべてが届いた、次は 1101 から」の意味です。この ACK が来なければ、クライアントはタイムアウト後にデータを再送します。
接続を閉じる
4 つのセグメント。方向ごとに別々に閉じるためです。
やり取りの全体
FIN、ACK、FIN、ACK。方向ごとに別々に閉じます。TIME_WAIT はクライアントのポートをもうしばらく確保し、この接続の遅れて届く迷子パケットが次の接続を混乱させないようにします。
11. FIN: 送るものはもうありません
クライアントは送るデータがなくなったことを伝えます。FIN は番号を 1 つ消費します。受信はまだ続けられます。
22. ACK: 了解
サーバが FIN を確認応答します。クライアント側の半分は閉じましたが、サーバ側の半分はまだ開いていて、送り続けられます。
33. FIN: こちらも終わりです
サーバのアプリケーションがソケットを閉じると、サーバも自分の FIN を送ります。接続の終了は 2 つの独立した片方向の切断であり、そのため 4 セグメントかかります。
44. ACK: さようなら
クライアントがサーバの FIN を確認応答します。サーバはすぐに閉じ、クライアントは TIME_WAIT(約 60 秒、最大セグメント寿命の 2 倍)で待ちます。この ACK が失われてサーバが FIN を再送してきたときに備えるためです。
使われる場面
- HTTP/1.1・HTTP/2、HTTPS(TLS 付き)、SSH、SMTP、データベース
- バイトの欠落や順序の乱れが許されないものすべて
- リアルタイムのメディアには不向き。1 つのセグメントの損失が後続すべてを止めます(ヘッドオブラインブロッキング)
つまずきやすい点
- シーケンス番号はセグメントではなくバイトを数えます。SYN と FIN はデータを運ばなくても、それぞれ番号を 1 つ消費します。
- Wireshark は既定で相対シーケンス番号を表示します。実際の ISN はランダムな 32 ビットの値です。
- SYN に SYN-ACK が返らないのは、ファイアウォールによる破棄かホスト停止のサインです。RST が返れば、ポートが閉じています。
- 「遅い」接続の多くは、実際には再送タイムアウトを待っている、失われたセグメントです。
出典・規格
- RFC 9293: Transmission Control Protocol
- RFC 1071: Internet Checksum