第16回 信頼性のある通信を実現するTCPプロトコル(3):基礎から学ぶWindowsネットワーク(3/4 ページ)
TCP/IPの核であるTCPプロトコルの詳細を知る。TCP編の最後である今回は、TCPのオプションと状態遷移について解説する。
TCP技術を習得するうえで非常に重要な項目として、「TCPの状態遷移図」というものがある。これはTCPプロトコルの規格書であるRFC793(STD0007)に掲載されている、TCPプロトコルの内部ステートを表現した図である。すでに解説したように、TCPでは接続ごとに、それぞれシーケンス番号やACK番号、オープン/クローズなどの処理状態といった「ステート(状態)」を持っている。このようなプロトコルを「ステートフルな(stateful、状態を持つ)」プロトコルという。TCP接続のオープンやクローズ、確立などに伴う、状態の変化を表現した図を「状態遷移図」という。
以下は、RFC793に記載されているTCPの状態遷移図を簡略化したものである(完全な状態遷移図についてはRFC793を参照していただきたい)。
TCPの状態遷移図
RFC793に記載の状態遷移図を簡略化して、分かりやすくしたもの。煩雑になりそうな部分は削除しているので、全遷移を知りたい場合はRFC793(STD0007)を参照していただきたい。一番上と一番下に「CLOSED」があるが、これは同じものである。四角の中に書かれているのがTCPの状態名。矢印は可能な遷移の経路。矢印のそばにある文字は、「トリガ(アクション)」を表しており、あるトリガとなるイベントが発生すると、「アクション」を実行する。
アクティブ・オープン((1))やパッシブ・オープン((2))、アクティブ・クローズ((4))、パッシブ・クローズ((5))などのカテゴリについてはすでに解説したとおりである。前回解説したパケットのやりとりの図と照らし合わせると、状態の遷移がよく分かるはずだ(前回の図には状態名も記入してある)。
「CLOSED」や「LISTEN」「SYN_SENT」「ESTABLISHED」「CLOSE_WAIT」など、四角で囲まれた英語の部分を「状態(ステート)」という。そして矢印は、ある状態から別の状態へ移行(遷移)する可能性があるということを示している。例えば真ん中の「ESTABLISHED」からは「FIN_WAIT_1」と「CLOSE_WAIT」のいずれかへ遷移する可能性がある。
さらに矢印のそばにある文字にも注意していただきたい。これは、その遷移が発生する条件と、そこで行われる動作(アクション)を表している。例えば「LISTEN」から「SYN_RECEIVED」へ向かう矢印のそばには、「SYNの受信(SYN/ACKの送信)」と書いてある。これは『現在「LISTEN」状態ならば、SYNパケットを受け取ると、SYN/ACKを送信して、「SYN_RECEIVED」状態へ遷移する』という意味である。同様にして『「SYN_RECEIVED」状態でACKを受信すると、「ESTABLISHED」状態へ遷移する』ということも読み取れるだろう。またよく見ると、アクティブ・オープンとパッシブ・オープン、アクティブ・クローズとパッシブ・クローズがそれぞれ対応していることも分かる(例:アクティブ・オープンの「SYNの送信」というアクションは、パッシブ・オープンの「SYNの受信」というトリガになっている)。このように、TCPの状態遷移図を読むと、TCPが取り得る状態の全体像と、その遷移のための条件、遷移時の動作などが分かる。慣れないうちは面倒に感じるかもしれないが、ぜひとも読みこなせるようになっていただきたい。
この図がなぜ重要かというと、ネットワークのトラブルシューティングなどでは、これらのステートを意識する必要があるからだ。
TCP/IPネットワークのトラブルシューティングでは、netstatコマンドをよく利用するだろう。試しに「netstat -an」を実行してみよう。
C:\>netstat -an
Active Connections
Proto Local Address Foreign Address State
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1025 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1067 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1792 0.0.0.0:0 LISTENING
TCP 0.0.0.0:3221 0.0.0.0:0 LISTENING
TCP 0.0.0.0:3389 0.0.0.0:0 LISTENING
TCP 0.0.0.0:3613 0.0.0.0:0 LISTENING
TCP 0.0.0.0:3838 0.0.0.0:0 LISTENING
TCP 0.0.0.0:4054 0.0.0.0:0 LISTENING
TCP 0.0.0.0:4924 0.0.0.0:0 LISTENING
TCP 0.0.0.0:4927 0.0.0.0:0 LISTENING
TCP 192.168.2.155:139 0.0.0.0:0 LISTENING
TCP 192.168.2.155:445 192.168.2.231:1172 ESTABLISHED
TCP 192.168.2.155:1052 0.0.0.0:0 LISTENING
TCP 192.168.2.155:1101 0.0.0.0:0 LISTENING
TCP 192.168.2.155:1104 0.0.0.0:0 LISTENING
TCP 192.168.2.155:1106 0.0.0.0:0 LISTENING
TCP 192.168.2.155:1792 192.168.2.51:445 ESTABLISHED
TCP 192.168.2.155:3613 192.168.2.56:445 ESTABLISHED
TCP 192.168.2.155:3838 128.9.XXX.XX:21 CLOSE_WAIT
TCP 192.168.2.155:4054 128.9.XXX.XX:21 CLOSE_WAIT
TCP 192.168.2.155:4438 1.2.3.4:23 SYN_SENT
TCP 192.168.2.155:4924 128.9.XXX.XX:21 CLOSE_WAIT
TCP 192.168.2.155:4927 128.9.XXX.XX:20 ESTABLISHED
UDP 0.0.0.0:445 *:*
…以下省略…
TCP接続の一番右端にある「State」の欄に注目していただきたい。「LISTENING(RFC中ではLISTENとなっている)」や「ESTABLISHED」「CLOSE_WAIT」「SYN_SENT」などの文字が並んでいる。そう、これは先の状態遷移図中に表示されている、TCPの状態の名称そのものなのである。状態遷移図と照らし合わせると、あるTCPコネクションがどの状態になっているかとか、どのようなパケットを待っているか、などが分かる。なおnetstatの使い方については別稿の「TIPS―netstatコマンドを使いこなす」なども参考にしていただきたい。ただし残念ながら、UDPはステートを持たないプロトコルなので、UDPの状態を調べることはできない。
以下、各状態について簡単に解説しておく。
■CLOSED
図の一番上(と一番下)にあるCLOSEDは、netstatでは表示されない。未使用もしくは使用済みのTCB(Transmission Control Block。TCPの各接続の内部状態を保存しているデータ構造)がこれに該当する。
■LISTEN
パッシブ・オープンで、待ち受け状態(リッスン状態)になっていることを表す。アクティブ・オープンのSYNを受けて「SYN_RECEIVED」へ遷移する。
■SYN_RECEIVED
アクティブ・オープンのSYNに対してACKとSYNで応答し、それに対するACKを待っている状態。ACKを受信すると「ESTABLISHED」へ遷移する。
■SYN_SENT
アクティブ・オープンで、SYNを送信した状態。SYNとACKを受信すれば、ACKを送信して「ESTABLISHED」へ遷移する。
■ESTABLISHED
TCP接続が確立した状態。データの送受信を行うことができる。FINを受けたり、上位アプリケーションからクローズが呼び出されたりすると、クローズ処理へ遷移する。
■FIN_WAIT_1
アクティブ・クローズの最初の段階。FINを送信して、それに対する応答を待っている状態。
■FIN_WAIT_2
送信したFINに対するACKを受け取った状態。送信側のクローズ処理が終了し、相手からのFINを受信するのを待っている状態。
■CLOSING
アクティブ・クローズでFINを送信した後、ACKが戻ってくるよりも先に、相手からもFINを受けた状態。両方でほぼ同時にアクティブ・クローズ処理を開始するとこの状態になる。送信したFINのACKを待って、「TIME_WAIT」へ遷移する。
■TIME_WAIT
「CLOSING」でACKを受けた状態。アクティブ・クローズ後のタイムアウト待ち状態。同じシーケンス番号やポート番号などを再利用しないように、しばらく待ってから(ネットワーク上で遅れていたパケットがこの時間内に到着する可能性があるので、それと衝突しないように待つ)、「CLOSED」へ遷移して終了する。
■CLOSE_WAIT
パッシブ・クローズの状態。送信側にFINを送信して「LAST_ACK」へ遷移する。
■LAST_ACK
「CLOSE_WAIT」で送信したFINに対するACKを待つ状態。ACKの受信後、「CLOSED」へ遷移する。
このような状態を調査することにより、ネットワークのトラブルシューティングに役立てることができる。例えばある通信がSYN_SENTのままでずっと止まっているとしたら、それはオープンをしようとして待っているということが分かる。相手側のマシンでも同じようにnetstatを実行し、SYN_RECEIVEDなら戻りのSYN/ACKのパケットがどこかでブロックされていることが分かるし、LISTENのままなら最初のSYN要求がブロックされ、相手に届いていないということが分かる。
Copyright© Digital Advantage Corp. All Rights Reserved.