操作して学ぶ

状態遷移(FSM)可視化

いまの状態起きたイベントだけで次が決まる—— これが有限オートマトン(状態機械)です。イベントのボタンを押して、実際に状態を歩いてみてください。 本命はTCPの接続状態ssnetstat で見かけるCLOSE_WAITTIME_WAIT が、 どの経路で現れるのかが分かります。

ソケットが辿る状態。ss や netstat で見える CLOSE_WAIT / TIME_WAIT が、どの経路で現れるのかを追えます。左半分が接続確立、右半分が切断。

CLOSEDLISTENSYN_SENTSYN_RECEIVEDESTABLISHEDFIN_WAIT_1CLOSE_WAITFIN_WAIT_2CLOSINGLAST_ACKTIME_WAIT
現在の状態CLOSED

接続なし。すべての始まりであり終わり。

ここから起こせるイベント(2

たどった経路
CLOSED

TCPで実務的に効く3点

  • CLOSE_WAIT が溜まっていたら自分側のバグ。相手のFINを受けてACKを返した後、アプリが close() を呼ぶまでここから動きません。 大量に滞留するのは「接続を閉じ忘れている」証拠で、FD枯渇へ直行します。図で ESTABLISHED → CLOSE_WAIT と進めると、次のイベントが自分の close() しか無いことが見えます。
  • TIME_WAIT が大量にあるのは普通。先に閉じた側(能動クローズ)が最後に通る状態で、2MSL待ってから消えます。 遅れて届いた古いパケットが、同じポートで張り直した次の接続に混ざるのを防ぐ意図的な猶予。 異常ではないので、闇雲に短縮するのは危険です。
  • 「どちらが先に閉じたか」で通る道が違う。能動クローズは FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT、 受動クローズは CLOSE_WAIT → LAST_ACK。同じ「切断」でも状態列が非対称なのがTCPの肝です。

状態機械は通信プロトコルだけのものではありません。注文・予約・ジョブの進行、UIの画面遷移、パーサ——「取りうる状態」と「許される遷移」を先に決めると、if の山が消え、ありえない組み合わせを型や構造で排除できます。