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

ブラウザにURLを入力してからページが表示されるまでを　探検ツアーのように説明されている本。

読むと以下のパケットの流れが解像度高くわかるようになる。



自分が理解した内容を文章形式にした。

「ブラウザにURLを入力すると、まずブラウザがURLを解読してHTTPのリクエストメッセージを作ります。OSにHTTPメッセージの送信を依頼するときにドメイン名ではなくIPアドレスが必要になるため、DNSサーバーに問い合わせます。Socketライブラリの中にあるリゾルバが`gethostbyname("www.lab.glasscom.com")`のような形で呼び出すと、最寄りDNSサーバーがルートドメインを経由したりしながら目的のサーバーに達して、対応表からクラスとタイプが一致するIPアドレスを探して返します。それをリゾルバが取り出してブラウザに指定されたメモリ領域に書き込みます。
このDNSサーバーへIPアドレスを問い合わせるときや、音声や映像データを送るときに使われるのはUDPプロトコルです。TCPのような複雑な仕組みはなく、返事が返ってこないときは届かなかったとみなしてもう一度送り直します。

IPアドレスがわかったら、次はプロトコルスタックにメッセージ送信を依頼します。

送受信全体の流れを先に説明してしまうと、まず`socket()`を呼び出しソケットを作り、そこで返ってきたディスクリプタ、IPアドレス、ポートを`connect()`に渡してソケットをパイプにつなぎます。このとき、TCPヘッダーに送信元と宛先ポート番号を入れて、SYNのコントロールビットを1にしてシーケンス番号初期値をセットしてから、IP担当部分に送信依頼をします。サーバー側からACKとSYNのコントロールビットが1でシーケンス番号初期値がセットされたレスポンスが返ってきたら、クライアント側からもACKを1で返します。これでコネクションができてプロトコルスタックの接続動作が終わります。
プロトコルスタックはアプリケーションから受け取ったデータをまずは送信用バッファメモリー領域にためます。`write()`でHTTPリクエストメッセージを送信し、シーケンス番号とACK番号でパケットが届いたことを確認します。このときACK番号が返って来なかったらパケットを送り直します。エラーの検出に関しては、ACK番号が返ってくる時間を計測してタイムアウト値を動的に計測して調整したり、受信側から受信可能なデータ量を通知するウィンドウ制御方式でやりとりします。これを両方面から行います。
`read()`を呼び出すとプロトコルスタックがデータの断片をつなぎ合わせて復元し、アプリケーションが指定したメモリー領域に転記してからアプリケーションに制御を戻します。
最後に`close()`を呼び出すとプロトコルスタックがFINのコントロールビットを1にしたTCPヘッダーを作ってIP担当部分に送信依頼し、サーバー側とACK番号のやり取りをして、誤動作を防ぐために数分程度待ってから終了します。

TCP担当部分はIP担当部分に依頼してやり取りデータをパケット化してもらい相手に届けてもらいます。
IP担当部分はTCPから依頼されたデータを、宛先や送信元の入ったIPヘッダーと、ARPで調べたMACヘッダーを付けてパケットにして、0や1のデジタルデータにしてからイーサネットや無線LANに渡します。

LANアダプタはまずパケットをバッファメモリーにコピーします。それからMAC回路がタイミングを計るためのプリアンプルと、開始位置を見つけるためのスタートフレームデリミタ付け加え、末尾にエラー検知のためのFCS（フレームチェックシーケンス）を付けてから、PHY(MAU)とよぶ信号送受信部分に渡し、そこから実際にケーブルに送りだす形式に変換して送信します。

送信されたパケットはスイッチングハブや、ルーターによって中継されます。
ルーターはPHY(MAU)回路でデジタルデータに変換し、パケット末尾のFCSを照合してから、宛先MACアドレスが自分であればバッファメモリーに格納します。それから先頭のMACアドレスを捨てて、IPヘッダーを見てルーティングテーブルを調べて該当行を探します。TTL更新し、パケットサイズが大きければフラグメンテーションで分割します。

そしてインターネット接続用ルーターにたどり着きます。

ADSLの場合、インターネット接続用ルーターはMACヘッダー、PPPoEヘッダー、PPPヘッダーの3つをつけてADSLモデムにパケットを送付します。
ADSLモデムはパケットをセルに分割し、正弦波を合成した信号に0と1のビット値を対応づける変調技術を使って電気信号に変えてスプリッタに送信します。
スプリッタから電話の音声信号に混じって電話回線に一緒に流れていき、保安器などを抜けて電話局のDSLAMに届きます。
DSLAMは信号の波形を読み取って振幅と位相を調べて、電気信号がデジタルデータのセルに戻されます。
DSLAMからBASに届くとBASはセルを元のパケットに戻して、先頭のMACヘッダーとPPPoEヘッダーを捨てて、PPPヘッダー以降の部分を取り出し、トンネリング用のヘッダーを付けてトンネリングの出口のインターネット内部に向けて中継します。

FTTHの場合、ユーザー側の終端装置でイーサネットの電気信号が光信号に変換されます。
シングルモードの光ファイバを流れて集合型のメディアコンバータで電気信号に戻り、BASのポートが受信してインターネット内部にパケットを中継します。

プロバイダのPOPに設置したルーターに届くとそこがインターネットの入り口となります。
インターネット内部はプロバイダ同士が経路情報を教え合うので、中継先を探してそこにパケットを送る動作を繰り返せば、そのうちWebサーバー側のPOPにたどり着くようになっています。

Webサーバー側に着いたら、まずファイアウォールによってパケットフィルタリングがされます。
ここで宛先IPアドレス、送信元IPアドレス、宛先ポート番号、送信元ポート番号、コントロールビットなどてパケットを通すか棄てるか判断されます。それからロードバランサーやキャッシュサーバーやCDNによってサーバーの負荷が分散されます。

サーバーの受信動作の全体の流れとしては、クライアント側と同じようにまず`socket()`を呼び出してソケット用のメモリ領域を確保しソケットを作ります。
`bind()`を呼び出してソケットにポート番号を記録します。
ポート番号を記録したら`listen()`を呼び出してソケットに接続待ち状態であることを記録して待ちます。
`accept()`を呼び出して接続を受け付けます。
このとき接続待ちのソケットをコピーして新しいソケットを作り、クライアント側のIPアドレスとポート番号でソケットを対応させます。

サーバーのパケット受信動作に関しては、LANアダプタがまずプリアンプルの波形でタイミングを計って、スタートフレームデリミタが出てきたらその次のビットからデジタルデータに変換する動作を開始します。
PHY(MAU)回路からMAC回路へ進み、バッファメモリーにためていきます。信号の最後まで達したら末尾のFCSをチェックして、問題がなければMACアドレスを調べて、それが自分宛であれば保存します。
パケットを受信したことを割り込みという仕組みでコンピュータ本体に通知します。それからLANドライバがMACヘッダーのタイプフィールドの値からプロトコルを判別し、プロトコルスタックに渡します。
IP担当部分がヘッダー部分に問題がないか調べ、宛先IPアドレスを確認します。もし間違っていたらICMPメッセージを使ってエラーを通知します。IPヘッダーにフラグメンテーションがあり分割されたものであれば、パケットを元の姿に戻すリアセンブリングをします。これが終わればIPヘッダーのプロトコル番号を調べて06であればTCP担当部分に渡します。
TCP担当部分はTCPヘッダーのSYNを確認し、IPヘッダーの宛先/送信元IPアドレスとTCPヘッダーの宛先/送信元ポート番号の4つの項目を調べて、該当するソケットを探します。
ソケットがあればコピーしてそこに送信元のIPアドレスやポート番号、シーケンス番号の初期値、ウィンドウの値などを記録して、送信受信バッファのためのメモリ領域を確保します。
シーケンス番号の初期値、受信のためのウィンドウ値などを記載したTCPヘッダーを作って、それをIP担当部分にクライアントに送り返してもらい、ACK番号が返ってきたら接続動作は完了です。
データのパケットを受信したTCP担当部分は、届いたパケットから4つの要素に該当するソケットを判断し、データ断片を繋ぐようにして受信バッファに保管し、クライアントに対してACKを返します。
アプリケーションが`read()`を呼び出し、HTTPリクエストメッセージの内容を調べてメソッドとデータ源を表すURIに従ってブラウザにデータを送り返します。
TCPの切断は、アプリケーションが`close()`を呼び出し、TCP担当部分がFINコントロールビットを1にセットしたTCPヘッダーを作ってIP担当部分に送ってもらい、クライアントからFINを1にしたTCPヘッダーが返ってきたらACKを送り返して切断動作が終わり、しばらく待ってからソケットを抹消します。

ブラウザがレスポンスメッセージ受け取って`Content-Type`からデータ形式を判断し、`Content-Encoding`を調べて必要に応じて元に戻します。
タグを解釈して文章をレイアウトして画面に表示します。画像データなどはHTTPリクエストのURI部分に画像データのファイル名を書いてリクエストメッセージを送り読み込みます。
以上がブラウザでURLを打ち込んでデータが返ってきて表示されるまでの流れです。」








# 序章

- ネットワークの全体像
    - 0と1から成るデータを目的地まで運ぶ仕組み
        - パケットという荷物がスイッチやルーターという集配所を経由して振り分けられながら目的地に近づくように運ばれていく
- Webサーバにアクセスする一連の動作
    1. Webブラウザが依頼する
    1. プロトコル・スタック（ネットワーク制御用ソフトウェア）が制御情報を付加してLANアダプタに渡して、それが電気信号になってLANケーブルに送り出される
        - 秘書が手紙を封筒に入れて宛名を書いて投函する
    1. スイッチング・ハブなどを経由してインターネット接続用のルーターに届く
        - 郵便ポストに投函された手紙を、郵便局員が持っていってくれる
    1. アクセス回線からPOP（Point Of Presence）というプロバイダ向けに作られたルーターにつながって、ここからインターネットの中核部分に入っていく
        - 最寄りの郵便局が仕分けをして全国に向けて配送する
    1. 最終的にWebサーバー側のLANのファイアウォールにたどり着く。次にキャッシュサーバーがあったり、負荷分散装置があったりする
    1. Webサーバーマシンにたどり着いたら、プロトコル・スタックがパケットの中身を取り出してリクエスト・メッセージを復元し、Webサーバーアプリケーションに渡す。そこに書いてある指示内容に従ってデータをレスポンス・メッセージに入れてクライアントに送り返す
    1. レスポンスが返ってきたらデータを取り出して画面に表示する


# 第1章 Webブラウザがメッセージを作る

## 出てくる用語
- URL（Uniform Resource Locator）
    - `http:`,`ftp:`,`file:`,`mailto:`など色々ある
        - ブラウザは複合的なクライアントソフトだから
- HTTPプロトコル
    - さまざまなアクセス先であるURI（Uniform Resource Identifier）をどうしたいのかメソッドに書く
        - メソッドに`GET`、URIに`/dir1/file.html`など
        - 補足情報はヘッダーに入る
            - ステータスコードが入ったレスポンスメッセージがヘッダーやデータとともに返ってくる
                - ブラウザがデータを取り出して画面に表示する
- TCP/IP
    - サブネットをルーターで繋いだもの
        - IPアドレス
            - 丁目であるネットワーク番号と、番地であるホスト番号でできたもの
                - ネットマスクでネットワーク番号がどこまでか特定する
- DNS
    - 名前がわかればIPアドレスがわかる、IPアドレスがわかれば名前がわかるようにした
        - IPアドレスだから4バイト分の数値だけを扱えばいいし、人間は覚えやすい名前を使って相手と通信できる
- ドメイン名
    - 会社の事業部、部、課といったような階層構造を持つ名前
        - `www.lab.glasscom.com`
            - 右に位置するのが上位の階層
                - 「com事業部glasscom部lab課のwww」
                - 1つの部署に相当するものをドメインと呼ぶ
                - `sub1.example.co.jp`のように下位ドメインをサブドメインとして作れる
                    -  インターネットのドメインはすべてそうやって割り当てたもの
                        -  `www.nikkeibp.co.jp`は日本のjpドメインに会社のcoを作りnikkeibpを作って最下位にwwwという名前のサーバーを割り当てている
    -  登録するとき
        -  `lab.glasscom.com`というドメインを担当するDNSサーバーを`glasscom.com`のDNSサーバーに登録するといったようにして、上位のDNSサーバーから下位へ辿っていけるようにした
            -  comやjpといったトップドメインの上にルートドメインがある
                -  ルートドメインのDNSサーバーはネットに存在するDNSサーバーすべてに登録されている（全世界で13個）
                    -  ルートドメインを経由して最終的に目的のDNSサーバーにたどり着ける
                    


       

## 実際の動作

- まずはブラウザがURLを解読する
    - Webサーバーとファイル名を特定する
- HTTPのリクエストメッセージを作る
    - 画像など複数ファイルを読み出すときは別々にリクエストメッセージを送ることになる
        - HTTP1.1では一度接続したら切断しないでやり取りすることもできる
- DNSサーバーにWebサーバーのIPアドレスを問い合わせる
    - OSにHTTPメッセージの送信を依頼するときにドメイン名ではなくIPアドレスが必要になるから
    - どうやって問い合わせるか
        - リゾルバが名前解決する
            - Socketライブラリの中にあるプログラム
                - Socketライブラリはカリフォルニア大学バークレー校で作られたBSD（Berkeley Software Distribution）で開発されたC言語用のライブラリ
            - `gethostbyname("www.lab.glasscom.com")`のように呼び出す
                - DNSサーバの動作
                        - 表の1行分をリソースレコードと呼ぶ
                    - サーバ内の対応表を調べて名前、クラス、タイプが一致するものを探す
                        - `A`タイプがIPアドレスで、`MX`タイプがメール配信先
                - 最寄りのDNSサーバーはルートドメインを経由して目的のサーバーに達し、わかったIPアドレスをクライアントに返答する
                    - 現実的には1ドメインに1DNSサーバーではないし、キャッシュも使われる
                - 応答メッセージにIPアドレスが格納されている
                    - リゾルバが取り出して、ブラウザに指定されたメモリ領域に書き込む
                        - アプリケーションが必要なときにそのメモリ領域からIPアドレスを取り出す
- プロトコルスタックにメッセージ送信を依頼する
        1. ソケットを作る
            - `socket()`で呼び出す
                - ディスクリプタが返ってくる
                    - コンピュータ内の複数のソケットをどれがどれか識別するもの
                        - ホテルのクロークにカバンを預けたときに渡される番号札のようなもの
        1. サーバー側のソケットにパイプをつなぐ
            - `connect()`でつなぐ
                - 引数にディスクリプタ、IPアドレス、ポートを渡す
                    - ポート番号
                        - 電話をかけて「〇〇さんをお願いしたいのですが」と呼び出す仕掛け
                        - アプリの種類によって決められている
                            - ブラウザからWebサーバーにアクセスするのは80番
                    - IPアドレスとポート番号でクライアントとサーバー間のソケットを識別する
        1. データを送受信する
            - `write()`でHTTPリクエストメッセージを送信する
                - 引数にディスクリプタと送信データを渡す
                    - ソケットに繋がった相手が記録されているから、ディスクリプタでソケットを指定するだけで相手先がわかる
            - `read()`でレスポンスメッセージを受信する
                - レスポンスを格納するためメモリー領域を指定する
        1. パイプを外してソケットを抹消する
            - `close()`でSocketに切断フェーズに入るよう依頼する


# 第2章 TCP/IPのデータを電気信号にして送る

## 出てくる用語

- プロトコルスタック
        - Socketライブラリの中にリゾルバがある
        - ICMPはパケットを運ぶときのエラー通知や制御用のメッセージを通知するときに使うもの
        - ARPはMACアドレスを調べるときに使う
    - 内部のメモリ領域に制御情報を記録する
        - 通信内でのIPアドレス、ポート番号、通信動作の進行状態など
- MTU
    - 1つのパケットで運ぶことができるデジタルデータの最大長
        - 1500バイト
    - ここからヘッダーを除いたものがMSS
- パケット
- MACヘッダー
    - IPアドレスのようにグループ化した値ではなく、48ビットを一つの値と考える
- イーサネット
    - 宛先MACアドレスにパケットが届く、送信元MACアドレスで送信元を表す、イーサタイプでパケットの内容物を表すという3つの性質
        - 無線LANも同じ性質を持つ
        - パケットの内容物を見ないからTCPの動作フェーズにかかわらずすべてに共通する
        - 最初は、1つの部屋で誰かが声を出せば全員に聞こえるというような簡単なものだった
            - その後宛先MACアドレスで目的の機器だけに信号が流れるようになった
    - 初期化作業
        - MAC（Media Access Control）回路にLANドライバがMACアドレスをセットする
            - LANアダプタのROMに全世界で重複しないように一元管理されたMACアドレスが製造時に書き込まれている
            



## 実際の動作

- ソケットを作成する
    - 制御情報を記録したメモリー領域がソケットの実体といえる
        - このソケットの情報を参照しながらプロトコルスタックが動く
    - `socket()`が呼び出されたらプロトコルスタックがソケット1つ分のメモリ領域を確保し初期状態で記録する
        - それからそのソケットを示すディスクリプタをアプリケーションに知らせる
- サーバーに接続する
    - クライアント側のIPアドレスやポート番号をサーバー側に知らせる
    - データを送受信格納するためのバッファメモリーを確保する
    - パケットのヘッダーに制御情報を記載する
        - この制御情報でやり取りが交わされる
            - 「データ送信動作開始」「どうぞ」「〇〇番目のデータを送ります」「〇〇番目のデータを受け取りました」
        - 加えて、ソケットに記録される制御情報がある
    - `connect(<ディスクリプタ>,<サーバー側のIPアドレスとポート番号>)`で接続する
        - サーバー側のIPアドレスとポート番号がプロトコルスタックのTCP担当部分に伝わる
            - TCPヘッダーに送信元と宛先ポート番号を入れコントロールビットのSYNを1にする
                - TCPヘッダーをIP担当部分に渡して送信依頼する
                    - ACKのコントロールビットが1になった返事が返ってくる
                        - クライアント側からもACKを1で返す
                            - コネクションができてプロトコルスタックの接続動作が終わりアプリケーションに制御が戻る
- データを送受信する
    - プロトコルスタックはアプリからの受け取ったデータをまずは送信用バッファメモリー領域にためる
        - MTUとタイミングを基に送信するかどうか判断する
            - 一定時間経過で送信する
                - データ量と時間の兼ね合いはTCPプロトコルの仕様では決まっていない
                    - プロトコルスタックを作る開発者次第
                        - アプリケーション側でコントロールもできる
                            - 「バッファをためずにすぐ送信すること」オプション
    - データが大きいときは分割して送る
    - シーケンス番号とACK番号でパケットが届いたことを確認する
        - データの断片が通信開始から数えて何バイト目なのかシーケンス番号に記載する
            - 1460バイト目まで受信し終わってシーケンス番号が1461のパケットが届けば抜けがないことがわかる
                - 何バイト目まで受信したか計算してACK番号に記載し、ACKを1にしフィールドを有効にして送信側に知らせる
                    - 送信側「〇〇バイト目から始まるデータをxxバイト送りますよ」受信側「△△バイトまで受信しました」
                        - 受信確認応答
                    - 実際のシーケンス番号は乱数を初期値とする
                        - 動きを予測されるから
                        - 初期値はSYN（Synchronize）コントロールビットを1にしてシーケンス番号をセットすることで伝える
                            - 実質的に接続動作を表すこととなる
        - TCPは確認できるまではパケットを送信用バッファメモリー領域に保管している
            - ACK番号が返ってこなかったらパケットを送り直す
                - 回復処置ができる
                    - TCPに任せておけば多少のエラーが起こってもちゃんと届けてくれる
                        - アプリも、LANアダプタも、ハブも、ルーターもエラーがあるとパケットを捨てるだけ
        - 実際のエラー検出と回復の仕組み
            - タイムアウト値を動的に設定する
                - ACK番号が返ってくる時間を計測して、遅くなったらそれに応じて待ち時間を長くする
            - ウィンドウ制御方式で管理する
                - 受信バッファ以上のデータが渡されると溢れて消えてしまう
                    - 受信側から送信側に受信可能なデータ量を通知してその量を超えないように送信させる
                        - TCPヘッダーのウィンドウフィールドで知らせる
                            - ウィンドウサイズと呼ばれるTCPをチューニングするパラメータの一つ
                            - 受信バッファの空き容量が増えたときに送信側に通知する
                - ACK番号通知とウィンドウ通知を相乗りさせたり、複数通知の最後だけ通知したりして効率化する
    - 両方面から行う
    - 受信動作
        - `read()`を呼び出すとアプリからプロトコルスタックに制御が移る
            - データの断片を繋ぎ合わせて復元してからアプリケーションに渡す
                - 受信データをアプリが指定したメモリー領域に転記してから、アプリに制御を戻す
- サーバーから切断してソケットを抹消する
    - どちらから先に切断フェーズに入ってもよいようにプロトコルスタックが作られている
    - `close()`を呼び出すとプロトコルスタックがTCPヘッダーを作ってそこに切断を表す情報をセットする
        - FINのコントロールビットを1にする
            - IP担当部分に依頼して送信してもらう
                - お互いにACK番号をやり取りして終了する
    - しばらく待ってからソケットを抹消する
        - 誤動作を防ぐため通常は数分程度待つ
            - ACK番号が返ってこないからFINをもう一度送信したときにソケットが消えていると通信できない
                - もし別のアプリに同じポート番号が割り当てられていたらそのアプリが終了してしまう
- TCP全体の動作
- IPとイーサネットのパケット送受信動作
    - TCP担当部分はIP担当部分に依頼して、やり取りデータをパケット
化して相手に届けてもらう
            - イーサネットは無線LAN、ADSL、FTTHなど置き換えられる
        - 「この相手に、この内容物(データ断片にTCPヘッダーを付加したもの）を届けてください」と依頼する
            - これに宛先や送信元の入ったIPヘッダーとMACヘッダーを付けてIP担当部分がパケットを0や1のデジタルデータにしてイーサネットや無線LANなどに渡す
                - IP担当部分はTCPヘッダーとデータ断片を一塊のバイナリデータとしかみない
                    - 依頼された内容物をパケットに格好にして相手に向けて送信したり、受信したりするだけ
                - ARPで宛先ルーターのMACアドレスを調べる
                    - 「〇〇というIPアドレスを持っている人はいませんか？いたらMACアドレスを教えてください」
                        - ARPキャッシュに保存される
                            - 数分で削除される
                - LANアダプタがデジタルデータを電気や光の信号に変換してネットワークケーブルに送り出す
                    - パケットをLANアダプタ内のバッファメモリーにコピーする
                        - MAC回路がプリアンプルとスタートフレームデリミタを付け加え、末尾にフレームチェックシーケンスを付け加える
                            - プリアンプルとは
                                - 送信するパケットを読み取るときのタイミングを56ビットのビット列で表す
                                    - 0や1が続くとどこが切れ目かわからなくなる
                                        - エスカレータに乗る時のように、しばらく信号の変化を眺めていればタイミングがつかめるので、そのためにプリアンプルという特別な信号をパケットの前に付加している
                                - スタートフレームデリミタとは
                                    - フレーム（パケット）の開始位置を見つけるもの
                            - フレームチェックシーケンス（FCS）はデータが化てないか検出するためのもの
                                - パケットの先頭から最後尾までの内容を計算したもの
                                    - 1バイトでも違うと変わるようになっている
                        - MAC回路がパケットを送信する
                            - 半２重モードなら信号が流れていないときに送信動作を始める
                                - PHYあるいはMAUと呼ぶ信号送受信部分に送る
                                    - 実際にケーブルに送り出す形式に変換して送信してくれる
                - LANアダプタが返ってきたパケットを受け取る
                    - プリアンプルの波形でタイミングを計って、スタートフレームデリミタが出てきたらその次のビットからデジタルデータに変換する動作を開始する
                        - PHY(MAU）回路からMAC回路へ進む
                            - バッファメモリーにためていく
                                - 信号の最後まで達したら末尾のFCSをチェックする
                                    - 問題なければMACアドレスを調べ、自分宛なら保存する
                                    - パケットを受信したことを割り込みという仕組みでコンピュータ本体に通知する
                                    - LANドライバがMACヘッダーのタイプフィールドの値からプロトコルを判別し、プロトコルスタックに渡す
                - IP担当部分がヘッダー部分に問題がないか調べ、宛先IPアドレスを調べる
                    - 間違っていたらICMPメッセージを使ってエラーを通知する
                    - IPヘッダーにフラグがあり分割されたものだったら、パケットを元の姿に戻すリアセンブリングをする
                        - 終わったらTCP担当部分に渡す
                            - TCP担当部分は、IPヘッダーの宛先/送信元IPアドレスとTCPヘッダーの宛先/送信元ポート番号の4つの項目を調べて、該当するソケットを探す
- UDPプロトコルを用いた送受信動作
    - 送りっぱなしで、送り直しの必要がないならUDPの方が効率的
        - DNSサーバーへIPアドレスを問い合わせるとき、音声や映像データを送るときなど
        - 届かなかったらもう一度全部送り直せばいい
            - データが1つのパケットに収まる程度の長さの場合なら無駄はない
                - IPパケットの最大値は65535バイト
                    - そこからIPヘッダーとUDPヘッダーを引いたもの
                        - 通常は65507バイト
                            - IP担当部分がフラグメンテーション機能で分割してから送る
                - TCPのような複雑な仕組みは必要ない
        - 返事が返ってきたらそれを受信確認応答の代わりとする



# 第3章 ケーブルの先はLAN機器だった

## 出てくる用語

- ルーターの基本
    - 中継部分とポート部分という2つの部分で構成される
        - 中継部分はIP担当部分と同じで、ポート部分はLANアダプタと同じ役割分担
            - ルーターの各ポートにはMACアドレスとIPアドレスが割り当てられている
    - ルーティングテーブル
        - アドレス集約でサブネットをまとめてルーティングテーブルに登録できる
        - 宛先欄とネットマスク欄で該当行を探し出したら、インターフェース欄に登録されているインターフェースからゲートウェイ欄に登録されているIPアドレスを持つルーターに対してパケットを中継する
        - メトリックは目的地が近いか遠いかを表す




## 実際の動作

- ケーブルとリピータハブの中を信号が流れていく
    - 中継するときはデータ部分を見ない
        - 郵便局員が封書の中身を見ないで配達するのと同じ
            - HTTPのメソッドも、TCPのシーケンス番号も、クライアントとサーバーという関係もすべて無視される
    - LANアダプタのPHY（MAU）回路でプラスとマイナスの電気信号になったパケットはツイストペアケーブル（より対線）に入っていく
        - ハブについた時は信号は弱くなり、角がとれて丸くなってしまう
            -  周波数が高いほどエネルギーの落ちる率が大きい
                -  0と1を見誤ると通信エラーの原因となる
            - より対線は外からの雑音を抑えるようになっている
    - リピータハブのPHY(MAU)回路の受信部に届いた信号が、リピータ回路からLAN全体にばら撒かれる
        - 減衰したものはそのままだが、FCSをチェックしてエラーがあれば捨てられるし、TCPなので問題ない
        - 宛先MACアドレスに該当した機器が受信する
- スイッチングハブのパケット中継動作
    - スイッチングハブのポートにはMACアドレスの割り当てがなく、全パケットをバッファメモリーに格納する
        - 宛先MACアドレスと一致するものがあるかMACアドレステーブルを調べる
            - わかったらスイッチ回路でパケットを送信側のポートに送る
    - パケットを中継するときにMACアドレステーブルの更新もする
        - 送信元MACアドレスと受信した入力ポート番号とセットにして登録しておく
        - 使わずに一定時間経過したMACアドレステーブルの情報を削除する
    - スイッチングハブの全2重モードは送信と受信を同時に行える
        - イーサネットのデータが流れていないときに送るパルスで相手のモードを識別
できるようにした
- ルーターのパケット中継動作
    - まずはルーターがパケットを受信する
        - 信号をPHY(MAU)回路とMAC回路でデジタルデータに変換し、パケット末尾のFCSを照合してから、宛先MACアドレスが自分であればバッファメモリーに格納する
    - 先頭のMACヘッダーを捨てる
        - このルーターに届けるためだけの役割だから
    - IPヘッダーを見て中継動作に入る
        - ルーティングテーブルを見て該当行を探す
            - ネットマスクに登録された値から調べる
                - `255.255.255.0`なら24ビット分だけ調べる
            - 該当がない時はパケットを捨ててICMPメッセージを送信元に送る
                - スイッチングハブとは違う
                    - スイッチングハブは多くて数千台だがルーターはネットの全世界だから、見つからないときに全ポートにばら撒くという方法はできない
                - 最後の行の`0.0.0.0`がどんなアドレスでも合致するので、他に該当がない場合はこのデフォルトゲートウェイが使われる
                    - ここにインターネットに出ていくルーターを登録しておく
                        - 中継先を全部登録しなくてもよくなる
    - TTL(Time To Live：生存期限)というIPヘッダーのフィールドを更新する
        - ルーターを経由する都度１ずつ減らす
            - 送信元が64や128といった値をセットする
                - 実際は地球の裏側まで経由しても数十個程度
    - パケットサイズが出力側の最大長を越えるときは、IPプロトコル規定のフラグメンテーションで分割する
        - 出力先のMTUを調べて比較してから、IPヘッダーのフラグフィールドを調べて分割していいか確認する
            - TCPヘッダーも含めて分割してコピーしたIPヘッダーをつける
            - 分割できない時はパケットを捨てて、ICMPメッセージを送信元に通知する
    - ルーターの送信動作はコンピュータと同じ
- 通信相手までパケットを届ける全体の動作はIP（ルーター）が担当し、その動作の際に次のルーターまでパケットを運ぶ部分をイーサネット（スイッチングハブ）が担当する
    - イーサネットの部分は無線LANやADSLなど適材適所で使い分けられるのがIPの特徴
        - インターネットのような巨大なネットワークが作れる
- ルーターの付加機能
    - アドレス変換
        - 社内用アドレスをプライベートアドレスと呼び、固有なアドレスはグローバルアドレスと呼ぶことにした
            - プライベートアドレスの範囲は限定されている
                - `10.0.0.0~10.255.255.255`
                - `172.16.0.0~172.31.255.255`
                - `192.168.0.0~192.168.255.255`
        - プライベートアドレスとポート番号をグローパルアドレスとポート番号に対応させて記録する
        - 社内から社外へは対応表になくても中継できる
            - グローバルアドレスはルーターにあるし、ポート番号は適当に空いているものを使えばいいから
            - 社外からは対応表がないと中継できない
                - インターネットにアクセスしていない機器にはネットからパケットを送ることができない
                    - アクセス中でもネットとの通信で使っているポート以外にはパケットを送れない
                        - 不正侵入を防ぐ効果
                - 手動で対応表に登録しておけばいい
    - パケットフィルタリング
        - 中継するときに、MACヘッダー、IPヘッダー、TCPヘッダーを調べて設定条件と違えば捨てる


# 第4章 アクセス回線を通ってインターネットの内部へ

## 用語など

- インターネットは家庭や会社のネットワークの規模が大きくなったもの
    - ルーターの仕組みやパケット中継動作はLANと同じ
        - 違う点
            - 中継装置間の距離が長い
            - ルーティングテーブルに10万件以上登録されているので登録が自動化されている
- PPP(Point-to-point Protocol)
    - 電話回線やISDNなどの通信回線を使って通信するときに使う仕組み
- 光ファイバ
    - 電圧を使って明るい状態と暗い状態を作り0と1を表す
        - デジタルデータを電気信号にしてから光の信号に変換する
    - 位相がそろう角度の数によって細いシングルモードと太いマルチモードがある
- PPP
    - ダイヤルアップ接続する動き
    - 接続した時にインターネット側からパソコンにTCP/IPの設定情報を通知し、その中のグローバルアドレスをパソコンに設定する
    - HDLCの代わりにをイーサネットのパケットを入れ物として使ってPPPプロトコルを流用するようにした
    - PPPを使わずイーサネットのパケットをそのままADSL信号に変換してDSLAMに送信するDHCPという方式もある
- トンネリング
    - トンネリング機能によってプロバイダにパケットを届ける
- BAS
    - 進化したルーター
        - 本人確認と設定値通知機能
            - PPPoEでユーザー名とパスワードを使ったログイン動作の窓口役をする
- POP
    - ユーザーが契約しているプロバイダの設備
        - インターネットは多数のプロバイダのネットワークを相互に接続したもの
- IX(Internet eXchabge)



## 実際の動作

- ADSL技術を用いたアクセス回線の構造と動作
        - インターネット接続用ルーターは、MACヘッダー、PPPoEヘッダー、PPPヘッダーの3つを付けてADSLモデムにパケットを送付する（PPPoEの場合）
        - ADSLモデムはパケットをセルに分割し、電気信号に変えてスプリッタに送信する
            - なだらかな波形（正弦波）を合成した信号に0と1のビット値を対応づける変調技術を使う
        - スプリッタに入って電話の音声信号に混じって電話回線に一緒に流れていく
            - スプリッタは流れ込んでくるときに信号を電話とADSLに分けてくれる
        - モジュラコネクタから屋内配線を通りぬけてIDF・MDFを通り、落雷などの保護なための保安器を抜けたら、信号は電柱の電話ケーブルに入っていく
        - 電柱のき線点から地下に入っていき地下道である、とう道を通って電話局のMDFに1本1本つなぎ込まれる
        - DSLAMに届くと、信号の波形を読み取って振幅と位相を調べて、電気信号がデジタルデータのセルに戻される
            - DSLAMは多数のADSLモデムの機能を1つの筐体に収めた装置
                - DSLAMはパケットを分割したセルの形のまま後方のルーターとやりとりする
        - DSLAMからBASに届くと、BASはセルを元のパケットに戻してインターネット内部に中継する
            - 先頭のMACヘッダーとPPPoEヘッダーを捨てて、PPPヘッダー以降の部分を取り出す
                - 捨てる2つはBASのインターフェイスにパケットを届けるためのものだから
            - トンネリング用のヘッダーを付けて、トンネリングの出口に向けて中継する
- 光ファイバを用いたアクセス回線(FTTH)
    - ユーザー側のメディアコンバータ（終端装置）でイーサネットの電気信号を光信号に変換する
        - ADSLのようにセルに格納しない
    - シングルモードの光ファイバを流れて集合型のメディアコンバータで電気信号に戻りBASのポートが受信してインターネットの内部にパケットを中継する
        - 上りと下りの信号が混じってしまう
            - 波長を変えるのは波長多重
            - 光スプリッタで複数ユーザーをつなぐ
                - ONU(Optical Network Unit)はメディアコンバータと同じだが、加えて電話局のOLT(Optical Line Terminal)と連携して信号の衝突を防ぐ機能がある
                    - 下りはONUを識別する情報をOLTがパケットの先頭に付けて送信先を分ける
- アクセス回線で用いるPPPとトンネリング
    - まずプロバイダから割り当てられたユーザー名とパスワードを登録する
        - インターネット接続用ルーターはPPPoEのDiscoveryというARPのような仕組みでBASのMACアドレスを探す
            - 「BASはいませんか？　いたらMACアドレスを教えてください」
        - BASから送られてきたTCP/IP設定値がインターネット接続用ルーターのBASポートに設定される
            - グローバルアドレスが割り当てられ、デフォルトゲートウェイが設定される
                - 誰かがネットにアクセスしてパケットが送られてくれば、宛先はインターネット接続用ルーターの経路表にないので、デフォルトゲートウェイに中継される
        - BASに届いたらMACヘッダーとPPPoEヘッダーを取り去り、PPPヘッダー以降を取り出す
        - トンネリングの仕組みを使ってパケットを送信する
- プロバイダの内部
    - プロバイダのPOPに設置したルーターに届くとそこがインターネットの入り口
        - POPやNOCは全国各地にあり、その中にあるルーターは会社や家庭のLANと同じ
- プロバイダをまたがって流れるパケット
    - インターネット内のルーターにはすべての経路が登録されている
        - プロバイダ同士が経路情報を教え合う
            - BGPという技術が使われている
                - 接続相手に全経路を通知するのはトランジットと呼ばれる
                - それぞれのネットワークの経路情報だけ相手に通知し合うのはピアと呼ばれる
        - 中継先を探してそこにパケットを送る動作を繰り返せば、そのうちWebサーバー側のPOPにたどり着く


# 第5章 サーバー側のLANには何がある

- Webサーバーの設置場所
    - IPアドレスの枯渇とセキュリティ上の理由で、ファイアウォールを置く方法が一般的
        - 特定のサーバー上で動く特定のアプリにアクセスするパケットだけを通す
            - ただアクセス許可されたアプリにセキュリティホールがあれば危険は残る
- ファイアウォールの仕組みと働き
    - パケットフィルタリング型が主流
        - 宛先IPアドレス、送信元IPアドレス、宛先ポート番号、送信元ポート番号、コントロールビットなどでパケットを通すか棄てるか判断する
            - Webサーバーからインターネットにアクセスする動作をSYNとACKのコントロールビットの条件で防ぐ
                - UDPは接続フェーズの動作がないからコントロールビットではアクセス方向が判別できない
        - 遮断したパケットは棄ててログを残す
- 複数サーバーにリクエストを振り分けてサーバーの負荷を分散する
    - サーバー１台あたりの処理量を減らす分散処理
        - DNSサーバーで振り分ける
            - `www.lab.glasscom.com`に3つのIPアドレスを対応づけて順番に並び替えて回答する
                - ラウンドロビン
                    - 均等にアクセスを分散できる
                    - 故障していてもそのまま回答したり、複数ページをまたがってのやり取りでWebサーバーが変わってしまうなどの欠点もある
            - ロードバランサーをWebサーバーの代わりにDNSサーバーに登録する
                - 複数ページにまたがらない単純なアクセスなら、WebサーバーのCPUやメモリ使用率や応答時間などで判断する
                - 複数ページかどうかの判断をどうするか
                    - HTTPはリクエストメッセージを送る前にTCPの接続動作を行い、レスポンスメッセージが返ってきたら切断するので、続いているかどうかはわからない
                        - プロキシやアドレス変換を使っていると送信元IPアドレスでも判別できない
                    - フォームを送るときに前後の関係を表すデータを入れたり、HTTPのヘッダーフィールドにクッキーを付け加えたりする
- キャッシュサーバーを利用したサーバーの負荷分散
    - プロキシという仕組み
    - DNSサーバーにWebサーバーの代わりにキャッシュサーバーを登録する
        - 接続待ちのソケットを作りリクエストメッセージを受けとる
            - キャッシュにあれば`If-Modified-Since`ヘッダーフィールドを追加して転送し変更があるかだけ確認する
            - なければ`Via`ヘッダーフィールドを追加してWebサーバーにリクエスト送信する
    - プロキシの原点はクライアント側にあったフォワードプロキシ
        - ファイアウォールやキャッシュ機能として使われていた
            - ブラウザへの設定が必須
    - サーバー側に設置するのがリバースプロキシ
- コンテンツ配信サービス
    - 事業者CDSPが主要なプロバイダと契約して多数のキャッシュサーバーを設置する
        - Webサーバー運営者とも契約して連携させる
    - ユーザーが何もしなくてもリクエストメッセージがキャッシュサーバーに届くような仕掛けが必要
        - DNSサーバーでアクセスを振り分けるのと似た方法
            - クライアントとキャッシュサーバーの距離を判断して一番近いIPアドレスを回答する
        - リダイレクト用サーバーでアクセス先を振り分ける
            - Locationヘッダーにリダイレクトさせる



# 第6章 Webサーバーに到着し、応答データがWebブラウザに戻る

- サーバーの概要
    - クライアントが接続してくる都度、新たにサーバープログラムを動かして1対1でやりとりする
        - マルチタスク（マルチプロセス）とマルチスレッドでさばく
    - Socketライブラリを呼び出す部分の概要
        - TCPは左右対称にどちらからでも自由にデータを送信できるように考えられている
            - だが同時に接続はできないので接続動作だけは左右対象にできない
                - 接続する側と受ける側の役割分担が必要
            - socketを呼び出してソケットを作る
                - 中核はソケット用のメモリ領域を確保することなので、クライアント側と変わらない
            - bindを呼び出してソケットにポート番号を記録する
            - ポート番号を記録したらlistenを呼び出してソケットに接続待ち状態であることを記録して待つ
            - acceptを呼び出して接続を受け付ける
                - パケットの到着を待つ
                - 接続待ちのソケットをコピーして新しいソケットを作る
                    - 元のソケットはそのまま
                        - 接続待ちのソケットがなくなってしまうから
                        - 同じポート番号のソケットが存在する問題を上図のように解決する
                            - 接続待ちのソケットにはクライアント側のIPアドレスとポート番号の記録がないからディスクリプタを使う
            - 接続した新しいソケットをクライアントとやり取りする部分に渡す
- サーバーの受信動作
    - 「LANアダプタのMAC部分が、パケットを信号からデジタルデータに戻し、FCSをチェックし、バッファメモリーに置く」
        - LANアダプタで受信して、1と0のデジタルデータ信号をクロック信号のタイミングで計りながら読み取る
        - フレームチェックシーケンス（FCS）でエラーチェックする
            - 電気信号に変換する前のデータを基にして計算されていると一致しているかどうか
                - 一致しなければ捨てる
        - 先頭MACヘッダーから宛先MACアドレスを調べて自分宛かどうか判断する
            - イーサネットの基本動作は信号をLAN全体に流すから
                - 自分以外だったら捨てる
        - デジタルデータに戻ったらLANアダプタ内のバッファメモリーに格納する
            - ここまでをLANアダプタのMAC部分が実行する
        - 割り込みという方法を使ってLANアダプタからCPUにパケットの到着を知らせる
            - CPUがLANドライバに実行を切り替える
            - LANドライバがLANアダプタのバッファメモリーから受信したパケットを取り出す
            - MACヘッダーのタイプフィールドがIPプロトコルであれば、TCP/IPのプロトコルスタックを呼び出してパケットを渡す
    - 「プロトコルスタックのIP担当部分は、IPヘッダーをチェックし、自分宛かどうか、フラグメンテーションによるパケット分割があるかどうか調べてから、TCPあるいはUDP担当部分にパケットを渡す」
        - IP担当部分がIPヘッダーをチェックし、自分宛かどうか調べる
            - ルーター機能が有効であれば経路表からパケットを中継する
        - フラグメンテーションで分割されていればパケットを一時的にメモリにためて完了次第組み立てる
        - IPヘッダーのプロトコル番号欄を調べ06だったらTCPに、11だったらUDP担当部分にパケットを渡す
    - 「TCP担当部分が接続パケットのTCPヘッダーのSYNを確認し、宛先ポート番号を調べて、該当する接続待ちソケットをコピーして作成し、送信元のIPアドレスやポート番号を記録する」
        - TCPヘッダーのSYNコントロールビットが1であれば接続を受け付ける動作を実行する
            - パケットの宛先ポート番号を調べ、接続待ちのソケットがあるか確認する
                - 無ければソケットがないことをICMPメッセージでエラー通知のパケットを送り返す
            - ソケットがあればコピーして、そこに送信元のIPアドレスやポート番号、シーケンス番号の初期値、ウィンドウの値などを記録し、送信受信バッファのためのメモリ領域を確保する
            - シーケンス番号の初期値、受信のためのウィンドウ値などを記載したTCPヘッダーを作って、それをIP担当部分にクライアントに送り返してもらう
            - クライアントからACK番号が返ってきたら接続動作は完了
    - 「データのパケットを受信したTCP担当部分は、届いたパケットから4つの要素に該当するソケットを判断し、データ断片を繋ぐようにして受信バッファに保管し、クライアントに対してACKを返す」
        - TCP担当部分はIPヘッダーの送信元IPアドレスと宛先IPアドレス、TCPヘッダーの宛先ポート番号と送信元ポート番号の4つが合致するソケットを探す
        - シーケンス番号を確認してデータ送受信が正しく正しく進行しているかチェックしながら受信バッファにつなぎ合わせながら保管していく
        - 受信確認応答用のTCPヘッダーを作り、受信パケットのシーケンス番号とACK番号を記載して、IP担当部分にクライアントに送り返してもらう
        - アプリケーションが`read`を呼び出してデータを渡す動作が始まる
            - 制御がサーバーアプリケーションに移る
            - HTTPのリクエストメッセージ内容を調べて、ブラウザにデータを送り返す
    - TCPの切断
        - HTTP1.0であればサーバーから切断動作を始め、HTTP1.1ならクライアントから始める
        - サーバー側でアプリケーションがSocketライブラリのcloseを呼び出す
        - TCP担当部分がFINコントロールビットに1をセットしたTCPヘッダーを作って、IP担当部分に送ってもらう
        - クライアントがFINを1にしたTCPヘッダーをサーバーに送り、サーバーがACK番号を送り返して切断動作は終わる
        - しばらく待ってソケットを抹消する
- Webサーバーソフトがリクエストメッセージの意味を解釈して要求に応える
    - メソッドと、データ源を表すURIに従ってデータを送り返す
        - Webサーバーで公開するディレクトリは仮想的に作られたディレクトリ
        - リクエストメッセージからデータを取り出してプログラムに渡す
            - POSTのメッセージボディを渡すなど
        - IPアドレス、ドメイン名、パスワード認証などでアクセス制御する
        - レスポンスメッセージを送り返す
- ブラウザがレスポンスメッセージの受け取り画面に表示
    - LANアダプタが信号からデジタルデータに戻し、プロトコルスタックが分割されたパケットを集めてデータ部分を取り出して元のレスポンスメッセージに戻し、それをブラウザに渡す
    - ブラウザは`Content-Type`ヘッダーフィールドからデータ形式を判断する
        - MIMEという仕様で規定された
    - `Content-Encoding`ヘッダーフィールドを調べて必要に応じて　元に戻す
    - タグを解釈して文章をレイアウトして画面に表示する
        - 画像データなどはHTTPリクエストのURI部分に画像データのファイル名を書いてリクエストメッセージを送って読み込む
    - 表示が終わったらユーザーがリンククリックなど次のアクションを取るのを待つ