寒月記

住みにくいところをどれほどか寛容て

『ネットワークはなぜつながるのか』読書記録:第1章 Web ブラウザがメッセージを作る

 第一章では, ブラウザに URL を入力してから, HTTP リクエストメッセージが作られて OS 経由で名前解決をし, Webサーバにリクエストを送るまでを解説しています。上のレイヤーを中心にした話で, TCP/IP などが出てくるのは次の章などになっています。

 なお, 記載内容はわたしの理解・解釈を通してますので, 誤りがあればおそらくわたしに帰属するものです。
そうしたものがあれば, お手数ですがご指摘いただけると幸いです。

本章の内容概略

  1. ブラウザが URL を解釈して HTTP リクエストメッセージを作成
  2. ブラウザがリクエスト先である Web サーバの IP アドレスを DNS サーバ (ネームサーバ) に問い合わせる
  3. 世界中の DNS サーバが連携して 2 で問い合わせのあった IP アドレスを探す = 名前解決
  4. ブラウザが DNS サーバから Web サーバの IP アドレスを受け取り, OS のプロトコルスタックに HTTP リクエストメッセージ送信を依頼
    • Web サーバが用意しているデータ送受信口 = socket にプロトコルスタックが接続してデータ送受信経路を作る
  5. Web サーバが HTTP リクエストに従って HTTP レスポンスメッセージを作り, クライアント = Web ブラウザに送り返す
  6. ブラウザが HTTP レスポンスを受け取ったらその内容に応じて描画などし, ユーザーは目的のコンテンツを閲覧・取得できる
  7. データ送受信が終わったら socket の接続 = コネクションを切断して終了

このうちいくつかピックアップして書いていきます。

ネットワークはなぜつながるのか 第2版 知っておきたいTCP/IP、LAN、光ファイバの基礎知識

ネットワークはなぜつながるのか 第2版 知っておきたいTCP/IP、LAN、光ファイバの基礎知識

1. HTTP リクエストメッセージの作成

 Web は基本的に HTTP (Hypertext Transfer Protocol) でやり取りをする設計となっています。
このため, まずはこちらの要求 = リクエストを HTTP の形で表現する必要があり, それを代行してくれるのがブラウザの機能の一つです。

 普段私たちが「インターネット」を使うときは, 検索サービスの結果からリンクをクリックしたり, ブックマークから直接飛んだり, まれにブラウザのアドレスバーに直接 URL を打ち込んだりしますが, これらはすべて内部的には同じ処理が走っており, 「ブラウザが URL を解釈し, それを基に HTTP リクエストメッセージを作って OS に送信を依頼する」というものとなっています。

HTTP とは

 ところで HTTP とはなんでしょうか。

 これは通信プロトコル, すなわち 通信をするときの約束事 の一種です。
プロトコルの理解としては, 卑近な例では郵便を考えると分かりやすいかと思います。

プロトコルについて:郵便の喩え

はがきや荷物を送るとき, 「A さん宛」などとはがきや伝票に書くだけでは届けてもらえない。郵便プロトコル = 約束事 として, 「郵便番号」「住所」「宛先の氏名や組織名」などが最低限記載すべきものとして決まっている。このプロトコルを守っていないものは郵便局や運送業者が解釈してくれないので, 送り手の意図した宛先に届くことはない

郵便も広義では通信プロトコルの一種と言えると思うので, 「プロトコル」の理解には, 上のような喩えが分かりやすいのではないでしょうか。

 話を戻すと, HTTP は, Web*1 上でテキストデータをやり取りするときのプロトコルです。普段ブラウザで見ているページは, 主に HTML ファイル, 画像ファイル, css や js などのファイルから成りますが, これらも突き詰めればテキスト, ひいては 2進数で表現されるものです。

 したがって, HTTP という約束事, 作法に従って通信をすることで, Web 上でコンピュータ間のデータのやり取りが実現できる, ということになります。
 逆に言えば, プロトコルに従わないはがきが相手に届けてもらえないように, HTTP に従わないフォーマットや方法でデータを送ろうとしても, HTTP の枠組みの中で通信をしようとしている限り相手にデータは届かない, 通信できない, ということになります。

 HTTP の必要性がピンと来ない場合は, もし「HTTP で通信をするという約束事がなかったら」を考えてみると分かりやすいと思います。
 もしこうした取り決めがないと, 世界中のコンピュータがそれぞれ好き勝手な方法でやり取りをしようとしますが, 送り手と受け手でメッセージやり取りの方法の合意が取れていないと, やり取りはできないですよね。
 モールス信号を知らない人にいぽぷ的にモールス信号を送っても, ただのトン・ツーでしかなく, 目的である「情報を伝えるための通信」は達成できません。
 Web の世界も同じで, こうした混乱や非効率が生じないよう, 世界的に統一規格である HTTP を策定した, ということと思います*2

2. Web サーバの IP アドレスを DNS サーバに問い合わせる

 少し脱線してしまいましたが, リクエスト送信先の URL をブラウザに渡すと, ブラウザが HTTP リクエストメッセージを作ってくれる, ということまではわかりました。
次はこのメッセージをネットワークを通じて送信しなければいけないのですが, 実はブラウザはネットワーク越しにメッセージを送信する機能は持っていません。これは, 「ネットワーク通信」という機能はブラウザに限らず様々なアプリケーションが必要とするものなので, それぞれのアプリでネットワーク通信機能を実装するより, 共通基盤である OS に任せる方が効率的なためです。

 ということで, ブラウザはメッセージの送信を OS に依頼します。
 ところが, ここでまた問題が発生します。
ブラウザは送信先の URL はわかるのですが, コンピュータは効率性の観点から, URL という長い文字列そのままをネットワーク通信で利用することはしないのです。
 したがって, URL をコンピュータが通信相手の識別に使うフォーマット, IP アドレス に変換 = 名前解決 する必要があります。
IP アドレスは, 現在主に利用されている IPv4 では 0.0.0.0 ~ 255.255.255.255 の 2554 = 4,228,250,625通りのアドレス から, 特殊な意味を持つアドレスいくつかを除いた数分使うことができます*3

3. 名前解決までの流れ

 この名前解決を専門にするサーバが, DNS (Domain Name System) サーバ と呼ばれるものです。
DNS サーバは世界中に多数存在し, これらが協力・役割分担し合って名前解決を実現しています。

ところで, ここで URL をしっかり見てみましょう。
例えば, http://server.example.com という URL にリクエストを送る場合を考えます*4
先ほど DNS サーバは階層的になっていると書きましたが, ということはつまり DNS サーバが解決する URL も階層的になっているということです。
URL は通常 . で区切られていて, 後ろの方から順に上の階層になっています。
http://server.example.com では, com ドメインの中の example ドメインの中の server を表している, というかたちです。

つまり名前解決も上の階層から順に行われていきます。
ここでも注意が必要なのですが, 普段は省略されているけれども実は URL の末尾にはもう一つ . が必要です。
すなわち, http://server.example.com. が正式な形です。
この末尾の . をルートドメインと呼び, これが最も上の階層のドメインです。
これに相当する一番上の階層の DNS サーバ, すなわちルート DNS サーバから順に問い合わせが始まり, ルート DNS サーバがトップレベルドメイン, .com.jp などの IP アドレスを管理する DNS サーバの所在を伝えてくれます。
あとは一番下のサーバ名 (例では server) まで, 順にこれを繰り返して最終的に IP アドレスを知ることができます。

ちょっと意外かもしれませんが, このように名前解決は, 一度でズバッと解決されるのではなく, 順にたらい回しのような形で行われます。
しかし, 必ずしもこのたらい回し的名前解決が毎回行われるわけではありません。
そもそも, 元々の問い合わせ元であるブラウザは, どの DNS サーバに問い合わせをしているのでしょうか。

直感通り, 上のような名前解決を毎回行うのは非効率なので, ブラウザなどの DNS クライアントは, まずは最寄りの DNS サーバに問い合わせをします。
この「最寄りの DNS サーバ」は大抵自動で取得するような設定になっていますが, 社内 LAN などを利用している場合は明示的に指定することが多いと思います。
この「最寄りの DNS サーバ」が, 過去の問い合わせ結果のキャッシュも含めて*5問い合わせられた URL を知っていればそこで名前解決は終わり, 知らなければそこからはその「最寄りの DNS サーバ」がルートドメインから順に問い合わせを代行してくれます。

この「最寄りの DNS サーバ」をキャッシュ DNS サーバ, そして初めの説明で登場した階層的になっている DNS サーバ達を権威 DNS サーバと呼びます*6

ブラウザから依頼を受けた OS がキャッシュ DNS サーバに問い合わせを行い, そこで解決できなければ, 今度はキャッシュ DNS サーバが権威 DNS サーバに順に問い合わせを行って名前解決を行う, ということとなります*7

※2019/8/5 追記:dig を使って再帰的名前解決の様子を見てみました

www.kangetsu121.work

4. OS のプロトコルスタックにメッセージの送信を依頼

 これまでで, HTTP リクエストメッセージの作成, 送信先サーバの名前解決ができました。
次はいよいよ, メッセージを送信します。

 既に書いた通り, HTTP リクエストメッセージを作成したブラウザ自身は, ネットワーク越しにデータを送受信する機能を備えていません。
このため, ブラウザは OS の API (systemcall) を呼び出して, メッセージの送信を依頼します。

 なお, このデータ送受信では注意が必要で, データは海を越えてやり取りが行われることも珍しくありません。
そうでなくても, データは結局, 電気信号や光だったりするわけで, それらも長い道のりの中でノイズが混入したり, 一部欠損することも珍しくないでしょう。
 このため, ただデータを授受するだけでなく, それらデータが「ちゃんと届いたか」を確かめ合って保証する仕組みも必要です。
これに一役買うのが Socket です。
通信開始時, クライアントとサーバはそれぞれが Socket を用意し, それを接続してコネクションを作ります。
コネクションがあるおかげで, ひとまとまりのデータのやり取りを同じソケットを介して行える, すなわちソケットに各種の通信制御情報を記録できるので, 通信の完全性を保証できる仕組みとなっているのだと思います。

まとめ

 以上,, 第一章はブラウザが URL を受け取ってから, リクエストメッセージを送信するまでにどんなことが起きているか, を主に見ることができました。
後半のソケットの当たりなどは自分の理解が怪しいかもしれないので, お気づきの点はなにとぞご指摘いただければ。
本章で大事だと思う点を絞るなら,

  • データ送受信という, アプリケーションが共通して使うであろう機能は OS 側が担っている
  • DNS サーバによる名前解決の仕組み

かと個人的には思います。

この記事を書いていて調べたいことがどんどん増えているので, 補足記事としてそちらもまとめたいと思います。

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

*1:厳密には違うが, Web という表現が分かりにくければインターネットと解釈すれば大抵大丈夫です

*2:HTTP の仕様書に当たるものとして RFC 3986 (https://www.rfc-editor.org/rfc/rfc3986.html) があります。私もまだ読めてませんが, 近いうちにちゃんと読んでみたいです

*3:厳密に言えばこの文脈ではグローバル IP アドレスを意図しています。また, IPv4 のアドレスは既に枯渇しているらしく, IPv6 への移行が進んでいるという話を聞きます

*4:example.com は RFC 2606 (https://www.rfc-editor.org/rfc/rfc2606.html) で例示用のセカンドレベルドメインとして定義されています

*5:サーバリプレースなどで URL:IP アドレスの対応が変わった場合は, この社内 DNS のキャッシュが問題になることがあります。ちゃんと flush したりしておかないと, 過去の名前解決結果のキャッシュを参照して, もう存在しないリプレース前のサーバのアドレスを返してしまったりします

*6:また, 「名前解決を行うクライアント」という役割から見たときは, キャッシュ DNS サーバに問い合わせを行う OS などを スタブリゾルバ, 権威 DNS サーバに問い合わせを行うキャッシュサーバを フルリゾルバ と呼びます

*7:この名前解決の様子は Linux なら dig コマンドなどで終えます, 後でまとめてみます -> まとめました