インターネットを利用してウェブサイトを閲覧したり、メールを送受信したりする際、データは「パケット」と呼ばれる小さな単位に分割されてネットワーク上を流れます。
このパケットが宛先に届く順序は必ずしも一定ではなく、ネットワークの混雑状況や経路の違いによって、送信した順番とは異なる順序で到着することがあります。
このような不安定なネットワーク環境において、データの整合性を保ち、確実に元の情報を復元するために重要な役割を果たしているのが「シーケンス番号」です。
本記事では、TCP(Transmission Control Protocol)通信の基幹技術であるシーケンス番号の仕組みや、パケット再送制御における役割について詳しく解説します。
シーケンス番号の基礎知識
シーケンス番号とは、TCP通信において送信するデータパケットに付与される、データの位置を示す連続した番号のことです。
TCPは「信頼性の高い通信」を提供するためのプロトコルであり、送信側と受信側でデータの正確な受け渡しを管理する必要があります。
送信されるデータはバイト単位でカウントされ、各パケットの先頭バイトが全体のデータの何番目にあたるのかをシーケンス番号によって識別します。
TCPヘッダ内には、このシーケンス番号を格納するための32ビットのフィールドが用意されています。
32ビットの符号なし整数で表現されるため、シーケンス番号は0から最大で約42億(4,294,967,295)までの値を取ることができます。
この最大値を超えた場合は、再び0に戻ってカウントが継続される仕組みになっています。
ネットワーク上ではパケットの追い越しが発生することが珍しくありませんが、受信側はこの番号を参照することで、バラバラに届いたパケットを正しい順序に並び替えることが可能になります。
また、途中でパケットが消失してしまった場合も、シーケンス番号の欠落を確認することで、どの範囲のデータが届いていないかを正確に把握できます。
3ウェイ・ハンドシェイクと初期シーケンス番号(ISN)
TCP通信を開始する際、クライアントとサーバーの間でコネクションを確立するために「3ウェイ・ハンドシェイク」という手順が行われます。
このハンドシェイクの過程で、双方が通信に使用する初期シーケンス番号(ISN: Initial Sequence Number)を決定します。
初期シーケンス番号は必ずしも0から始まるわけではなく、セキュリティ上の理由からランダムな値が選ばれるのが一般的です。
もしシーケンス番号が常に0から始まったり、容易に予測可能なルールで割り振られたりすると、悪意のある第三者によるパケットの偽装やセッションハイジャックのリスクが高まるためです。
コネクション確立の流れ
まず、通信を開始したいクライアントが、自身のISN(例:X)を含むSYN(同期)パケットをサーバーに送信します。
次に、パケットを受け取ったサーバーは、クライアントのISNに1を加えた値を「確認応答番号(ACK番号)」として設定し、さらに自身のISN(例:Y)を含めたSYN+ACKパケットを返します。
最後に、クライアントがサーバーのISNに1を加えた値をACK番号として返し、コネクションが確立されます。
この手順により、双方がこれから送信するデータの開始地点を共有し、同期を取ることが可能になります。
確認応答(ACK番号)との密接な関係
シーケンス番号と対になって機能するのが、確認応答番号(ACK番号)です。
ACK番号は、受信側が「次に送信側から送ってほしいデータのシーケンス番号」を伝えるために使用されます。
例えば、送信側がシーケンス番号「1001」から「500バイト」のデータを送った場合、受信側は「1501」というACK番号を返します。
これは、「1500番までのデータは正常に受け取ったので、次は1501番から送ってください」というサインになります。
このように、シーケンス番号でデータの位置を伝え、ACK番号で受信完了を報告することで、1対1の確実なやり取りが実現されています。
送信側と受信側のやり取りの例
| アクション | 送信側のシーケンス番号 | データのサイズ | 受信側のACK番号 |
|---|---|---|---|
| 最初のデータ送信 | 1 | 1000バイト | 1001 |
| 次のデータ送信 | 1001 | 1000バイト | 2001 |
| その次のデータ送信 | 2001 | 1000バイト | 3001 |
この仕組みにより、送信側はACK番号を受け取ることで、どのデータまでが相手に無事に届いたのかを逐一確認できます。
パケットの順序制御と重複排除の仕組み
インターネット上の経路は複雑であり、パケットは必ずしも送信された順番通りに目的地へ到着するとは限りません。
例えば、あるパケットが遅延の少ない経路を通り、先に送信された別のパケットを追い越してしまう「順序逆転」が発生することがあります。
受信側のTCPスタックは、届いたパケットのシーケンス番号を確認し、あらかじめ確保されたバッファメモリ上でデータを並び替えます。
もし「1001番」の次に届くべきパケットが飛ばされ、「2001番」が先に届いた場合、TCPは「2001番」以降のデータを一時的に保管し、欠落している部分が届くのを待ちます。
全てのピースが揃った段階で初めて、アプリケーション層(ブラウザやメールソフトなど)にデータが引き渡されます。
また、ネットワークの不具合などで同じパケットが2回届いてしまう「重複パケット」の問題も、シーケンス番号によって解決されます。
受信側はすでに受け取り済みのシーケンス番号を持つパケットが再度届いた場合、それを重複データとして破棄することで、データの整合性を維持します。
データの再送制御(リトランスミッション)
TCPの最も強力な機能の一つが、データの紛失を検知して自動的に再送する「再送制御」です。
送信側はデータを送信した後、相手からのACK(確認応答)が戻ってくるのを一定時間待ちます。
この待ち時間を「再送タイマー(RTO: Retransmission TimeOut)」と呼びます。
もしタイマーが満了してもACKが返ってこない場合、送信側はパケットが途中で消失したか、あるいは相手に届かなかったと判断し、同じシーケンス番号を持つデータを再送します。
高速再送アルゴリズム
タイムアウトを待つのは時間がかかるため、効率を上げるための「高速再送」という仕組みも存在します。
受信側は、期待していたシーケンス番号とは異なる「先の番号」が届いた場合、欠落を知らせるために同じACK番号を繰り返し送信します。
送信側が「重複したACK」を3回受け取った時点で、タイムアウトを待たずに即座に該当するパケットを再送します。
これにより、一部のパケットロスによる通信速度の大幅な低下を防ぎ、スムーズな通信を継続できるようになっています。
スライディングウィンドウとフロー制御への応用
シーケンス番号は、通信の効率化を図る「スライディングウィンドウ」という仕組みにも深く関わっています。
本来、パケットを一つ送るたびにACKを待っていては、通信の待ち時間が長くなり効率が非常に悪くなります。
そこで、相手の受信能力(ウィンドウサイズ)に合わせて、ACKを待たずに複数のパケットをまとめて送信する手法が採られています。
送信側は、シーケンス番号を基準として「現在送信を許可されている範囲」を管理します。
受信側からACKが届くたびに、この送信可能な範囲(ウィンドウ)がスライドしていくため、スライディングウィンドウと呼ばれます。
もし受信側の処理が追いつかなくなり、バッファが一杯になった場合は、受信側から送られるウィンドウサイズの値を小さくすることで、送信側にブレーキをかける「フロー制御」が行われます。
このように、シーケンス番号は単なる「順番」以上の意味を持ち、通信の流量を最適化するためのインデックスとしても機能しています。
セキュリティ上の重要性とシーケンス番号予測攻撃
シーケンス番号は、通信の信頼性だけでなく、ネットワークセキュリティの観点からも極めて重要です。
かつてはISNが予測可能な単純な数値であったため、第三者がシーケンス番号を推測してなりすましを行う「シーケンス番号予測攻撃」が大きな脅威となっていました。
攻撃者が正しいシーケンス番号を偽装したパケットを送信できれば、正当なユーザーに代わってセッションを乗っ取ることが可能になります。
現在では、多くのオペレーティングシステム(OS)において、高度な擬似乱数生成器を用いてISNをランダム化する対策が施されています。
RFC 6528などの標準規格においても、ISNの生成アルゴリズムの厳格化が推奨されており、現代のTCP通信の安全性が確保されています。
まとめ
シーケンス番号は、TCP/IP通信におけるデータの順序正しさと完全性を保証するための心臓部とも言える仕組みです。
この小さな32ビットの数値があるおかげで、私たちはパケットの消失や順序の入れ替わりが発生するインターネットという不完全な経路の上で、エラーのない正確なデータをやり取りできています。
コネクションの確立から、データの再送、フロー制御、そしてセキュリティ対策に至るまで、シーケンス番号が果たす役割は多岐にわたります。
ネットワークエンジニアやシステム開発に携わる方にとって、シーケンス番号の挙動を深く理解することは、トラブルシューティングやパフォーマンス最適化において大きな助けとなるでしょう。
普段意識することのない裏方の仕組みですが、現代のデジタル社会を支える不可欠な技術であることを再確認していただければ幸いです。
