&応用情報を受験して、今年4月にはネットワークスペシャリストを受験してみる予定です。資格自体が欲しいというよりは、基礎体力をつけるために勉強したく、期限と強制力を持たせるために試験を活用しようと考えています。ネットワークスペシャリスト教科書」などを読んでみました。勉強を進め知っていることが増えていくに従い、詳細に気を取られ全体が見えなくなってきてしまっていました。そこで、「木を見て森を見ず」な状態を脱却するために一度全体の大きな流れを掴んでから、再度詳細を勉強した方が効率が良いのではないかと思い、擦られ倒した話題ではあるものの、「URLがアドレスバーに入力されてからWebページが表示されるまで」の流れをまとめていこうと思った次第です。今回は、この順番でまとめていければと思います。詳細を読む中で、全体のどこにいるのかがわからなくなったら、再度この構成を見ていただければと思います。*本来各大項目毎に本が何冊も書けるレベルで情報量が多いはずですが、今回は全体の流れを掴むことが目的なので、詳細や一部項目は省略しております。*使っているOSやブラウザなどによって異なる項目もございます。それでは早速、URLを入力してからサーバーにデータが届くまで、往路の説明をこれからしていきます。URL解析アドレスバーにはURLではない検索文字列を打ち込むこともできるし、URLを打ち込むこともできます。そのため、まずはアドレスバーに打ち込まれた文字列を解析して、URLであれば続く処理を、文字列であれば検索ブラウザを呼び出す処理をしていきます。今回はテーマに沿ってURLが打ち込まれた例を考えていきます。https://blog.shgnkn.io/from-typing-url-to-rendering-contents-in-your-browser/という、このブログのURLがあります。このURL文字列は複数の要素で成り立っており、ブラウザ内部では以下のように分解されます。プロトコルを表します。後に続く文字列がサーバーの名前であることを表します。データがあるパス名です。これらの情報をもとに、HTTPリクエストを作成したり、必要に応じて暗号処理モジュールを呼び出して暗号化処理をしたりしていきます。この際に、対象リソースのキャッシュをブラウザが保有しており、サーバーにHTTPリクエストを送信する必要がない場合には、以下の手順は飛ばして最後のブラウザへの表示を開始することができます。HTTPリクエストメッセージの作成URLの解析が完了して、サーバーへの問い合わせが必要なことがわかったら、次はHTTPリクエストメッセージを作成していきます。リクエストメッセージにはルールが決められており、それに従ってブラウザは以下のような形式のリクエストメッセージを作成していきます。・<空白行><メッセージボディ>最初の行がリクエストヘッダで、どのメソッドをどのリソースに対してどんなプロトコルでリクエストを出したいのか指定します。その後複数行のメッセージヘッダーで、コンテンツの種類や圧縮の形式など、必要な情報を付与していきます。メソッドがPOSTの場合には、メッセージヘッダーの後に1行空白行を開けてからメッセージボディが続きます。ここには、/sample/samle.phpに渡したいデータなどを記載します。メッセージをご確認ください。ブラウザはURLを解析して、HTTPリクエストメッセージを作成することまでできますが、メッセージをサーバーに向けて送信する機能は持ち合わせていません。そのため、作成したメッセージをサーバーに向けて送信する作業はOSに依頼していきます。OSが依頼を受け取ってからは、TCP/IPなどさまざまなプロトコルが共同で作業をしていくことになります。全体の流れとしてはOSI参照モデルに沿って順番にデータが流れていくのですが、一部階層の異なるプロトコルが互いにやりとりをして進む処理もあるため、今回のまとめでは厳密に切り分けずに進めていきたいと思います。DNSサーバーへの問い合わせURLを解析して、宛先ドメインはわかりましたが、宛先IPアドレスはまだわかっていません。ブラウザがドメインとIPアドレスのペアをキャッシュとして保有している場合には、DNSサーバーに問い合わせする必要がなくなるので、以下のプロセスは飛ばして、「4.TCPコネクション確立」に進むことができます。ブラウザがキャッシュを保有していない場合には、DNSサーバーと通信してドメインからIPアドレスを取得する必要があります。その際に、SocketライブラリのDNSリゾルバを用いて通信を進めていきます。イメージとしては、今回まとめているブラウザとサーバーの関係がDNSリゾルバとDNSとで成り立っていると考えていただけると分かりやすいかと思います。Socketライブラリについて少し補足すると、SocketライブラリはOSに組み込まれているネットワークと通信するためのライブラリです。これからの説明でも、Socketライブラリの他のメソッドが登場していきます。問い合わせを行い、ドメインからIPアドレスを取得するのですが、実際の通信はDNSリゾルバではなく、OS組み込みのプロトコル・スタックが行います。DNSリゾルバがリクエストメッセージを作成しプロトコル・スタックを呼び出して、DNSサーバーへの問い合わせをプロトコル・スタックに依頼するイメージです。この際に「DNSサーバーのIPアドレスはどうやって調べるんだ?」という疑問が出るかと思うのですが、DNSサーバーのIPアドレスは、PCのTCP/IPの設定であらかじめ設定してあるので、特にどこかに問い合わせたりする必要がないのです。ちなみに、DNSサーバーへの問い合わせはTCPではなくUDPで行われます。問い合わせに使うパケットは1つしかないので、万が一通信に失敗してもDNSサーバーからのレスポンスが返って来なかったら失敗と判断することが可能で、わざわざ面倒な接続手続きをしてTCPを活用するよりも効率が良いからです。DNSサーバーは階層構造で世界中にたくさんあるので、自分が問い合わせしたドメインのIPアドレスが格納されているDNSサーバーに問い合わせるまでにはもう少し道のりがあるのですが、今回は簡略化のために詳細は割愛します。宛先IPアドレスがわかったら、次はサーバーに向けてHTTPリクエストメッセージを送信するための準備をしていきます。ここでも、DNSサーバーに問い合わせを行った時のように、Socketライブラリを活用しOSのプロトコル・スタックを呼び出して実際の処理を行っていきます。イメージとしては、データを流すためのパイプラインを通信の最初に確立して、そこにデータを流していくイメージです。以下の手順で処理をしていきます。サーバーとクライアント双方でそれぞれソケットを作成するクライアント側のソケットからからサーバー側のソケットにパイプを伸ばす(ソケットを接続する)実際のデータ送受信を行う最後にパイプを外すこのパートでは、データの送受信の手前までそれぞれ詳細を見ていきます。ソケット作成ソケットは実態を持っているわけではなく、宛先IPアドレス、送信元IPアドレス、ポート番号などを保持しているメモリ領域にすぎません。プロトコル・スタックはこれらの情報を確認して、どの宛先に対してデータを送信するのかなどを把握しています。クライアント側、サーバー側ではそれぞれソケットが作成されるタイミングが異なります。【クライアント側】Socketライブラリからsocketを呼び出して、socketがプロトコル・スタックを呼び出して、プロトコル・スタックがソケットを作成します。ソケットを作成すると、ディスクリプタというソケットの識別子が生成されるので、ソケット内部に保存しておきます。この際にデータの送受信で必要となるバッファメモリの確保も行っておきます。【サーバー側】サーバーを立ち上げた際にクライアント側と同じ手順でソケットが作成されるようになっています。サーバー側では、ソケットを作成したら、接続待ち状態でクライアントからの接続依頼が来るのを待ちます。ソケット接続ブラウザはサーバーのIPアドレスなどの情報を持っていますが、プロトコル・スタックはそれらの情報を持っていません。そのため、ソケット同士をSocketライブラリのconnectを呼び出すことで接続して、プロトコル・スタックに通信で必要になる情報を知らせてやる必要があります。サーバーも然りで、ソケットがあるだけではどのクライアントと接続したらいいのかわからないので、接続動作をする際に、クライアントからクライアントのIPアドレス&ポート番号をサーバー側に知らせてやる必要があります。本物のパイプのように物理的な何かを生成するわけではなく、IPアドレスなど制御情報のやりとりを行うことをソケットの接続とよんでいます。流れは以下の通りです。handshake」と呼ばれています。*以降説明を省略しますが、Socketライブラリのメソッドを呼び出した際には、そのメソッドがプロトコル・スタックに実際の処理を依頼して、プロトコル・スタックが処理は行っていると解釈してください。送信元、宛先のポート番号を入れる。これでどことどこが通信するのかわかるコントロールビットのSYNを1にするその他もろもろ設定して、TCPヘッダーをIP担当部分に渡す。実際の通信はIP担当部分の仕事IP担当がネットワークにパケットを流して、サーバーのIP担当が受け取るサーバーのIP担当はTCP担当に渡して、TCPはTCPヘッダーの中身を見る。ポート番号コントロールビットのSYNは1ACK番号は初期シーケンス番号+1但しコントロールビットのACKは1ここがややこしいので注意。確認番号とコントロールビットは同じACKでも別もの。TCPヘッダーをIP担当に渡してネットワークに流すクライアントは受け取ったら、SYNが1かどうか確認。1なら接続成功なので、ソケットにサーバーのIP、ポート、などを記載して、接続完了を示す制御情報もソケットに書き込んでおく。サーバーにACKを1にしたTCPヘッダーを送り返して、接続完了を伝える。クションが確立された状態になり、データを流すことが可能。Socketライブラリのcloseを実行するまでコネクションは確立された状態になる。今回の説明では、「IP担当」という言葉が複数回にわたって登場しましたが、この詳細は後ほど説明していきます。ここでは、TCP/IPプロトコルを用いて制御情報のやりとりを行い、クライアント側、サーバー側それぞれのソケットに対して制御情報をセットしていく作業がソケット接続に当たるのだな。理解していただければOKです。データの送信ソケットの接続が完了したら、アプリケーションに処理が戻ります。次は、アプリケーションがSocketライブラリのwriteを呼び出し、送信データをプロトコル・スタックに渡してデータの送信処理が始まります。バッファにデータを貯めてから流すことで、効率の良い通信を行っています。逆に、データサイズが大きすぎてMSS(マックス送信できるデータ量、MTUからヘッダー分を引いたもの)を超えるものに関しては送信用バッファから分割して送信するようにします。送信する際に、制御情報から送信元ポート番号や宛先ポート番号などを書き込んだTCPヘッダーを付与して、IP担当部分に渡し、IP担当部分がIPヘッダーやイーサネットのMACヘッダーなどを付与して送信を行います。IP担当の処理は、ソケット接続を行った時と同じでやっていることは共通しているので、後ほどまとめて説明していきます。TCPプロトコルが信頼性担保TCPプロトコルは通信の信頼性を担保して、他のプロトコルが信頼性のことは気にしなくても済むようにしています。具体的な方法としては、以下の手順で信頼性を担保しています。受信側はシーケンス番号とパケットのサイズから何バイト目から始まるデータが何バイト届くのかがわかる受信側でパケットに抜けがないか確認することが可能になる。受信側は、何バイト目まで受信完了したのかをTCPヘッダーのACKに書き込んで送信側に知らせる送信側もどこまで正確に送ることができているのかわかる。ACKが正しく返ってこなかったら再送するが、何回か再送してダメだったら諦めてアプリケーションにエラーを返す*シーケンス番号は1から始まるのではなく、乱数で設定されます。ソケット接続時に、シーケンス番号の初期値をクライアントで設定してTCPヘッダーに付与することでサーバー側に渡しています。ACKが帰ってこなくても連続してデータを送信できるようにしています。することでACKの返答待ちをしなくてもパケットを送信することができる&ACKパケットが減ることで通信効率を上げることができます。データ送信処理詳細これまでの説明の中で「IP担当に依頼して〜」のような形でお茶を濁してきた部分の詳細を説明していきます。ここまでお茶を濁してきた理由としては、IPプロトコル、正確にはIP以下のプロトコルで行っている通信はデータの中身や目的によらず共通で、基本的にはあるデータを目的地まで届けるということを行っているので、後からまとめて説明した方が全体の流れを追いやすいと考えたためでした。ここから、IP担当が行っていた処理の詳細を説明していきます。出てきますが、あくまでも、「データを目的地まで届ける」ということをしている点を忘れないでください。IPヘッダーとMACヘッダーの付与TCP担当からTCPヘッダーとデータを渡されたら、そこにIPヘッダーとMACヘッダーを付与していきます。パケットを宛先に届けるにあたって、まだどこに届けたらいいのかがわからない状態です。そのため、IPヘッダーとMACヘッダーそれぞれの中に、最終的な宛先IPアドレスと、次にパケットを渡す先のMACアドレスを設定してどこにパケットを渡せばいいのか他の機器が判断することができる状態にする必要があるのです。その後、ヘッダーが付与されたパケットはLANアダプタに渡されていきます。宛先MACアドレス宛先をもとに経路表からどのルータ(IPアドレス)にパケットを渡すべきか調べる宛先ルータのIPアドレスからARPを用いてMACアドレスを取得するDNSサーバに問い合わせる時同様、キャッシュにあるかまず確認して、なかったら問い合わせる送信元MACアドレスLANアダプタに製造時に付与されている。OS起動時に読み出してメモリに保存しておいて、その値をMACヘッダー作成時に付与するイーサタイプIP(0800)、ARP(0806)など上位プロトコルを表すための番号LANアダプタでデジタルデータを信号に変換IPヘッダーとMACヘッダーを付与したことで、パケットを最終的にどこに届けたらいいのか、次の宛先はどこに送信したらいいのかは分かるようになりました。次は、ネットワークの中にデータを流して、宛先まで届けることができるように、デジタルデータを信号に変換して送信していきます。この作業は、LANアダプタが担います。LANアダプタはそれ単体では活用することができず、LANドライバと一緒になって初めて活用することができます。LANドライバが動き出してから、デジタルデータを信号に変換して送信するまでの流れを追っていきます。OS起動時にLANアダプタを初期化するイーサネットの送受信動作をコントロールする、LANアダプタ内のMAC回路にMACアドレスをセットするLANアダプタのROMにMACアドレスが製造時に書き込まれているのでそれをセット宛先MACアドレスはこのMACアドレスを指しているIPからパケットを受け取るLANドライバがIPから受け取ったパケットをLANアダプタ内のバッファメモリにコピーするMAC回路に送信コマンドを送って、そこから先はMAC回路が処理をするMAC回路はバッファメモリからデータを読み出して、イーサネットフレームの先頭にプリアンブルとスタート・フレーム・デリミタ、末尾にはFCSも付与プリアンブルはデータ受信側がタイミングを図るためスタート・フレーム・デリミタはどこから実際のデータが始まるのか受信側が判断するためFCSはフレームのエラーを検知するためMAC回路がプリアンブルの頭から1ビットずつデジタルデータを信号に変換して、PHYもしくはMAUという信号送受信部分に送る。信号をPHYもしくはMAU回路がケーブルに送り出す形式に変換して送信イーサネットはケーブルの種類や伝送速度によって形式が異なるのだが、MAC回路は共通のところまで変換して残りはPHYもしくはMAU回路に任している送信したら、あとはルーター間を辿ってネットワーク内を流れ、送信先まで届く送信時には受信信号が流れこんできていないかも確認しているただ、エラーはほぼない&あっても処理はTCPに任せているので、イーサネットは何もしない万が一流れ込んできていたらパケットが衝突するので送信を止める送信を止めたら、ジャミング信号を他の機器に流して、しばらく送信動作をストップ待ち時間は、MACアドレスから乱数を生成して、他の機器と被らないようにするここまでで、IP担当が行っていた送信処理をまとめてきました。受信処理に関しては、サーバー側に関する説明の際にまとめますが、クライアント側が受信処理をする際でも流れは同じで、基本的には送信処理の逆手順を辿っていきます。ルーター間を伝わりサーバーに届く詳細を記載していくと膨大になるので、今回は大幅に簡略化してまとめていきたいと思います。宛先IPアドレスからMACアドレスを取得するために、ARPで問い合わせてMACアドレスを取得するARPキャッシュが残っていれば、キャッシュからMACアドレスを取得ルーターのポート部分がLANアダプタと同様の働きをしてデジタルデータを信号に変換し、次のルーターに送信ルーター間についてルーター間は、回線事業者が引いたADSL回線などを通ってデータが流れています。この部分でも本来はさまざまな処理が行われていますが、普段我々が直接操作したり意識したりする部分は少ないので、今回は割愛します。ルーター間を通ってサーバーに届くまでの間には、ファイヤウォールやロードバランサ、プロキシサーバー(キャッシュサーバー)、CDSなど、様々な技術が活用されており、それぞれセキュリティを高めたり、サーバーの負荷を分散したり、コンテンツ配信の速度を上げたりといった役割を持っています。これらも今回は詳細を割愛します。サーバーが信号を受信ここまでの長い道のりを経て、やっとサーバーが信号を受信します。ここからは復路の説明です。この先、サーバーが信号を受信してから、レスポンスを返して、ブラウザが画面にコンテンツを表示するまでを見ていきます。受信する際の処理はクライアントが送信処理をした際の逆になるものがほとんどなので、新しいことは多くありません。受信時はクライアントからのデータ送信時とは逆の手順が取られます。クライアント側がデータを受信する場合でも、サーバー側がデータを受信する場合でも処理内容は同じです。LANアダプタの処理PHYもしくはMAU回路が、プリアンプルをみてタイミングを取って、データを読み込むPHYもしくはMAU回路がMAC回路が処理できる形式に変換してMAC回路に渡すMAC回路がデジタルデータに変換して、バッファメモリに貯めるデータを全て受け取ったら、FCSの計算をするイーサネットフレームの末尾についているFCSと付き合わせてズレていたらパケットを捨てるMACアドレスが自分宛かどうかチェックし、異なる場合捨てる。自分ならバッファメモリに貯めるMAC回路の仕事は終了で、CPUにデータの受信を通知する通知方法は、LANアダプタが拡張バススロットにある割り込み用の信号線に信号を送るCPUは今の仕事を止めて、割り込み処理用プログラムに切り替えるCPUがLANドライバを呼び出しLANアダプタのバッファメモリに格納されたデータを取り出すLANドライバがMACヘッダーのタイプ・フィールドを確認して適切なプロトコルスタックにパケットを渡すここからは、LANアダプタの仕事ではなく、プロトコルスタックが処理する範囲です。分割されていた場合、IP担当の内部メモリに一時保管して他のデータと繋ぎ合わせるID情報に同じ値を持つパケットが分割されている同一パケットフラグメント・オフセット:該当パケットが同一ID値内でどの位置にくるパケットかを表しているので、この情報をもとにデータを結合するデータを結合したら、次のプロトコルをチェックして然るべき担当にデータを渡すこの際、IPヘッダーの宛先&送信元IPアドレス、TCPヘッダーの宛先&送信元ポート番号を調べて、該当するソケットを探してTCP担当を見つけているTCPでの処理TCPヘッダーを調べるSYNが1の接続依頼の場合には、接続処理をするが、以下はデータが送られてきている前提で話を進める該当するソケットにデータを渡し、TCPヘッダーの中身を調べるシーケンス番号が正しいかどうかなど前回受け取ったデータに繋げ、受信バッファに保存TCPヘッダにACKを1にして作成し、IP担当に依頼し受信動作成功をクライアントに伝えるアプリケーションがreadを呼び出して待っているはずなので、受信バッファのデータがアプリケーションに取られたらTCP担当の処理は完了サーバーサイドアプリケーションの処理サーバーアプリがreadでソケットの受信バッファからデータを読むURIとHTTPメソッドを元に後続の処理を決定するサーバーサイドで処理したらwriteでクライアントにデータを送り返すHTMLをそのまま返すこともあれば、URIに付与されたパラメタやリクエストボディの内容をCGIプログラムに渡して動かして、処理結果を返すこともあるIPアドレスやドメイン、ユーザ名&パスワードなどでアクセス制御をかける場合もある処理されたデータをまとめ、クライアントがリクエストメッセージを作成したのと同じ方法で、レスポンスメッセージを作成するSocketライブラリのwriteメソッドでプロトコルスタックを呼び出しクライアントに送り返す送信先はソケットのディスクリプタで指定する。ソケットはIPアドレスなど、データを届けるのに必要な情報持っているのでディスクリプタを指定するだけでOKこの先の流れは、クライアントからサーバーまでデータが送信された際の流れと同じです。ブラウザがデータを受信ブラウザがデータを受信してから、画面にコンテンツを表示するまでの流れを説明していきます。ー管理者が設定を間違えていたりすることがある。そのため、データの中身などから総合的に判断する機能をブラウザが持っていることも多い。これはブラウザによって異なるContent-Encodingも確認して、どんな方法で圧縮されているのか確認。必要に応じて元に戻すコンテンツの種類がHTMLの場合には、中身を解析OSが画面上にコンテンツを表示する機能を持っているので、OSに対してどこに何を表示するのかブラウザから指示を出す画像データを示すファイルがHTMLに入っている場合、サーバーに問い合わせて画像を取得するHTMLを取得したリクエストと同じ方法を画像に対しても1枚ずつ行うそのため、大量に画像が設置されているwebサイトなどは全ての画像を表示するために何回も通信する必要があり時間がかかるJPEGなどは圧縮されているので、受け取ったら復元して、文章と同じくOSに依頼して表示するまとめかなり絞ってまとめたつもりでも、一部詳細に書き過ぎている部分があるので後ほどより絞る編集をし直すことができたらと思います。目的であった、全体感を把握できるようにまとめる。いう目的は達成できたので、デリバリー優先でリリースとします。withGatsby。