シーケンス番号
TCPで、送信するデータの位置をバイト(オクテット)単位で示す番号。次に送るセグメントのシーケンス番号は、直前のセグメントのシーケンス番号に、そのデータのオクテット数を足した値になる。
イマシルちゃんの解説
長い手紙を何枚かに分けて送るとき、それぞれに「何文字目から書いてあるか」を書いておけば、
順番がバラバラに届いても、正しく並べ直せるよね。
TCPのシーケンス番号は、まさにこれなんだ!
「1枚目」「2枚目」っていう枚数じゃなくて、「何バイト目から」っていう位置を書くのがポイントだよ。
だから、100バイト送ったら、次の番号は100増えるんだ!
より深い解説
定義
シーケンス番号(Sequence Number)は、TCPヘッダーにある32ビットのフィールドで、そのセグメントに含まれるデータの先頭のバイトが、送信するデータの流れ(バイトストリーム)全体のどの位置にあたるかを示す。TCPは、データをセグメントの単位ではなく、バイトの単位で番号付けしている。
番号の進み方
次のシーケンス番号 = 今のシーケンス番号 + 今のセグメントのデータのオクテット数
例:シーケンス番号1001から、1セグメントに500バイトずつ送る場合
| セグメント | シーケンス番号 | データ | 含まれるバイトの位置 |
|---|---|---|---|
| 1つ目 | 1001 | 500バイト | 1001~1500 |
| 2つ目 | 1501 | 500バイト | 1501~2000 |
| 3つ目 | 2001 | 300バイト | 2001~2300 |
受信側から応答を待たずに続けて送る場合も、番号は同じ規則で進む。セグメントの数ではなく、送ったデータの量だけ増えるので、「1ずつ増える」わけではない。
初期シーケンス番号(ISN)
シーケンス番号は0から始まるのではなく、コネクションの確立時に決める初期シーケンス番号(ISN:Initial Sequence Number)から始まる。ISNは、3ウェイハンドシェイクのSYNのセグメントで相手に伝える。
- SYNとFINは、データを含まないが、シーケンス番号を1つ消費する
- ISNは、推測されにくい値にする必要がある。予測できると、第三者が正しい番号の偽のセグメントを送り込む攻撃(TCPシーケンス番号予測攻撃)が可能になるためである
番号の一周
シーケンス番号は32ビットなので、最大値は2^32 − 1(4,294,967,295)である。最大値を超えると0に戻り、そのまま番号付けを続ける。最大値が65,535なのは、16ビットのフィールドであるポート番号やウィンドウサイズのほうである。
高速な回線では、32ビットの番号が短時間で一周してしまい、古いセグメントと新しいセグメントの番号が重なる恐れがある。これを防ぐため、タイムスタンプオプションを使ったPAWS(Protection Against Wrapped Sequence numbers)という仕組みがある。
確認応答番号との関係
受信側は、データを受け取ると、「次に受け取りたいバイトのシーケンス番号」を確認応答番号として返す。
確認応答番号 = 受け取ったシーケンス番号 + 受け取ったデータのオクテット数
受信側が返す確認応答番号は、受け取ったシーケンス番号そのものではなく、その次の番号である。送信側は、確認応答番号より前のデータが届いたと判断できる。
双方向の番号
TCPは全二重の通信なので、AからBへのデータと、BからAへのデータには、それぞれ独立したシーケンス番号が使われる。1つのセグメントの中で、シーケンス番号は自分が送るデータの位置を、確認応答番号は相手から受け取ったデータの位置を表す。両者は別の番号の系列なので、大小を比べることには意味がない。