【図解】TCPコネクションのシーケンスと状態確認〜3way handshake, FIN/RST, netstat〜

TCPのコネクションは、3wayハンドシェイクにより始まります

3wayハンドシェイク時には、TCPのペイロードにはデータは一切入りません。この3wayハンドシェイクが終わってから、TCPのペイロードに上位レイヤの情報(例えばhttp)のデータやり取りが開始されます。

TCPコネクションを開始する(SYNを最初に送信する)ホストをクライアント、TCPコネクションを受ける(SYNを最初に受信する)ホストをサーバと言います。

以下に、TCPコネクションのサンプルを示します。

TCPのデータ送信

TCPはデータを信頼性は、シーケンス番号と応答確認番号で実装されます。

データが欠けている場合、再送をしますが、再送タイマのタイムアウト時間(RTO: Retransmission TimeOut)はRTT値を元に計算されます。

RTT値は、データを送ってからackが戻ってくるまでの時間のことで、Windowサイズ毎に1パケットだけサンプリングされます。

さらにこのRTT値はSmooth RTT(SRTT)値の計算に用いられます。SRTT値の計算式は以下の通りです。

SRTT(new) = α * SRTT(old) + (1-α) * RTT

αは0.9が推奨されています。

また、RTOは以下の式が利用されています。

RTO = SRTT + 4 * (平均偏差)

TCPコネクションの終了

TCP のコネクションは、ハーフクローズという方法で終了されます。つまり、片方ずつコネクションを切断します。

コネクションを切断したいほうは、FIN bit をセットして TCP セグメントを相手に贈ります。 最初に FIN を出す側を Active Close といいます。

一方、FIN を受け取った側は ACK bit とともに FIN bit をセットして TCP セグメントを送信します。 後に FIN を出す側を Passive Close といいます。

Active Close はどちらから行なっても良いことになっています。(アプリケーションでのソケットAPIの使い方次第です)。

なお、『FIN を受け取った側はまず ACK bit をセットした TCP セグメントを送り、一定待ち時間を待った後にFIN bitをセットした TCP セグメントを送る』という実装もありますが、上記のように ACK と FIN を一緒にしてしまう実装もあります。このあたりはアプリケーションでどのように実装しているかに依存します。

TCP Reset によるコネクション強制終了

TCP RST を使うと一方的にコネクション終了を通知することができます。通信の途中、アプリケーションで不具合が発生した場合など、直ちに TCP RST を行い、通信を終了させます。

TCP RST がもしパケットロスした場合、相手には届きませんが、その場合は相手が TCP Open の前提で送信してきますが、そのたびに TCP RST を何度も送り続けることになります。

TCP RST の例は、次のパケットキャプチャで例を示します。

3way handshake をパケットキャプチャで見てみる

Wireshark という無料ソフトでネットワークに流れるパケットを閲覧できます。

最近は https 通信が当たり前で、http通信のできるサイトは少なくなってきました。このページも基本は全てhttpsですが、以下URLだけは例外的に http 通信ができるようにしています。

http://milestone-of-se.nesuke.com/http.txt

上記URLにアクセスしたときの通信をパケットキャプチャで見てみます。クライアント=192.168.100.100, サーバ=157.112.150.6 です。

取得したパケットキャプチャを "tcp.port == 11699" でフィルタして表示しています。なので、1つのTCPコネクションのみが表示されています。

最初の3行が 3way Handshake です。そしてその後にクライアントからサーバに対して http 通信 (GETメソッド) を発行しています。その次に ACK を挟んで http レスポンスコード200 OK が返されています。それに対しても ACK が返され、数秒経った後にサーバから [FIN, ACK] でサーバ⇒クライアント方向のコネクションを閉じています(Active Close)。そのまた数秒後にクライアントから [FIN, ACK] でクライアント⇒サーバ方向のコネクションを閉じています(Passive Close)。

実はこのキャプチャで使ったブラウザは IE11 なのですが、Passive Close についてはブラウザを閉じることで発生しました。Active Close が為される前にブラウザを閉じると、TCP Reset によるコネクションクローズが発生しました。

TCP コネクションの状態確認

Windows の場合はコマンドプロンプトで netstat -an を使うと状態が確認できます。

LISTENING が待ち受け(通信が来るのを待っている)状態で、ESTABLISHED は通信が来て処理を開始している状態です。その他の状態は以下を参照下さい。

【図解】TCPの状態遷移 〜Listen、Establish、FIN Wait等〜
【図解】TCPの状態遷移 〜Listen、Establish、FIN Wait等〜
TCP には、ホストがどのような状況であるかを示す"状態(State)"...

また、Linux のTCP/UDP状態確認については ss コマンドを使います。以下コマンドを参照下さい。

linux【ss/netstat】コマンドの見方/オプション~Recv-Q/Send-Qやポート確認(Listen/Estab/Unconn),プロセス表示等~
linux【ss/netstat】コマンドの見方/オプション~Recv-Q/Send-Qやポート確認(Listen/Estab/Unconn),プロセス表示等~
ss コマンド (旧 netstat コマンド) とは ss は socket...

TCP/UDP の勉強については、以下の書籍がお薦めです。

フォローする