ネットワーク(TCP/IP):URL を入力してからページが表示されるまで
Prerequisite:クラウドコンピューティング:オンプレミスとの分岐点を数式で見る
This content is not available in your language yet.
0. この記事の要点
Section titled “0. この記事の要点”- インターネットは「層」に分けて設計されています。層の本質はカプセル化、すなわち上位層のデータをそのまま下位層のペイロードとして包み、下位層は中身を解釈しないという規律です。この規律のおかげで、アプリケーションの数と物理媒体の数を掛け算ではなく足し算で扱えます。
- IP アドレスは「番号」ではなくアドレスの集合(プレフィックス)として扱われます。プレフィックスの集合は入れ子か素かのどちらかにしかならず、そこから最長プレフィックス一致が一意に定まることが証明できます(Theorem 4.4)。経路表という巨大な分散データ構造が矛盾なく動くのは、この単純な事実のおかげです。
- TCP のスループットには という上限があります(Proposition 5.4)。帯域を増やしても RTT が縮まらない限り、ウィンドウ を広げなければ速くなりません。長距離通信で「回線は速いのに遅い」現象の大半はこれで説明できます。
- 3 ウェイハンドシェイクの 3 回目は冗長ではありません。2 回で済ませると、遅延して届いた古い接続要求で誤った接続が成立します(Proposition 5.3)。
- ブラウザに URL を入れてから HTML が届くまでには、DNS・TCP・TLS・HTTP でそれぞれ往復が発生します。国際回線の RTT を 80 ms とすると初回アクセスに約 320 ms かかり、この内訳を数えられることが性能改善の出発点になります(Example 7.1)。
1. 動機 — 二台をつなぐのは簡単、全世界をつなぐのは難しい
Section titled “1. 動機 — 二台をつなぐのは簡単、全世界をつなぐのは難しい”二台の計算機をケーブルでつなぎ、電圧の高低でビットを送る。これだけなら数十行のプログラムで書けます。難しいのは、互いに設計を知らない何十億台の機器を、誰も全体を管理していない状態でつなぐことです。
歴史的には 1969 年の ARPANET が出発点でした。当初のプロトコル NCP は、すべてのホストが同種のネットワークにつながっていることを前提にしていました。しかし 1970 年代に入ると、無線パケット網や衛星回線など、性質のまったく異なるネットワークが現れます。「ネットワークどうしをつなぐ」という問題(inter-networking、これが internet の語源です)に Vinton Cerf と Robert Kahn が 1974 年の論文で与えた答えが、現在の TCP/IP の骨格です。1983 年 1 月 1 日、ARPANET は NCP を捨てて TCP/IP に一斉移行します。
彼らの設計の中心にあるのは、次の二つの割り切りです。
第一に、パケット交換にする。 通話のように回線を占有する方式(回線交換)では、通信していない間も帯域が遊びます。データを小さな塊(パケット)に切って宛先を書き、共有された回線に流し込めば、複数の通信で帯域を分け合えます。代わりに、パケットは順序が入れ替わったり、混雑時に捨てられたりします。
第二に、中継ノードを賢くしない。 途中のルータは「次にどこへ渡すか」だけを決め、再送も順序の復元も末端のホストが行います。これを end-to-end 原則と呼びます。中継が単純だからこそルータは高速化でき、新しい種類の通信を追加してもネットワークの中身を書き換えずに済みます。
そのうえで機能を層に分けます。動機は抽象化の美しさというより、単純な組み合わせの数え上げです。アプリケーションが 種類、物理媒体が 種類あるとき、すべての組み合わせを個別に実装すれば 通りの作業が要ります。両者の間に共通の中間層(IP)を挟めば、上向きに 個、下向きに 個、合計 個で済みます。IP が一種類しかなく上下が多様なこの構造を、砂時計モデルと呼びます。
2. 準備:パケット交換と遅延のモデル
Section titled “2. 準備:パケット交換と遅延のモデル”Definition 2.1(プロトコルと PDU)
プロトコルとは、通信する二つ以上の主体が交換するメッセージの形式と、送受信に際して取る動作の順序を定めた規約です。ある層のプロトコルがやり取りする単位をその層の PDU(Protocol Data Unit)と呼び、PDU はヘッダ(その層の制御情報)とペイロード(上位層から預かったデータ)からなります。
性能の議論に入る前に、遅延がどこから来るのかを分解しておきます。「どこを改善すれば速くなるか」を判断する土台になります。
Proposition 2.2(端点間遅延の分解)
送信元から宛先までの経路が 本のリンクからなり、リンク の帯域を [bit/s]、物理長を [m]、その媒体中の信号伝搬速度を [m/s] とします。サイズ [bit] のパケットが各中継ノードで蓄積交換される(パケット全体を受信し終えてから次のリンクへ送り出す)とき、パケットの端点間遅延 は
で与えられます。ここで はノード での処理遅延、 は送信待ち行列での待ち時間です。
Proof(Proposition 2.2)
リンク に注目します。ノードがパケットの先頭ビットを送り出してから最後のビットを送り出すまでにかかる時間が送信遅延で、 ビットを毎秒 ビットの速度で押し出すのですから です。最後のビットが回線に乗ってから相手側に届くまでの時間が伝搬遅延で、距離 を速度 で進むのですから です。したがってリンク の通過に かかります。
蓄積交換の仮定により、ノードはパケット全体を受け取るまで次のリンクへの送出を開始しません。よって各リンクの通過時間は重ならず、単純に足し合わされます。これに、ヘッダを読んで出力ポートを決める処理遅延と、その出力ポートが塞がっている間の待ち時間を各ノードで加えれば、主張の式を得ます。
四つの成分のうち、経路の混雑度に左右されるのは だけです。その定常的な大きさは待ち行列のモデルから見積もれます(M/M/1 待ち行列(Proposition 5.2)[クラウドコンピューティング])。以下の見積もりでは、混雑していない経路を想定して送信遅延と伝搬遅延に注目します。
Example 2.3(太平洋を越える遅延の内訳)
東京からサンフランシスコまで、光ファイバの実経路長を km、ファイバ中の光速を m/s とします。伝搬遅延の合計は
です。一方、1500 バイト( bit)のパケットが 1 Gbit/s のリンク 10 本を蓄積交換で通るときの送信遅延の合計は
にすぎません。片道 60 ms のうち送信遅延は 0.2% です。往復時間(RTT)はおよそ 120 ms になります。
すべてのリンクを 10 Gbit/s に増強しても、片道遅延は 60.12 ms から 60.01 ms にしか縮みません。帯域はお金で買えますが、伝搬遅延は光速で決まっており買えません。 遅いページを速くしたいとき、まず数えるべきは往復回数です。
3. 階層モデル:OSI と TCP/IP
Section titled “3. 階層モデル:OSI と TCP/IP”3.1. 二つのモデル
Section titled “3.1. 二つのモデル”OSI 参照モデルは ISO と ITU-T が 1980 年代に標準化した 7 層のモデルで、通信機能を物理層から応用層まで整理した「教科書上の座標系」です。これに対し TCP/IP モデルは、実際に動くプロトコル群を後から 4 層に整理したものです。実務では両者が混ぜて使われ、「L3 スイッチ」「L7 ロードバランサ」のように OSI の層番号が日常語になっています。
| TCP/IP(4 層) | OSI(7 層) | PDU の呼び名 | 代表的なプロトコル | アドレスの単位 |
|---|---|---|---|---|
| アプリケーション層 | 応用・プレゼンテーション・セッション(5〜7) | メッセージ | HTTP, DNS, SMTP, TLS | URL・ドメイン名 |
| トランスポート層 | トランスポート(4) | セグメント / データグラム | TCP, UDP, QUIC | ポート番号 |
| インターネット層 | ネットワーク(3) | パケット | IP, ICMP | IP アドレス |
| リンク層 | データリンク・物理(1〜2) | フレーム | Ethernet, Wi-Fi (802.11) | MAC アドレス |
OSI の第 5 層(セッション)と第 6 層(プレゼンテーション)に対応する独立したプロトコルは、TCP/IP にはほぼ存在しません。TLS は「第 6 層」と呼ばれますが、実装上は TCP の上に載る一つのプロトコルです。OSI モデルは共通語彙として使い、実装の構造そのものだと思わないでください。
3.2. カプセル化
Section titled “3.2. カプセル化”Definition 3.2(カプセル化)
層 のプロトコルが上位層 から受け取った PDU を、内容を解釈せずそのまま自分のペイロードとし、自層のヘッダ(必要ならトレーラも)を付けて層 の PDU を作ることをカプセル化といいます。受信側では逆に、層 が自層のヘッダを取り除き、ペイロードを層 に渡します。
「内容を解釈せず」が層の独立性の本体です。IP はペイロードが TCP か UDP か QUIC かを気にせず(番号を運ぶだけで)、Ethernet は中身が IPv4 か IPv6 かを気にしません。
Definition 3.3(MTU と MSS)
あるリンクが一度に運べるペイロードの最大長(IP パケットの最大長)を MTU(Maximum Transmission Unit)、TCP が一つのセグメントに載せられるアプリケーションデータの最大長を MSS(Maximum Segment Size)と呼びます。オプションのない IPv4 と TCP では
です。
Example 3.4(イーサネット上での有効伝送率)
標準的なイーサネットの MTU は 1500 バイトです。IPv4 ヘッダ 20 バイト、TCP ヘッダ 20 バイトを引くと
となります。IP パケットの長さに対する有効データの割合は です。
リンク層まで数えます。イーサネットフレームは宛先・送信元 MAC アドレスと型フィールドで 14 バイト、末尾の誤り検出符号(FCS)で 4 バイトを使い、回線上ではさらにプリアンブル 8 バイトとフレーム間ギャップ 12 バイト分の時間を消費します。1 回の送信が占有するのは
分で、有効伝送率は です。1 Gbit/s の回線で得られる TCP の理論最大スループットは Gbit/s Mbit/s ということになります。「1 Gbps 回線なのに 940 Mbps しか出ない」のは異常ではなく、ヘッダの分です。
4. インターネット層:アドレスと経路制御
Section titled “4. インターネット層:アドレスと経路制御”4.1. IP アドレスとプレフィックス
Section titled “4.1. IP アドレスとプレフィックス”Definition 4.1(IPv4 アドレスと CIDR プレフィックス)
IPv4 アドレスは 32 ビットの列で、8 ビットずつ 10 進で区切って 192.0.2.1 のように書きます。プレフィックス ()とは、上位 ビットが の上位 ビットと一致する 32 ビット列全体の集合を指します。 をプレフィックス長と呼びます。この表記法を CIDR(Classless Inter-Domain Routing)といいます。
強調したいのは、個々のアドレスより集合が主役だという点です。経路表はアドレスを一つずつ覚えるのではなく、「この集合に属する宛先は隣のルータへ」という規則をプレフィックス単位で持ちます。 個のアドレスを 程度の規則に圧縮できるからこそ、全世界の経路が 1 台のメモリに載ります。
Example 4.2(プレフィックスの計算)
プレフィックス 203.0.113.128/25 を考えます。プレフィックス長が 25 なので、固定されるのは上位 25 ビット、すなわち最初の 3 オクテットと第 4 オクテットの最上位 1 ビットです。第 4 オクテット の最上位ビットは 1 ですから、この集合は
すなわち 128 個のアドレスからなります。一般に長さ のプレフィックスは 個のアドレスを含みます。
203.0.113.130は含まれるか。 で最上位ビットが 1 なので、含まれます。203.0.113.60は含まれるか。 で最上位ビットが 0 なので、含まれません。
このうち先頭の 203.0.113.128 はネットワークアドレス、末尾の 203.0.113.255 はブロードキャストアドレスとして予約されるため、ホストに割り当てられるのは 個です。一般に のとき割当可能数は です。
4.2. 最長プレフィックス一致
Section titled “4.2. 最長プレフィックス一致”経路表には、同じ宛先アドレスにマッチする規則が複数入りえます。203.0.113.0/24 が ISP A へ、203.0.113.128/25 が ISP B へ、という二つが同時に存在する状況は普通です。このとき「より細かいほうを選ぶ」のが最長プレフィックス一致です。これが常に一意に決まることを示します。
Lemma 4.3(プレフィックスの入れ子性)
二つのプレフィックス 、 について、集合として ならば、 のとき が成り立ちます。すなわち任意の二つのプレフィックスは、互いに素であるか、一方が他方を含むかのいずれかです。
Proof(Lemma 4.3)
を一つ取り、 とします。アドレス の上位 ビットからなる列を と書きます。
より 、 より です。 なので、後者の等式の最初の ビットだけを見れば を得ます。二つを合わせると
です。さて任意の を取ると 、とくに ですから、 です。よって が示されました。
でない限りこの議論が使えるので、二つのプレフィックスは素か入れ子かのどちらかです。
Theorem 4.4(最長プレフィックス一致の一意性)
を有限個のプレフィックスの集合、 を 32 ビットのアドレスとし、 とおきます。 ならば、 の中でプレフィックス長が最大のものはただ一つ存在し、それは包含関係に関する の最小元です。
Proof(Theorem 4.4)
まず、 の元でプレフィックス長が等しいものは一致します。実際 と がともに を含むなら、 であり、プレフィックスは上位 ビットのみで定まるので です。したがって の元のプレフィックス長はすべて相異なり、 は有限で空でないので、長さ最大の元 がただ一つ定まります。
次に が包含に関する最小元であることを見ます。任意の を取ると、 より であり、 の長さは の長さ以下ですから、Lemma 4.3 を に適用して を得ます。これがすべての について成り立つので、 は の最小元です。
この定理は「最長のものを選ぶ」規則が「候補のうち最も限定的な指示に従う」規則と同じであることを示しています。設計者は大きな範囲に大まかな規則を書き、例外だけを長いプレフィックスで上書きできます。経路表の最後に必ず置かれるデフォルト経路 0.0.0.0/0 は長さ 0 のプレフィックス、すなわち全アドレスの集合であり、これが を保証します。
IPv4 のアドレスは 個しかなく、2011 年に IANA の在庫が枯渇しました。現在は二つの対処が併存しています。一つは 128 ビットに拡張した IPv6、もう一つは NAT(Network Address Translation)で、内部で 192.168.0.0/16 などのプライベートアドレスを使い、外向きには 1 個のグローバルアドレスを共有する方式です。NAT は送信元のアドレスとポート番号を書き換えるため、Definition 5.1 の 4 つ組が経路の途中で変化します。層の独立性を破る仕組みですが、実務では前提として扱う必要があります。クラウド上の VPC も、この private/public の区別の上に構成されています(クラウドコンピューティング の Example 4.1[クラウドコンピューティング] を参照してください)。
5. トランスポート層:TCP と UDP
Section titled “5. トランスポート層:TCP と UDP”5.1. ポート番号による多重化
Section titled “5.1. ポート番号による多重化”IP アドレスはホストを指しますが、1 台のホストでは多数のプロセスが同時に通信します。これを区別するのがポート番号(16 ビット)です。
Definition 5.1(接続を識別する 4 つ組)
TCP の一つの接続は
という 4 つ組で一意に識別されます。到着したセグメントは、この 4 つ組が一致する接続に配送されます。UDP には接続の概念がなく、宛先の 2 つ組(IP とポート)だけで受け取り口が決まります。
サーバは 80 番(HTTP)、443 番(HTTPS)、53 番(DNS)のようなよく知られたポートで待ち受け、クライアントは OS が割り当てるエフェメラルポートを使います。
Example 5.2(1 台のクライアントが張れる同時接続数)
Linux の既定のエフェメラルポート範囲は 32768〜60999 で、 個です。Definition 5.1 より、同一のクライアント IP から同一のサーバ(同じ IP・同じポート)へ張れる同時接続は、送信元ポートが相異なる必要があるため最大 28,232 本です。
さらに TCP は、接続終了後もしばらく TIME_WAIT 状態で 4 つ組を保持します(既定でおよそ 60 秒)。毎秒 本の短命な接続を張り続けると、到着率 ・滞在時間 60 秒に リトルの法則(Theorem 5.1)[クラウドコンピューティング] を当てはめて、定常状態で約 本分が占有されます。よって すなわち 本/秒が上限です。負荷試験で「500 リクエスト/秒あたりから接続エラーが出る」現象の典型的な原因がこれです。対策は接続の使い回し(HTTP の keep-alive、データベースのコネクションプール)で、データベース設計の基礎 で設計する永続データ層へアクセスするときも、この制約は同じように効きます。
TCP と UDP の役割分担を整理します。
| TCP | UDP | |
|---|---|---|
| 接続 | あり(ハンドシェイクが必要) | なし |
| 到達保証・順序保証 | あり(確認応答と再送) | なし |
| 流量制御・輻輳制御 | あり | なし(アプリが実装する) |
| ヘッダ長 | 20 バイト以上 | 8 バイト |
| 向く用途 | HTTP, メール, ファイル転送 | DNS, 音声・映像, QUIC の土台 |
UDP は「機能が足りない」のではなく、必要な機能だけを上に載せるための素材です。HTTP/3 が UDP 上に QUIC を実装するのは、カーネルにある TCP は改良しにくく、再送や輻輳制御をユーザ空間で設計したいからです。
5.2. 3 ウェイハンドシェイク
Section titled “5.2. 3 ウェイハンドシェイク”TCP の接続確立は SYN、SYN+ACK、ACK の 3 通で行われます。クライアントは初期シーケンス番号 を選んで SYN(seq=x) を送り、サーバは自分の初期シーケンス番号 を選んで SYN(seq=y), ACK(ack=x+1) を返し、クライアントが ACK(ack=y+1) を返して確立します。3 通目は冗長に見えますが、そうではありません。
Proposition 5.3(2 ウェイでは接続確立が安全でない)
接続確立を「クライアントの SYN」と「サーバの SYN+ACK」の 2 通のみで完了とし、サーバは SYN+ACK を送った時点で接続を確立済みと見なす方式を考えます。ネットワークがパケットを任意に遅延させて重複配送しうるとき、この方式では、クライアントが接続を望んでいないのにサーバ側だけが接続を確立してしまう実行系列が存在します。
Proof(Proposition 5.3)
次の実行を構成します。
- 時刻 に、クライアント C が
SYN(seq=x)をサーバ S に送ります。このSYNは経路の途中で複製され、片方は正常に届いて接続が確立し、通信を終えて閉じられます。もう片方は、あるルータのキューに滞留したまま残ります。 - C は再起動するなどして、この接続に関する状態をすべて失います。
- 時刻 に、滞留していた複製
SYN(seq=x)が S に到達します。S から見ると、これは正当な新しい接続要求と区別がつきません(SYNの内容は のときと完全に同一だからです)。 - S は接続用の資源を確保し、
SYN+ACKを返し、2 ウェイの規約により確立済みと見なします。以後 S は、この接続でデータを受け取れる状態で待ち、場合によっては自分からデータを送ります。 - C にはこの接続の記録がないので、届いた
SYN+ACKを無視するか破棄します。
結果として、C は何も要求していないのに S 側だけが接続を保持します。これが主張した実行系列です。
3 ウェイならこの実行は成立しません。ステップ 4 で S は確立せず、ack = y+1 を含む ACK を待ちます。 は S がこの試行のために新しく選んだ値なので、 に作られた古いパケットが を含むことはできません。C はこの SYN+ACK に対応する接続を持たないので RST を返し、S は資源を解放します。すなわち 3 回目の ACK は「相手がこの試行を認識していること」の証拠であり、鮮度の検査になっています。この理由から初期シーケンス番号は予測困難でなければならず、現在の実装は乱数に基づいて生成します。
5.3. ウィンドウとスループットの上限
Section titled “5.3. ウィンドウとスループットの上限”TCP は、確認応答(ACK)を待たずに送出できるデータ量に上限を設けます。これをウィンドウと呼び、受信側のバッファ空きを表す広告ウィンドウと、混雑度の推定である輻輳ウィンドウの小さいほうが実効値です。
Proposition 5.4(ウィンドウによるスループットの上限)
送信側の実効ウィンドウが常に バイト以下、往復時間が常に 秒以上であるとします。すなわち、任意の時刻において確認応答が返っていない(未確認の)データ量は バイト以下であり、あるバイトを送出してからその確認応答が届くまでに少なくとも 秒かかるものとします。このとき、時間 に送出できるデータ量 について
が成り立ち、したがって長時間平均のスループットは を超えません。
Proof(Proposition 5.4)
任意の時刻 を取り、半開区間 に送出されたバイトを考えます。仮定より、これらのバイトの確認応答が届くのは送出時刻から 秒以上あとですから、時刻 の時点ではいずれもまだ確認されていません。よってこれらはすべて未確認データに含まれ、その総量は 以下でなければなりません。式で書けば、任意の について
です( は送出済みバイト数の累積、 では とします)。
とおき、この不等式を について足し合わせると、左辺は望遠鏡和になって
を得ます。 かつ は非減少、 なので です。 を代入すれば主張の不等式が従います。両辺を で割って とすれば、平均スループット の上極限は 以下です。
Example 5.5(帯域遅延積とウィンドウスケール)
東京とサンフランシスコの間を ms、回線を 100 Mbit/s とします。TCP ヘッダのウィンドウフィールドは 16 ビットしかないので、拡張しなければ バイトです。Proposition 5.4 より、スループットの上限は
です。100 Mbit/s の回線の 5% しか使えません。
回線を埋め切るのに必要なウィンドウは帯域遅延積(BDP)
で、16 ビットの枠に収まりません。この問題を解くのが RFC 7323 のウィンドウスケールオプションで、接続確立時にシフト量 ()を交換し、以後ウィンドウ値を 倍して解釈します。 なので 倍あれば足り、 以上を選べば回線を使い切れます。
なお、シフト量は SYN でしか交換できず、途中の機器がこれを削除すると、接続はできるのに遅いという診断の難しい状態になります。
Example 5.6(再送タイムアウトの計算)
再送タイマ RTO の値は、RFC 6298 で次のように定められています。新しい RTT の測定値 が得られたとき、、 として
と更新します(RTTVAR の更新に古い SRTT を使う点に注意してください)。
いま ms、 ms の状態で ms が観測されたとします。
平均に 4 標準偏差相当の余裕を足すので、RTT が安定した経路では RTO は平均の 1.1 倍程度、揺らぐ経路では数倍になります。早すぎる再送は輻輳を悪化させるため、TCP は保守的な側に倒しています。
6. アプリケーション層:DNS と HTTP
Section titled “6. アプリケーション層:DNS と HTTP”6.1. DNS — 名前を住所に変える分散データベース
Section titled “6.1. DNS — 名前を住所に変える分散データベース”人間は www.example.com を覚え、IP は 32 ビットの数を要求します。この対応表が DNS です。表は一箇所になく、ドメイン名の階層に沿って権威が分割されています。
Definition 6.1(ドメイン名の階層と権威サーバ)
ドメイン名 www.example.com. は、右端の根(ルート、空ラベル)から左へ com、example、www とたどる木のパスです。各ノードに対して、その配下の情報について正しい答えを返す責任を持つサーバを権威 DNS サーバといい、親のゾーンは子のゾーンの権威サーバを指す NS レコードだけを保持します。名前とアドレスの対応は A レコード(IPv4)、AAAA レコード(IPv6)として保持されます。
クライアント(スタブリゾルバ)は通常、/etc/resolv.conf などで指定されたフルサービスリゾルバに問い合わせるだけです。木をたどるのはリゾルバの仕事で、次の反復問い合わせを行います。
Example 6.2(www.example.com の反復解決)
リゾルバのキャッシュが空だとして、手順を追います。
- ルートサーバ(13 系統のアドレスがあらかじめ設定されています)に
www.example.com の A レコードは?と尋ねます。ルートは答えを知りませんが、「comの権威は次の NS だ」と返します。 comの権威サーバに同じ質問をします。「example.comの権威は次の NS だ」と返ってきます。example.comの権威サーバに同じ質問をします。ここで初めてAレコード(本記事では説明用に203.0.113.10とします)が返ります。- リゾルバは答えをクライアントに返し、同時に各段の応答を TTL(レコードごとに指定された秒数)の間キャッシュします。
段数は 3 段ですが、実運用ではリゾルバがルートと TLD の情報をほぼ常時キャッシュしているため、キャッシュミス時でも往復は 1〜2 回で済みます。逆に TTL を極端に短くすると(たとえば 30 秒)、この往復が毎回体感遅延に上乗せされます。TTL は「切り替えの速さ」と「解決の速さ」のトレードオフです。
手元で同じ手順を再現するには、次のコマンドが使えます。
dig +trace www.example.com ADNS は主に UDP の 53 番ポートを使います。1 往復で終わるため軽く、失われたら再送すればよいからです。ただし応答が 512 バイトを超えると、EDNS0 で大きなサイズを許可するか TCP に切り替える必要があります。DNSSEC の署名を含む応答は大きくなりやすく、障害の起きやすい部分です。
6.2. HTTP — テキストの要求と応答
Section titled “6.2. HTTP — テキストの要求と応答”HTTP は単純なプロトコルです。クライアントは「メソッド、対象、バージョン」からなるリクエスト行と 名前: 値 の形のヘッダ行を送り、空行のあとに本体を置きます。サーバはステータス行とヘッダ、空行、本体を返します。次のコードは Python の標準ライブラリだけで HTTP/1.1 のリクエストを組み立て、応答ヘッダを表示します。
import socket
request = ( "GET / HTTP/1.1\r\n" "Host: example.com\r\n" "User-Agent: rikai-demo/1.0\r\n" "Connection: close\r\n" "\r\n")
with socket.create_connection(("example.com", 80), timeout=5) as sock: sock.sendall(request.encode("ascii")) chunks = [] while True: data = sock.recv(4096) if not data: break chunks.append(data)
response = b"".join(chunks)header, _, body = response.partition(b"\r\n\r\n")print(header.decode("ascii", errors="replace"))print(f"body: {len(body)} bytes")Host ヘッダは HTTP/1.1 で必須です。1 つの IP アドレスで複数のドメインを提供する(バーチャルホスト)ために、どのサイト宛かをアプリケーション層で伝える必要があるからです。Connection: close を外すと、サーバは接続を維持したまま次のリクエストを待ちます(keep-alive)。ステータスコードは 3 桁で、2xx は成功、3xx はリダイレクト、4xx はクライアント側の誤り、5xx はサーバ側の誤りを表します。
| バージョン | 下位プロトコル | 主な変更点 |
|---|---|---|
| HTTP/1.1 (1997, RFC 9112) | TCP | 持続接続、Host ヘッダ必須、チャンク転送 |
| HTTP/2 (2015, RFC 9113) | TCP + TLS | ヘッダ圧縮(HPACK)、1 接続上のストリーム多重化 |
| HTTP/3 (2022, RFC 9114) | QUIC (UDP + TLS 1.3) | ストリームごとの独立再送、接続確立の 1-RTT 化 |
HTTP/2 の動機は、HTTP/1.1 のヘッドオブラインブロッキングです。1.1 では 1 本の接続で 1 リクエストずつしか処理できず、ブラウザは同一ホストに 6 本程度の TCP 接続を張って並列化していました。HTTP/2 はこれを 1 本の接続上のストリーム多重化で解消します。ただし土台が TCP である限り、1 つのパケットが失われるとその後ろのすべてのストリームが待たされます。HTTP/3 が UDP に移ったのは、この待ち合わせを消すためです。
7. URL を入力してからページが表示されるまで
Section titled “7. URL を入力してからページが表示されるまで”ここまでの各層を 1 本の時系列に並べ、https://www.example.com/ を入力してから HTML が届くまでを追います。
sequenceDiagram participant B as ブラウザ participant R as フルサービスリゾルバ participant S as Web サーバ B->>R: www.example.com の A レコードは? R-->>B: 203.0.113.10 (TTL 300) B->>S: SYN seq=x S-->>B: SYN seq=y, ACK x+1 B->>S: ACK y+1 B->>S: TLS ClientHello + 鍵共有 S-->>B: ServerHello + 証明書 + Finished B->>S: Finished(以後は暗号化) B->>S: GET / HTTP/1.1, Host: www.example.com S-->>B: 200 OK + HTML 本体 B->>B: HTML 解析、CSS/JS/画像の追加取得へ
順に見ます。
- URL の解析。 スキーム(
https)、ホスト(www.example.com)、ポート(省略時は 443)、パス(/)に分解します。国際化ドメイン名は Punycode に変換されます。 - 名前解決。 ブラウザ内キャッシュ、OS のキャッシュ、
hostsファイル、フルサービスリゾルバの順に問い合わせます。Example 6.2 の手順でA/AAAAレコードが得られます。キャッシュに当たれば往復は 0 回、外れれば 1〜2 回です。 - TCP 接続の確立。 得られた IP アドレスの 443 番ポートに 3 ウェイハンドシェイクを行います(Proposition 5.3)。データを送れるまで 1 往復です。送信元は自ホストのエフェメラルポートで、接続は Definition 5.1 の 4 つ組で識別されます。
- TLS ハンドシェイク。 TLS 1.3 では ClientHello に鍵共有の材料を載せるため、1 往復で鍵が確立します(TLS 1.2 では 2 往復必要でした)。サーバ証明書の検証もここで行われます。
- HTTP リクエストとレスポンス。
GET / HTTP/1.1を送り、200 OKと HTML を受け取ります。これで 1 往復です。 - 描画と追加取得。 HTML を解析しながら CSS・JavaScript・画像を追加取得します。この段階で 2〜5 の一部が別ホストに対して繰り返されます。
Example 7.1(往復回数から所要時間を見積もる)
RTT を ms、DNS はキャッシュミス(リゾルバは TLD をキャッシュ済みで 1 往復)、TLS 1.3、HTML は 1 パケットに収まるとします。Example 2.3 で見たとおり送信遅延は無視できるので、往復回数だけを数えます。
| 段階 | 往復数 | 所要時間 |
|---|---|---|
| DNS 解決 | 1 | 80 ms |
| TCP 3 ウェイハンドシェイク | 1 | 80 ms |
| TLS 1.3 ハンドシェイク | 1 | 80 ms |
| HTTP リクエスト/レスポンス | 1 | 80 ms |
| 合計 | 4 | 320 ms |
2 回目以降のアクセスでは、DNS が TTL の間キャッシュされ、TCP 接続も keep-alive で再利用されるため、HTTP の 1 往復(80 ms)で済みます。初回 320 ms、2 回目 80 ms という 4 倍の差が、往復回数の数え上げだけから出てきます。
改善の方向も読めます。CDN で物理距離を縮めれば 自体が下がり(80 ms から 10 ms へ)、全段が同じ比率で速くなります。HTTP/3 なら TCP と TLS のハンドシェイクが統合されて 1 往復減ります。逆に、サーバの処理を 10 ms 速くしても全体の 3% です。どこを直すべきかは、この表を作ってから決めてください。
IPv4 アドレス 198.51.100.200 が、プレフィックス長 26 のブロックに分割された空間の中でどのブロックに属するかを求め、そのブロックのネットワークアドレス、ブロードキャストアドレス、ホストに割り当て可能なアドレス数を答えてください。
Solution
プレフィックス長 26 のブロックが含むアドレス数は 個です。したがって第 4 オクテットは 0〜63、64〜127、128〜191、192〜255 の 4 ブロックに分かれます。 は最後のブロックに入ります。実際、 であり、上位 2 ビット(第 26 ビットまでに含まれる部分)は 、これは の上位 2 ビットと一致します。
- 所属ブロック:
198.51.100.192/26 - ネットワークアドレス:
198.51.100.192 - ブロードキャストアドレス:
198.51.100.255 - 割り当て可能なホスト数: 個
帯域 1 Gbit/s、RTT 60 ms の経路があります。
(1) この経路を埋め切るのに必要なウィンドウサイズ(帯域遅延積)をバイト単位で求めてください。 (2) ウィンドウスケールを使わない場合( バイト)の最大スループットを求めてください。 (3) 経路を埋め切るために必要な最小のウィンドウスケール係数 (ウィンドウ値を 倍する)を求めてください。
Solution
(1) 帯域遅延積は
すなわち 7.5 MB です。
(2) Proposition 5.4 より上限は
回線の 0.87% しか使えません。
(3) 必要な倍率は です。、 なので が最小です。このとき表現できる最大ウィンドウは バイトで、7.5 MB を上回ります。
長距離・広帯域の経路(long fat network)では、送受信バッファの設定が決定的に効きます。OS のバッファ上限が 4 MB なら、ウィンドウスケールを有効にしても実効ウィンドウは 4 MB で頭打ちになり、 Mbit/s しか出ません。
ある TCP 接続で ms、 ms の状態にあります。次の RTT 測定値が ms でした。RFC 6298 の更新式(Example 5.6 参照、、)に従って、更新後の SRTT、RTTVAR、RTO を求めてください。
Solution
更新の順序が重要です。RTTVAR を先に、古い SRTT を使って計算します。
次に SRTT を更新します。
最後に RTO を求めます。
測定値が平均より 60 ms 小さかったのに、RTO は更新前の ms からわずかに増えて 402.5 ms になりました。RTTVAR は平均からのずれの大きさを追うので、上下どちらにぶれても増えるためです。なお RFC 6298 は RTO の下限を 1 秒と定めており、実装によってはこの値は 1 秒に丸められます。
1 つのホストから 100 個の小さなリソース(各レスポンスは 1 パケットに収まるとします)を取得します。RTT は 80 ms、TLS 1.3 を使い、サーバの処理時間と送信遅延は無視します。
(1) HTTP/1.1 で同一ホストへ 6 本の TCP 接続を並列に張り(パイプラインは使わない)、各接続でリクエストを 1 つずつ順に処理する場合、全リソースの取得完了までの時間を見積もってください。接続確立にかかる時間も含めてください。 (2) HTTP/2 で 1 本の接続に 100 個のリクエストを多重化する場合の時間を見積もってください。 (3) HTTP/3 を使うと (2) はどう変わりますか。
Solution
(1) 6 本の接続はすべて並列に張れるので、確立にかかるのは 1 本分の時間です。TCP の 3 ウェイハンドシェイクで 1 往復、TLS 1.3 で 1 往復、合わせて ms かかります。
その後、100 個のリクエストを 6 本に振り分けます。1 本あたりのリクエスト数は最大 個で、各リクエストは 1 往復ずつ順番に処理されるので ms です。合計は
となります。
(2) 接続確立は 1 本分で同じく 160 ms です。多重化により 100 個のリクエストを一度に送れるので、応答が返るのは 1 往復後、80 ms です。合計は
です。(1) の約 倍の高速化になります。
(3) HTTP/3 の土台である QUIC は、トランスポートの接続確立と TLS 1.3 の鍵交換を 1 往復に統合します。確立が 160 ms から 80 ms に減り、合計は ms です。さらに同じサーバに以前接続していれば 0-RTT 再開が使え、理論上は 80 ms まで縮みます。
遅延支配的な環境では往復回数がほぼすべてを決めます。 (1) の 1520 ms のうち 1360 ms、89% は「順番待ち」であり、帯域とは無関係です。
- Kevin R. Fall, W. Richard Stevens, TCP/IP Illustrated, Volume 1: The Protocols, 2nd ed., Addison-Wesley, 2011 — リンク層から HTTP まで、実際のパケットを見ながら追う定番。第 3 章(リンク層)、第 5 章(IP)、第 12〜17 章(TCP)。
- James F. Kurose, Keith W. Ross, Computer Networking: A Top-Down Approach, 8th ed., Pearson, 2020 — 本記事と同じくアプリケーション層から降りていく構成。第 1 章(遅延の分解)、第 3 章(トランスポート層)。
- V. Cerf, R. Kahn, “A Protocol for Packet Network Intercommunication”, IEEE Transactions on Communications 22(5) (1974), 637–648 — TCP/IP の原論文。
- RFC 9293, Transmission Control Protocol (TCP), 2022 — TCP の現行仕様(RFC 793 を置き換えたもの)。https://www.rfc-editor.org/rfc/rfc9293
- RFC 6298, Computing TCP’s Retransmission Timer, 2011 — Example 5.6 の更新式の出典。https://www.rfc-editor.org/rfc/rfc6298
- RFC 9110, HTTP Semantics, 2022 — メソッド・ステータスコード・ヘッダの現行定義。https://www.rfc-editor.org/rfc/rfc9110
- RFC 1035, Domain Names — Implementation and Specification, 1987 — DNS のメッセージ形式とレコード型。https://www.rfc-editor.org/rfc/rfc1035
Appendix: インターネットチェックサムが見逃す誤り
Section titled “Appendix: インターネットチェックサムが見逃す誤り”チェックサムの定義。 IP・TCP・UDP のヘッダには 16 ビットのチェックサムがあります。その計算法(RFC 1071)は、対象データを 16 ビット語 に区切り、1 の補数和
を求め、その 1 の補数 を送るというものです。ここで は、 を計算して 16 ビットからあふれたキャリーを最下位に巡回加算する演算です。受信側は を含めた全語の和を取り、結果が全ビット 1 になることを確認します。
この演算は見かけより単純な代数的意味を持ちます。
補題(1 の補数和の正体)。 と を同一視すると、 は の加法と一致します。実際、 のとき であり、これは から を引くこと、すなわち法 での還元です。 のときは でそのままです。よって は法 の加法であり、とくに可換かつ結合的です。
Proposition 8.5(インターネットチェックサムが検出できない誤り)
チェックサムの対象となる 16 ビット語の列 に対して、次の二種類の改変はチェックサムを変化させず、したがって検出できません。
- 語の順序の入れ替え。すなわち任意の置換 に対する 。
- 相殺する誤り。すなわち、ある と について を に、 を に変える改変( は の逆演算)。
Proof(Proposition 8.5)
補題より、 は法 での和 に等しく、 は可換かつ結合的です。
1 について。有限個の元の和は加える順序によらないので、 です。よって は不変で、チェックサムも変わりません。
2 について。改変後の和は
であり、 の項が打ち消し合います。よってこれも検出されません。
実務上の意味。 1 の帰結として、機器のバグでパケット内の 2 バイト境界のブロックが入れ替わってもチェックサムは通ってしまいます。実測に基づく報告として、Stone と Partridge の研究(“When the CRC and TCP Checksum Disagree”, ACM SIGCOMM 2000)は、TCP チェックサムを通過した誤りが数千〜数万パケットに 1 回の割合で存在しうると論じています。
データの完全性が重要な場面では、アプリケーション層で SHA-256 などのハッシュ検証を行ってください(偶然の衝突が事実上起きないことの見積もりは 誕生日境界による上界(Proposition 2.2)[Git] にあります)。TCP が保証するのは「多くの偶発的な誤りを高い確率で捨てること」であって「届いたデータが正しいこと」ではありません。層が保証する内容を過大評価しないことも、階層モデルを正しく使うことの一部です。
Report an error in this article ・Operated by: Mugen Giken LLC ・Pricing ・Terms ・Legal notice
© 2026 夢現技研合同会社 ・Feeding the text to an LLM is welcome. Code samples are MIT licensed.