TCP / IP の基本〜アプリケーション層・トランスポート層編〜

# はじめに
TCP / IP のアプリケーション層とトランスポート層について簡潔にまとめております。
この記事は以下の記事の続編となり、合わせて確認していただくと幸いです。

https://qiita.com/yukitkns/items/72c8a988a3f616b0150c

https://qiita.com/yukitkns/items/1b5e9da33b86aa68dd31

# TCP / IP とは？
「**TCP / IP**」とは、現在のインターネットで使用されている標準プロトコルである。

そもそもプロトコルとは、いわば「約束事」のことであり、ネットワーク通信するためには「TCP / IP」というルールに従ってプログラムを実装する必要がある。
もしこのルールに従っていなければ、「他の様々な機器とネットワーク通信できない」という制約を受けることになる。

元々、ネットワークのプロトコルはOSメーカーが独自に決定したものを利用していた。（例：Windows は「NetBEUI」、Macは「AppleTalk」)
そのため、同じ LAN 内で接続しているのにも関わらず、OS が異なると通信できないことも多々あった。

しかし、現在はほとんどのプロトコルが TCP / IPをベースにしているため、つながっていれば通信できるのは当たり前になっている。

![スクリーンショット 2024-02-19 19.26.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/3c8ed8e5-56e8-9a78-6438-d01e6747296b.png)


![スクリーンショット 2024-02-19 19.25.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/2c87398e-5051-54e8-6d58-901e3a0f1c78.png)

# TCP / IP プロトコル群と OSI 参照モデル
TCP / IP プロトコル群はインターネットで主に使用する TCP（Transmission Control Protocol）と IP（Internet Protocol）を中心に、実際のアプリケーションに実装することを考えて作成されたモデルである。

同じようなモデルとして **OSI 参照モデル**が挙げられる。

OSI 参照モデルは、ネットワークでの通信に必要なプロトコルを7つの階層に分けてまとめられたモデルである。

OSI 参照モデルはネットワークシステムにとって理想的なモデルではあるが、必ずしも現実のプログラムとして対応するものではなく、
逆に TCP / IP プロトコル群は前述の通り、アプリケーションを実装することを重点に置かれているため、こちらのモデルの方が現在動作するネットワークシステムに迎合している。

そのため、TCP / IP プロトコルがインターネットで使用されており、現在、世界で最も普及しているモデルとなっている。

ただし、両モデルとも基本的な考え方が同じで、対応関係は以下のようになっている。
![スクリーンショット 2024-02-20 7.16.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/2a34a99e-3a6b-15a0-0b74-2c0d9ce62516.png)

TCP / IP プロトコル群の方が階層は少なくシンプルなため、実装向けな構成となっている。

# TCP/ IP の階層構造
TCP / IP は4階層構造のモデルを採用している。
![スクリーンショット 2024-02-20 7.41.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/3091015d-22f1-a3fe-d414-1c27bd1e36c0.png)

階層構造とは、層（レイヤ）を重ね、処理する役割が上から下へ、各層は自分の役割に応じた処理のみ行うという構造である。

階層構造になっていると、各層は独立して機能化し、変更が容易となる。
例えば、トランスポート層である TCP が変更されても、他の層にはほとんど影響を与えない。
これにより、新しい技術や機能の導入が比較的容易になる。
また、階層ごとに機能が分割されているため、トラブルが発生した場合に特定の階層に焦点を当てて問題解決ができる、といった利点も挙げられる。

# ネットワークの階層を通過するデータの様子
送信側は以下のフローでデータが渡される。

![スクリーンショット 2024-02-20 9.38.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/69ba6d5d-0c2f-820f-eef4-103957f845ef.png)

**1. 分割されたデータ（「セグメント」と呼ぶ)に、宛先のプログラムを表す情報を付加する
2. 宛先のコンピュータを表す情報を付加する
3. ハードウェアに信号を流すために必要な情報を付加する
4. 電気や光の信号として送られる**

また、ネットワークインターフェース層を通過した後のハードウェア内のデータは以下の状態となっている。
![スクリーンショット 2024-02-20 10.12.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/ddc548f4-7e46-c8c5-dd61-72eda56ef2b1.png)

同様に受信側は以下のフローでデータが渡される。
![スクリーンショット 2024-02-20 10.28.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/1ef83e64-28a7-9e15-4345-42b91e5b1bcb.png)

**1. ヘッダやトレーラを取り除いてインターネット層に渡す
2. 自分宛のデータであることを確認したら、トランスポート層に渡す
3. 全てのデータが届いたことを確認して、データを結合して宛先のプログラムに渡す**

# アプリケーション層
TCP / IP のアプリケーション層は、実際のサービスを提供する層で、
Web ページの表示の場合は、Web サーバと Web　ブラウザがアプリケーション層にあたり、リクエストした URL と表示すべき Web ページのデータのやり取りを行う。

アプリケーション層の詳細については、HTTPを例にした以下の記事にて紹介している。

https://qiita.com/yukitkns/items/1b5e9da33b86aa68dd31

## 代表的なアプリケーション層のプロトコル
| プロトコル | 説明 |
|:-:|:-:|
| HTTP  | Web サーバと Web ブラウザの間で、Web ページのやり取りをする |
| POP、SMTP、IMAP  | メールの受信、送信、保管を行う |
| SMB、AFP | LAN 内でファイルを共有する |
| FTP  | サーバとファイルのやり取りをする |
| Telnet、SSH  | サーバを遠隔操作する |
| DNS | URL と IP アドレスを相互変換する|
| DHCP | LAN 内のパソコンにプライベート IP アドレスを割り当てる |
| SSL/TLS | 通信データを暗号化して、クレジットカード情報などの重要なデータを安全にやり取りできるようにする |
| NTP | ネットワーク機器が持つ時計を同期する |
| LDAP | ネットワークの構成機器を一元的に管理するディレクトリサービスを提供 |

# トランスポート層
トランスポート層はアプリケーション層とインターネット層の間に位置し、両プロトコルの橋渡し役を担っている。
トランスポート層ではデータを確実に届けるため、送信速度やサイズの調整、未到達のデータの再送等を行う「**TCP(Transmission Control Protocol）**」が主に使用される。
他にも「**UDP(User Datagram Protocol）**」というプロトコルもトランスポート層で使用されるが、ここでは TCP のみを説明する。

トランスポート層は、アプリケーションデータをネットワーク上で転送可能なサイズに分割し、アプリケーションを識別するために「**ポート番号**」を各データに割り当てる。
ポート番号を割り当てることで、同じクライアント内で複数のアプリケーションを同時に通信できる。

## ポート番号
ポート番号は 0 〜 65535 番の数値を利用し、範囲によって「**システムポート**」「**ユーザーポート**」「**ダイナミックポート**」の3つに分かれている。

![スクリーンショット 2024-02-20 11.37.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/506facbc-ce2a-1ee4-518c-211ad3ba2e9c.png)

**サーバ側が利用する主なシステムポートの番号はあらかじめ決まっている。**
| ポート番号 | 対応するプロトコル |
|:-:|:-:|
| 20番  | FTPのデータ転送用  |
| 21番  | FTPのデータ制御用  |
| 22番  | SSH（遠隔操作）  |
| 23番  | Telnet（遠隔操作）  |
| 25番  | SMTP（メール）  |
| 80番  | HTTP（Web）  |
| 110番  | POP3（メール）  |
| 143番  | IMAP（メール）  |
| 443番  | HTTPS(Web）  |

**クライアントが利用するポート番号はダイナミックポートの範囲（49152番〜65535番）からランダムに割り当てるので、どれが何番を使っているのかは決まっていない。**

## クライアントとサーバが接続するまでの流れ
クライアントとサーバが接続するまでの流れは大まかに以下となっている。
![スクリーンショット 2024-02-20 15.02.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/cfd3a773-72ba-a793-817e-213625f92747.png)

**1. クライアント側はランダムにポートが割り当てられる。Web サーバの場合は 80 番ポートで接続を待っている状態となっている
2. 上図の例で 49153 番が割り当てられたので、49153 番を使用して、サーバ側に接続を要求する
3. Web サーバが接続を受け入れると、通信可能な状態になる。クライアント側は通信が終わったら、割り当てられたポートの解放を行う**

接続の詳しい流れについては「**3 ウェイハンドシェイク**」で詳しく説明する。

## TCPヘッダ
トランスポート層ではセグメントに以下の「**TCPヘッダ**」を付与して、インターネット層にデータを転送する。
![qiita-ページ7.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/cabc9481-dbcd-2d99-b903-6241726d0263.png)
| フィールド | サイズ | 説明 |
|:-:|:-:|:-:|
| 送信元ポート番号  | 2バイト  | 送信元のアプリケーションを示すポート番号  |
| 宛先ポート番号  | 2バイト  | 宛先のアプリケーションを示すポート番号  |
| シーケンス番号  | 4バイト  | 送信するデータの順序を管理するためのフィールド  |
| 確認応答番号  | 4バイト  | どこまで受信したかを管理するためのフィールドで、次に送信されるデータのシーケンス番号になる  |
| データオフセット  | 4ビット  | TCP ヘッダの長さ（4 バイト単位）  |
| 予約  | 6ビット  | 未使用  |
| コントロールフラグ  | 6ビット  | ※以下に記載  |
| ウィンドウサイズ  | 2バイト  | 確認応答を行わずに受信できるデータのサイズ   |
| チェックサム   | 2バイト  | TCP セグメントにエラーがないかをチェックするための値が設定される  |
| 緊急ポインタ  | 2バイト  | URG フラグが1の場合、緊急データの位置を示すための値が設定される  |
| オプション  | 可変長 | 追加のデータ（4 バイト単位）  |

この中で「**コントロールフラグ**」について、上位ビット（0 ビット目）から 1 ビットずつ次の用途で使われる。
| フラグ名 | 説明|
|:-:|:-:|
| URG（Urgent）  | このビットが 1 の場合、データ中に緊急データが含まれていることを示す  |
| ACK(Acknowledgement）| 送信元からの要求に対する応答を返す場合にこのビットを1に設定する。最初の TCP 接続要求以外は、ACK フラグが 1 になる  |
| PSH（Push）  | このビットが 1 の場合、データは直ちに上位層のアプリケーションに引き渡す必要がある  |
| RST（Reset）  | このビットが 1 の場合、現在の TCP 接続を破棄する  |
| SYN（Synchronize）  | 接続要求を送信する場合、このビットを 1 に設定する  |
| FIN（Finish）  | このビットが 1 の場合、これ以上データを受信する必要がないことを示す  |

## 3 ウェイハンドシェイク
「**クライアントとサーバが接続するまでの流れ**」にて通信の大まかな流れについて説明したが、ここでは通信の詳しい流れについて説明する。

TCP では通信を開始する前に、データの送信元と宛先間で接続を確立する必要があり、「**3 ウェイハンドシェイク**」という方法を用いて行なっている。

接続を開始する際は、以下の流れで行う。

**1. クライアントは最初にサーバに接続を確立するために「**SYN**」フラグが立ったデータを送信する
クライアントが新しい通信を開始するとき、ランダムに選ばれたクライアントのポート番号を使用する
2. サーバはクライアントから「SYN」フラグが立ったデータを受信し、接続要求を受け入れたことを示す「**ACK**」フラグと、自身も新しい通信を開始するために「SYN」フラグを立てたデータをクライアントに返す
3. クライアントはサーバからの応答を受信し、最後に「ACK」フラグを立てたデータをサーバに送信して通信が確立されたことを通知する**

![スクリーンショット 2024-02-20 16.20.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/8200986d-c952-65b7-c9c5-ef04e9c06b95.png)

また接続開始時に最大セグメントサイズ（「**MSS（Maximum Segment Size）**」）のすり合わせを行い、サイズの小さいものが接続時の最大サイズとして使用される。

***

接続を終了する際は、以下の流れで行う。
**1. 通信が終了する際、クライアントは「ACK」フラグと「**FIN**」フラグが立ったデータをサーバに送信する。
これにより、クライアントはサーバに「これ以上データを送るつもりはない」と通知する。
2. サーバはクライアントからの「FIN」フラグが立ったデータを受信、確認応答として「ACK」フラグが立ったデータをクライアントに返す。
この時点でサーバはまだデータを送り続けることができる。
3. サーバがデータの送信を終了したら、サーバも自身の通信を終了するために「FIN」フラグが立ったデータをクライアントに送信する
4. クライアントはサーバからの「FIN」フラグが立ったデータを受信し、確認応答として「ACK」フラグが立ったデータをサーバに送信する。
この時点でクライアントとサーバの通信は完全に終了する**

![スクリーンショット 2024-02-20 16.35.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/c4c7f2f5-359d-99ee-85a7-7a0e32b81fcc.png)

## シーケンス番号と 確認応答番号
**シーケンス番号と確認応答番号（ACK 番号）は、TCP 通信においてデータの送受信を管理するために使用される番号である。**

接続確立時は**シーケンス番号**は 1 ずつ加算されるが、データ転送中は送ったデータのバイト数を加算する。
また、受け取ったデータのバイト数は**確認応答番号**に加算するので、2つの番号を見れば何バイトのデータをやり取りしたのかがわかる。
以下の図の場合はクライアント側で送信したデータはシーケンス番号から 800 バイトで、受信したデータは確認応答番号から 2,000 バイトとなる。

![スクリーンショット 2024-02-21 22.04.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/a8498154-b5da-52dc-6c28-6e652dd62198.png)

データ転送時に確認応答を待ってから次のデータを送るのでは、通信が完了するまでに時間がかかってしまうため、
TCP では確認応答を待たずにまとめてデータを送信することで通信を高速化することができる。
この場合、同じ確認応答番号が3回連続で届いた時のみ失敗とみなされる。
この仕組みを「**ウィンドウ制御**」と呼ぶ。

![スクリーンショット 2024-02-22 7.31.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/84b78fcf-028c-5f69-4410-fe8623090255.png)

まとめて送る量が多すぎると、受信側が処理しきれなくなる場合があり、その際はデータを一時的に溜めておく「**バッファ**」という記憶領域が活用される。
TCP ヘッダーの「**ウィンドウサイズ**」には、バッファの空き容量が含まれており、これを送信することでお互いがどのくらいまとめて受信できるかを伝え合う。
また、受信可能な容量を適宜送信側に通知する仕組みがあり、これを「**フロー制御**」と呼ぶ。
![スクリーンショット 2024-02-22 9.37.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/aa7bdd48-f3dd-2ff5-5fd6-450d8f87367e.png)

補足として、バッファが満杯になるとウィンドウサイズ 0 の確認応答が送られ、データの送信は一時停止する。
送信再開のタイミングを把握するため、送信側は「**ウィンドウプローブ**」と呼ばれるデータを送信、その確認応答によってウィンドウサイズを確認する。

## 参考文献

https://www.amazon.co.jp/gp/product/B0CR62KT8C?notRedirectToSDP=1&ref_=dbs_mng_calw_1&storeType=ebooks

https://www.sbcr.jp/product/4815623333/