こんにちは!技術メディアの主筆ライターとして、日々パケットの鼓動を追いかけているネットワークスペシャリストです。
ネットワークの世界に足を踏み入れたばかりの皆さん、「パケットが届かない」というトラブルに遭遇したことはありませんか?
インターネットという大海原では、時としてパケット(データの欠片)が波にのまれて消えてしまうことがあります。そんな時、私たちの通信を影で支え、効率よくデータを修復してくれるヒーローがいます。
それが、今回ご紹介する「TCP SACK (Selective Acknowledgment)」です。
一見難しそうな名前ですが、仕組みを紐解けば、私たちが日常で行っている「スマートなやり取り」そのもの。今回は、郵便配達の例えを交えながら、このSACKオプションの魔法について、一歩ずつ丁寧に解説していきますね!
—
1. そもそも、なぜ SACK が必要なの?
TCP(Transmission Control Protocol)は、データの「信頼性」を何よりも大切にするプロトコルです。データが欠けたら、必ず送り直す。これが鉄則です。
しかし、昔ながらのTCPには、少し「融通が利かない」ところがありました。
昔のTCP(累積確認応答)の場合
例えば、あなたが友人に1番から10番までの「10枚の連続した写真」を送ったとしましょう。
ところが、途中で3番の写真だけが風に飛ばされてしまいました。
- 友人: 「2番までは届いたよ!だから、次は3番から送って!」
- あなた: 「えっ、4番から10番まではもう持ってるはずだけど……。まあいいや、指示通り3番から10番まで全部送り直すよ」
……どう思いますか? 4番から10番はすでに届いているのに、もう一度送り直すのは、時間も通信量(帯域)ももったいないですよね。これが、SACKがない時代の「累積確認応答」の弱点でした。
SACK がある場合
ここで SACK の登場です。同じ状況で、友人はこう言います。
- 友人: 「2番までは届いたよ! あと、4番から10番も手元にあるよ! だから、3番だけ送って!」
- あなた: 「了解! じゃあ3番だけ送るね。効率的だね!」
これが SACK (Selective Acknowledgment:選択的確認応答) です。「どこが抜けていて、どこが届いているか」をピンポイントで伝えることで、無駄な再送を劇的に減らしてくれるのです。
—
2. パケットの中身を覗いてみよう(構造の理解)
さて、ここからは少しだけ専門的な「パケットの構造」に踏み込んでみましょう。難しいビット計算は置いておいて、「何が書かれているか」をイメージしてくださいね。
TCP SACK は、TCPヘッダーの最後の方にある「オプション(Options)」という自由記述欄のようなスペースを使います。
ステップ1:まずは「SACKできるよ!」という握手
通信を始める一番最初(SYNパケットを投げ合う時)、お互いに「私はSACKの機能を知っているよ、使ってもいい?」と確認し合います。これを SACK-Permitted オプションと呼びます。
ステップ2:実際の「歯抜け」報告
データが欠けた時、受信側は以下の情報をパケットに書き込んで送り返します。
- ACK番号: 「ここまでは連続して届いてるよ」という境界線(例:2番までOK)
- SACKオプション: 「離れた場所にあるけど、ここからここまでは届いてるよ」という範囲
この「ここからここまで」という範囲を、専門用語で Left Edge (左端) と Right Edge (右端) と呼びます。
| 項目 | 意味 |
| :— | :— |
| Left Edge (左端) | 届いているデータの塊の「開始」シーケンス番号 |
| Right Edge (右端) | 届いているデータの塊の「終了」シーケンス番号 |
一つのパケットには、この「範囲(ブロック)」を最大で4つまで書くことができます。パケットのヘッダーはサイズに限りがあるので、4つが限界なんですね。
—
3. 実務での設定と確認方法
「自分のサーバーやPCで SACK が動いているか気になる!」という方のために、Linuxでの設定確認方法と、パケットキャプチャでの見え方をご紹介します。
Linuxでの設定確認
最近のOSであれば、デフォルトで有効になっていることがほとんどですが、以下のコマンドで設定を確認・変更できます。
# SACKが有効になっているか確認(1なら有効、0なら無効)
sysctl net.ipv4.tcp_sack
# 設定を変更する場合(一時的な適用)
# sudo sysctl -w net.ipv4.tcp_sack=1
# 設定ファイルを確認して永続化する場合
# cat /etc/sysctl.conf | grep tcp_sack
Wiresharkでの見え方
ネットワーク解析ツール Wireshark でパケットを覗くと、TCPヘッダーの中に以下のような記述が見つかるはずです。
- 接続開始時:
TCP Option - SACK permitted - パケットロス発生時:
TCP Option - SACK: 4001-5001, 6001-7001
このように、欠落した部分を飛ばして「持っている範囲」を律儀に報告している様子が見えると、なんだかパケットが健気に思えてきませんか?
—
4. Pythonでシミュレーションしてみよう
「コードで動きをイメージしたい」というエンジニアの方に向けて、SACKの考え方を簡単なリスト操作で表現してみました。これは通信そのものではなく、「どの範囲を再送すべきか」を判断するロジックのイメージです。
def get_retransmission_targets(total_packets, received_indices, sack_blocks):
"""
再送が必要なパケットを特定するシミュレーション
total_packets: 送信した全パケット番号のリスト
received_indices: 正常に届いた連続したパケット(ACK)
sack_blocks: SACKで通知された「離れ小島」の受信済み範囲
"""
# すでに受信できている範囲をセットにまとめる
already_have = set(range(1, received_indices + 1))
# SACKブロック(Left Edge, Right Edge)を反映
for left, right in sack_blocks:
# rightは「次に期待する番号」なので、実際はright-1まで受信済み
already_have.update(range(left, right))
# 送信した全パケットのうち、まだ持っていないものだけを抽出
needs_retransmit = [p for p in total_packets if p not in already_have]
return needs_retransmit
# 例:1番〜10番を送ったが、3番と5番が消えた場合
# 受信側は「2番までOK」「4番OK」「6〜10番OK」と伝える
total = list(range(1, 11))
ack_up_to = 2
sacks = [(4, 5), (6, 11)] # 4番のみ、および6番から10番まで
targets = get_retransmission_targets(total, ack_up_to, sacks)
print(f"再送が必要なパケット: {targets}")
# 出力結果: 再送が必要なパケット: [3, 5]
# 4番や6〜10番を飛ばして、3番と5番だけを狙い撃ちできました!
—
まとめ:SACK は「スマートな気配り」
TCP SACK の仕組み、いかがでしたでしょうか?
1. 無駄を省く: すでに届いているデータは二度送らせない。
2. ピンポイント: 足りないピースだけを正確に要求する。
3. 高速化: 特に遅延が大きい回線や、パケットロスが起きやすい無線環境で絶大な効果を発揮する。
現代のインターネットがこれほどスムーズに動いているのは、OSI参照モデルの第4層(トランスポート層)で、こうした「ちょっとした気配り」が積み重なっているからなのです。
もし、皆さんがトラブルシューティングでパケットキャプチャを見る機会があったら、ぜひ TCP Options の中にある SACK を探してみてください。そこには、健気にデータの欠落を埋めようとする、ネットワークの熱いドラマが隠されています。
「一歩ずつ理解していけば、ネットワークはもっと楽しくなる!」
これからも一緒に、パケットの裏側を探検していきましょうね。
それでは、また次回の記事でお会いしましょう!
コメント