TCP 接続の終了
TCP は二つの送信方向を独立して閉じる。本課は通常の FIN、ACK、FIN、ACK の四段を示す。能動側は FIN_WAIT_1→FIN_WAIT_2→TIME_WAIT→CLOSED、受動側は CLOSE_WAIT→LAST_ACK→CLOSED と進む。
片方が送信終了を伝えても、他方は確認した後まだ送ることがある。自身も終えたら FIN を送り、能動側は最後に 2·MSL の TIME_WAIT を保持する。FIN の再送へ応答し、古いセグメントの期限切れも待つためだ。
仕組み
クライアントが能動的に送信を閉じ、FIN seq=u を送る。サーバーは ACK ack=u+1 を先に返し、自分の方向は続けられる。これが半閉鎖だ。その後 FIN seq=w, ack=u+1 を送り、クライアントが ack=w+1 で確認する。
FIN は SYN と同様、ペイロードなしでも一シーケンス番号を消費する。ACK は次を期待するので +1。本課は実際の 32 ビット番号の代わりに u、w を使う。
中間 ACK と二つ目の FIN は同時に準備できるとは限らず、ここでは四段になる。受動側もすぐ閉じられれば組み合わせられるので、毎回独立四パケットと決め付けない。受信を保つ半閉鎖には実 API で shutdown などを使い、close の資源挙動は環境に従う。
ステップ実行
Normal close は 13 ステップ。
- 両側 ESTABLISHED。クライアントのアプリが終了を開始する。
- 第 1 段
FIN seq=uを送り、FIN_WAIT_1 へ。 - サーバーは受けてクライアントの送信終了を知り、CLOSE_WAIT へ。
- 第 2 段
ACK ack=u+1を送る。 - クライアントは受け、FIN_WAIT_2 へ。自分の送信方向が確認済みで閉じる。
- 半閉鎖の窓。サーバーはまだデータを持ち得て、送信済み ACK と未送信 FIN を分ける。
- サーバーは送信を終え、第 3 段
FIN seq=w, ack=u+1を送り LAST_ACK へ。 - クライアントは FIN を受け、TIME_WAIT へ。
- 第 4 段
ACK ack=w+1を送る。 - サーバーは受けて CLOSED。この例はサーバーが先に終わる。
- クライアントは 2·MSL 待ち、再送 FIN の確認と古い重複段の期限切れに備える。
- 期限で CLOSED へ。
- 両階段が CLOSED となり、通常終了を終える。
移動カードと状態ラベルを生命線に示し、古いラベルを薄くする。転送と TIME_WAIT は遅く見せ、番号と状態を照合できる。
TIME_WAIT の役割
純 ACK はそれ自体を ACK されず、最後の確認も同じだ。クライアントは到着を確定できない。
Lost final ACK は ack=w+1 を落とす。サーバーは LAST_ACK に残り、再送期限で FIN seq=w を出す。TIME_WAIT のクライアントは ACK ack=w+1 を再送し、2·MSL を再開始する。今度はサーバーが閉じ、クライアントも新期限後に閉じる。
最後の ACK 直後に状態を捨てれば、再送 FIN が接続のない場所へ届き、正常な再確認でなく RST になる可能性がある。2·MSL は同じ接続識別を再利用する前に旧段を消す役割もあるが、任意の遅延・喪失への絶対保証ではない。全状態と時間規則は RFC 9293を参照。
境界ケース
- 最後の ACK 喪失では LAST_ACK が FIN を再送し、TIME_WAIT が再確認して時計を再始動する。
- 同時終了は双方が相手を見る前に FIN を送り、FIN_WAIT_1→CLOSING→TIME_WAIT で両方待ち得る。ここでは未展開。
- 相手が FIN を出さなければ FIN_WAIT_2 に残り得る。アプリがもう持たない接続などに掃除期限を設ける実装もあり、全半閉鎖に同じ期限を仮定しない。
- RST による中止はこの正常 FIN 経路とは異なり、未配達データを捨て得る。
よくある間違い
- 三段で済むと決め付け、受動側の残る送信を無視する。逆に ACK と FIN が絶対結合できないとも言えない。
- 両側が同時に CLOSED と思う。既定はサーバーが先、クライアントは TIME_WAIT。
- 待機を無駄とする。最終確認の再送と旧段分離を支え、大量に能動終了するサーバー側にもたまる。
- TIME_WAIT をクライアント固定、または必ず片側だけとする。通常例は能動側、同時終了なら両端だ。
- FIN の番号消費を忘れる。確認は u+1 と w+1。
モデルの範囲
記号番号を使い、データ転送を挟まず、再送と待機を短い説明動作にする。通常の能動・受動終了と最終 ACK の一回喪失だけで、全状態組、資源回収、スタック最適化を再現しない。