Networkまとめ①

URLからプロトコルスタックまで

Posted by     "sora" on Tuesday, May 23, 2023

Networkまとめ①


0章 初めに

  • 「ネットワークはなぜつながるのか」という本を学びながら、その他いろいろ調べたことのまとめです
  • このサイトを見る前に上記の本をどうぞ 凄くわかりやすいです

1章 ブラウザ

1.1 URLの入力

  • ブラウザにURLを入力する
    • URLにはプロトコルの種類が書いてある HTTPやFTPなど
  • ブラウザはURLを解読する
    • プロトコル//webサーバー名/ディレクトリ名/ファイル名 が一般的
    • このURLを見てHTTPプロトコルでもってWebサーバーにアクセスするのがやりたいこと
  • URLをもとにリクエストメッセージを作成する

1.2 リクエストメッセージ

  • リクエストライン
    • メソッド /URI HTTPのバージョンという書き方になっている
リクエストライン:
POST /index.html HTTP/1.0
  • メッセージヘッダー
    • リクエストラインでは足りない情報を書き留めておく場所
    • リクエストライン直下に記述する
    • 多数の項目が仕様として定められている
    • 空白行を挟んだ先がメッセージボディとなる
メッセージヘッダー:
Accept: image/gif, image/jpeg, */*
Accept-Language: ja
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (Compatible; MSIE 6.0; Windows NT 5.1;)

メッセージボディ:
〜〜〜〜〜〜〜〜〜〜

2章 DNS

2.1 ブラウザの役割

  • ブラウザは解析するのみでネットワークに送信する機能は持っていない
    • OSに依頼して送ってもらう必要がある
    • その際にドメイン名ではなくIPアドレスが必要になる
    • ブラウザはリゾルバを使ってDNSへの問い合わせを行う

2.2 IPアドレスの基本

  • TCP/IPの考え方によって作られている
  • サブネットと呼ばれる無数の小さなネットワークがルーターによって接続されることでネットワークが出来上がっているという感じ
    • サブネットはハブに何台かのPCが繋がっているイメージ
  • サブネットを識別するものがネットワーク番号
  • サブネット内でPCを識別するものがホスト番号
  • IPアドレスはネットワーク番号とホスト番号で構成されている
    • その境目はサブネットマスクと呼ばれるもので判断できる
    • サブネットマスクが全て0でサブネット自体を表す
    • サブネットマスクが全て1でブロードキャストを表す
      • ブロードキャストはサブネット内全機への送信を表す

2.3 ドメインとDNS

  • IPアドレスは効率が良いが覚えづらい
  • ドメインは覚えやすいが効率が悪い
  • なので人間はドメインを使い、ルーターはIPアドレスを使う
  • ドメインとIPアドレスの橋渡しをしているのがDNS
    • ドメインが分かればIPが分かり、IPが分かればドメインが分かる

2.4 DNSサーバーへの問い合わせ方法

  • DNSを使用してIPアドレスを調べる仕組みを名前解決(ネームリゾリューション)という
  • その名前解決を担当するプログラムをリゾルバと呼ぶ
  • リゾルバの実態はSocketライブラリというライブラリで簡単に行える
    • Socketライブラリはネットワーク機能を集めた部品集
    • x = gethostbyname("www.aaa.com")のようにして問い合わせる
  • ブラウザはSocketライブラリを利用して名前解決を行う

2.5 リゾルバの動き

  • ブラウザがリゾルバを動かすと制御がリゾルバへ移る
    • その間ブラウザには待ってもらう
  • リゾルバはDNSサーバーへの問い合わせメッセージを作成する
  • その問い合わせメッセージをプロトコルスタックへ依頼して送信動作を行う
    • プロトコルスタックはOS内部に組み込まれている制御用ソフトウェア
    • 別名「プロトコルドライバ」「TCP/IP ソフト」
  • 送信動作が完了し、DNSから送られてきたものをプロトコルスタックを経由して受け取り、リゾルバが解読して、指定してある場所にIPアドレスを格納する
  • DNSサーバーのIPアドレスが必要だがTCP/IPの設定で事前に定められている

2.6 DNSサーバーの仕組み

  • 基本的な流れは、クライアントから問い合わせを受け取り、情報を回答する
  • 問い合わせには名前、クラス、タイプの3種類が含まれている
    • 名前は.comなどのサーバー名など
    • クラスはインターネットを表すIN以外は現在では使われない
    • タイプは名前に対応している返答項目がどのような種類かが書かれる
      • IPアドレスなら「A」メールなら「MX」など
  • DNSには関連づけられた表が用意されていて、該当する返答項目を送り返す
    • 1件分をソースレコードと言い、それが集まって表になっている
名前       クラス タイプ 返答項目
www.aaa.co.jp  IN    A     192.168.1.27
aaa.com        IN    MX    1 mail.aaa.com
mail.aaa.com   IN    A     192.168.1.28

2.7 ドメイン

  • 1台のDNSに全て登録することは不可能なのでドメインという階層構造をとっている
    • 一番最上位にルートドメインが存在し、その下にjpやcomなどのDNSが、さらにその下にcoがという感じ
    • 下位のDNSの情報をその上位のDNSが持ち、その上位のDNSの情報を…という感じで最後にはルートドメインにたどり着く
    • そうすることで全てのレコードをルートドメインにアクセスするだけで辿ることが出来る
    • また、全てのDNSにルートドメインのIPを登録しておくことでどこかのDNSサーバーにアクセスすればルートドメインを経由して辿り着くことが出来る
  • 問い合わせを受けたDNSサーバーはこのようにIPアドレスを調べ、クライアントへ回答する
  • 現実のDNSは上位と下位のDNSサーバーが登録されているケースもあるため、毎回一つづつ辿っていくわけではない

2.8 DNSキャッシュ

  • DNSサーバーには一度調べた名前をキャッシュとして保存しておく機能がある
    • これにより、過去に問い合わせがあったものに即座に回答することが出来る
    • 存在しないという回答も保存が出来る
  • 時間が経つと登録情報が変更されている場合もあるので、一定期間で削除されるように設定されている

3章 プロトコルスタック

3.1 データの送受信の概要

  • リゾルバによってサーバーのIPアドレスを手に入れたら、その相手に対してメッセージを送信するために、Socketライブラリを介してプロトコルスタックへ依頼する
  • Socketライブラリを用いたデータ送受信は自分と相手間でパイプを繋ぐイメージ
    • このパイプの中にデータを入れると相手に届く双方向の通り道
  • このパイプを作る動作、繋がったパイプにデータを流す操作、終了時にパイプを外す動作が大まかな流れになる

3.2 ソケットと通信動作

  • パイプで繋いだ時の出入り口をソケットと呼ぶ
  • サーバー側でソケットが作られ、クライアント側がそのソケットにパイプを繋げにいくイメージ
ざっくりとした通信動作
1. Socketライブラリのsocketを呼び出し、ソケットを作成
2. ディスクリプタと呼ばれるソケット識別番号が帰ってくるのでメモリに記録
3. Socketライブラリのconnectを呼び出し、「ディスクリプタ」「サーバーIPアドレス」「ポート番号」を指定してプロトコルスタックへ接続を依頼する
//パイプ接続完了
4. アプリはソケットに触れないので都度Socketライブラリのwriteへ依頼する
5. 返答をSocketライブラリのreadが受け取って受信バッファへ格納する
6. Socketライブラリのcloseで切断フェーズを依頼する
//通信終了

3.3 プロトコルスタックとは

  • OS内部に組み込まれている制御用ソフトウェアでSocketライブラリにより操作される事が多い
  • プロトコルスタックには様々な部品で構成されている
    • TCPプロトコルによる送受信
    • UDPプロトコルによる送受信
    • IPプロトコルによる通信制御
      • ICMPによるエラー制御
      • ARPによるMACアドレス検索
  • プロトコルスタックはLANドライバへ依頼をし、LANドライバがLANアダプタを用いて送受信を行う
//上から下へ依頼する
上位
|    WEBブラウザ
|    Socketライブラリ
|    プロトコルスタック(TCP、UDP、IP)
|    LANドライバ
|    LANアダプタ
下位
  • プロトコルスタックは内部にメモリ領域があり、そこに様々な制御情報が記載されている
    • 通信相手のアドレスやポート番号、通信の状況などなど
    • この情報がソケットの実態と言える
    • ソケットはWindowsの場合、$ netstat -anoコマンドで確認できる
  • プロトコルスタックはそこに保存された情報を元に様々な通信動作を行なっている

3.4 サーバーへの接続に必要なこと

  • connectに必要な情報をプロトコルスタックへ渡す
  • 相手方にも自分のアドレスやポート番号を知ってもらう
  • 送受信するデータを一時的に保存しておく場所の確保
    • バッファメモリと呼ぶ
  • 上記の三つが必要なほか、二つの制御情報が必要となる
    • ヘッダーに書き込まれる情報
      • TCPヘッダーと呼ばれ、TCPプロトコルの仕様によって決められている

3.5 実際の接続流れ

  • アプリケーションがSocketライブラリのconnectが呼び出される
  • プロトコルスタックのTCP部分に伝わり、データ送受信開始のヘッダーを作成する
    • ポイントはお互いのポート番号
    • コントロールビットのSYNを1にする
  • IP担当へ渡して送信の依頼をする
  • ネットワーク内を通ってサーバーへ届く
  • サーバーのIP部分が受け取り、TCP部分へ渡す
    • IPヘッダを確認し、自分宛か分割されているか、TCPなのかなどをチェックする
  • TCP部分がTCPヘッダを調べ、該当するソケットを探し出す(コピーする)
  • 該当ソケットに必要情報を記録する
    • 必要情報は送信元IPやポート番号など
  • コントロールビットのACKを1にしたTCPヘッダーを作り、IP部分に頼んで送り返す
  • クライアント側が受け取ったら、ソケットに相手の情報を記録し、サーバーへACKビットを1にしたものを送り返す
  • 届いたら接続動作終了
TCPヘッダ詳細
送信元ポート&宛先ポート  :ポート番号
シーケンス番号       :分割時に送信データの何バイト目か
確認応答番号(ACK)     :相手から来たシーケンス番号+データサイズ
コントロールビット     :1を入れてフラグ管理をする
              :ACK:確認応答番号が有効&正しく届いたかの確認
              :SYN:シーケンス番号があるよの確認など
ウインドウサイズ      :受信側が一度に受け取れる最大数を通知する

3.6 データの送受信概要

  • アプリがwriteを呼び出し、プロトコルスタックが受け取る
    • プロトコルスタックは中身を関知しない
    • writeにはデータの長さが必要
  • プロトコルスタックが長さをチェックする
    • MTUパラメータを元にそこからヘッダーを引いたMSSで判断する
    • MTU:1パケットの最大   MSS:MTU ー(マイナス) ヘッダー
  • 長い場合は分割して送信、短い場合は貯めておいて いっぱいになるOR一定時間で送信する
    • TCPには一定時間などの規定が無く、プロトコルスタックに任されている
    • アプリ側からも貯めないなどの指定ができる
  • 相手に届いていたらACK番号が返ってくる 来なければ送り返す

3.7 パケットの分割と応答確認

  • 開始時に通知されたシーケンス番号を、分割したものに着けて送る
  • 確認応答番号が返ってくるので、それをシーケンス番号として次のものを送る
    • 確認応答番号が返ってこなかった場合は再度送り返す
  • この流れを双方で行い、常に届いたかを確認し合いながら通信する
    • これにより、他の地点で送信成功の確認をする必要がなくなる

3.8 ウインドウ制御方式

  • ACKが返って来るまで待っていたのでは時間がかかるので、どんどん送ってしまおうというのがウインドウ制御方式
  • ただ、受け取ったデータの処理が終わらないうちに受け取ってしまうと、いつかメモリが溢れてしまう
  • そこでTCPヘッダのウインドウ欄で受信バッファの空きを知らせ、溢れを防ぐ
    • ウインドウ通知単体で送ってしまうと大変なので、ACK通知を少し待ってもらい、そこに相乗りさせてもらう

3.9 相手との切断動作

  • どちらから切断に入るかはアプリ次第
  • サーバー側からの場合はサーバー側のアプリケーションがSocketのcloseを呼び出す
  • その後、サーバーのプロトコルスタックがFINに1をセットしたTCPヘッダを作り、IPに送信してもらう
  • クライアント側でFIN1が届いたら、ACK番号をサーバーへ送り返し、クライアントのreadに合わせてその旨を伝える
  • クライアント側もcloseを実行し、通信終了
  • その後、しばらく待ってからソケットを削除する
    • 最後のACKが届かなかった場合の保険

参考にさせていただいた文献

https://bookplus.nikkei.com/atcl/catalog/07/P83110/
https://ja.wikipedia.org/wiki/Domain_Name_System
https://www.infraexpert.com/study/tcpip8.html
https://wa3.i-3-i.info/word12209.html