[図解]TCPヘッダのフォーマット〜シーケンス,PSH,RST,URGの動作〜

TCPの通信データ単位は"セグメント"と呼ぶことが多く、ここでもそれに倣うことにします。

以下にTCPセグメントのフォーマットを示します。TCPはIPv4の上位レイヤーとして使う場合、IPv4のプロトコルフィールドに Ox06(10進数:6)を指定します。

各Fieldについて

送信元ポート

16bit。送信元で利用するポート番号が入ります。送信元がクライアントの場合、多くのシーンで1024以上のHigher Portと呼ばれるポート群から適当ものが利用されます。

宛先ポート

16bit。宛先で利用するポート番号が入ります。宛先がサーバの場合、サービスに応じたポート番号になります。 例えば、telnetサーバへのtelnet接続であれば23、Webサーバへのhttp接続であれば80が入ります。

シーケンス番号/応答確認番号

共に32bit。どのデータを受信したかをお互い相手に知らせます。受信していないデータを検知したら再送する、といった高信頼性の提供に役立っています。また、TCPデータの到着順番が変わってしまっても、データを順番通りに組み立てられるようにもなっています。

以下に3wayハンドシェイクから始まる 一般的なTCPシーケンスにおける、Seq#/Ack#の番号の変化の例を示します。

シーケンス番号(Seq#)は、TCPコネクションを張る際のTCP 3wayハンドシェイクのTCP synおよびTCP syn/ack送信時に、端末が各々、ランダムに初期値を決めます。(クライアント⇒サーバの方向でのSeq#とサーバ⇒クライアントの方向でのSeq#は異なります)

それ以降は「Seq#=初期値+相手に送ったTCPデータのバイト数(DataLength)」となります。例外的に、3wayハンドシェイクのパケットは実際にはDataLength=0ですが、DataLength=1で計算します

例えば、Seq#=101で、相手に 500byteのデータを送ったとき、次に送るTCPセグメントのSeq#は601になります。(TCPデータのバイト数は、DataOffset(TCPヘッダ長)とIPヘッダ長、IPパケット長から算出)

なお、Seq#は双方向で独立したものが必要になります。つまり、クライアント⇒サーバの方向でのSeq#と、 サーバ⇒クライアントの方向でのSeq#は異なります。

確認応答番号(Ack#)は、TCP synは必ず0になります。それ以降は「Ack#=前回の相手のSeq#+DataLength」が入りますが、やはり例外的に、3wayハンドシェイクのパケットはDataLength=1で計算します。

なお、1セグメント毎に確認応答していたら効率が悪いので、データの受信側では、ある一定の数だけセグメントを受け取ったら、最後の確認応答だけを返すことで、それまでの全てのセグメントを受信した、ということになります。途中で欠損があった場合は、以下の2パターンに分かれます。

  1. TCPオプションのSACK(Selective ACK)に対応している場合は、SACKによって「受信したSeq#」を返し、欠損したSeq#のデータの再送を促します。
  2. SACKに対応していない場合は欠損の直前までのAck#を返し、それ以降のSeq#のデータを全て再送してもらいます。

なお、SACKに対応しているか否かは、最初のTCP 3wayハンドシェイク時のオプションで通知し合います。

データオフセット

4bit。TCPヘッダの長さ(4Byte単位)が入ります。

CWR bit、ECE bit

RFC3168で定義された、輻輳制御のためのビットです。(鈴木さん、ご指摘ありがとうございます。)

URG bit

1の場合、緊急通信であることを示します。使われ方としては、アプリケーション側で「緊急だ」と定義する通信において、ソケットAPIを利用してこのURGビットを立て、それを受信した対向アプリケーションがどのように処理するかを決めます。TCPとしては特に何も実行しません。

ただ、アプリケーション側でもこれを識別して特別な処理をさせることはほとんど無いようです。あまり意識しなくても良さそうなbitですが、パケットキャプチャを実行して、もしこのパケットが大量に出ているなどの場合は、その通信を行っているアプリケーションベンダに問い合わせるのが良いでしょう。

ACK bit

1の場合、応答確認番号Fieldが有効であることを示します。

PSH bit

1の場合、データ受信側はただちにデータをアプリケーションに引き渡すよう促します。これもURG bitと同じで、アプリケーション側でソケットAPIを利用してビットを立て、対向アプリケーションで処理を決めます。TCPとしては特に何も実行しません。URG bitよりはよく使われている気はします。

例えばTeraTerm等のターミナルソフトにおいては、コンソールで1文字打つたびにPSHで1byteのデータを送り、速やかに接続先に情報を渡す挙動になっていたりします。

RST bit

このビットが1にセットされたTCPセグメントを受信したホストは、ただちにTCPコネクションを切断します。

このビットは、TCP synを受信したが、そのTCPポートが開放されていない場合や、TCPシーケンス上で正しくないと判断されるデータを受け取った場合などに不正な通信としてコネクションを切断するために利用されます。

SYN bit

TCPのスリーウェイハンドシェイクの最初の往復だけに利用されます。それ以外では利用されません。

FIN bit

送信側に送るデータが無いときに、このビットをセットして受信側に送り、(RSTとは異なり、正しい通信として)コネクションを閉じる旨を通知します。ただし、コネクションは2方向あるので、基本的には双方からFIN bitの通信を送り合ってコネクションが完全終了となります。

ウィンドウ

16bit。このFieldは受信側が受け入れ可能なデータのバイト数を送信側に知らせるためのものです。受信側が送信側に ACK bitをセットしたセグメントを送る際にこのウィンドウFieldもセットされます。

なお、このウィンドウFieldは、効率の観点から、MSS値の整数倍が良いとされています。あるサンプルでは、 1430ByteのMSSに対して、46倍の65780Byte(=約64KByte)が設定されました(環境 OS:Windows7, ブラウザ:IE9)。

チェックサム

16bit。このFieldではTCPヘッダ、TCPデータだけでなく、送信元IPアドレス、宛先IPアドレス、プロトコル番号(Ox06)、 TCPセグメント長も検査されます。詳細は以下のページを参考にして下さい。

TCPの信頼性〜再送時間(RTO)と再送回数、チェックサム〜
TCPの信頼性〜再送時間(RTO)と再送回数、チェックサム〜
TCPの信頼性は、前述の通り、シーケンス番号(Seq#)と応答確認番号(Ack#...

緊急ポインタ

16bit。このFieldはURG bitがセットされた時のみに有効で、TCPデータの中のどこに緊急で処理する必要があるものがあるかを 示します。このFieldにセットされる値は、シーケンス番号 + 緊急処理を要するデータの位置(シーケンス番号が110で、緊急処理を 要するデータがTCPデータの先頭から440Byte目だった場合、550が入る)です。

前述の通り、このFieldをどのように活用するかはアプリケーション次第であり、TCPとしては特に何も実行しません。

オプションについては、次の章で説明します。

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

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

Comment

  1. 鈴木 より:

    参考にさせてもらいました。具体的でわかりやすいです。
    CWR bit、ECE bitの説明でRFC3268とありますがRFC3168ですかね。
    公開ありがとうございます。