TCPのおかげでデータが確実に届く！

## データってどうやって送信されているの？
私は[前の記事](https://qiita.com/tamago3keran/items/dce288a5aa47787f313c)で、HTTPに則ってWebブラウザとWebサーバの通信に適したアプリケーションデータ（リクエスト・メッセージ）が作成されることを理解しました。

しかし、実際にそのデータが送信される時の仕組みについては理解できていません。今回は相手にデータを届けるためのプロトコルである、`TCP`についてまとめていきます。

## これは何の記事か？
プログラミングしか学んでこなかったエンジニアが本を参考に、`TCP`の仕組みについて**大まか**にまとめた記事です。

**対象読者**

- プログラミングしか学んでこなかった
- `TCP`ってなんですか？？

## この記事のゴール
- `TCP`でのデータ通信の特徴について、大まかに説明ができる。

## 全体像の把握
この記事は、WebブラウザがWebサーバに対してデータを送信するときの、トランスポート層で行われる処理のうち、`TCP`についてまとめたものになります。（赤枠の部分）

![network-OSI参照モデル (3).png](https://qiita-image-store.s3.amazonaws.com/0/186009/d5eea5b9-5e10-8a43-e7af-d2bcde56236f.png)

## トランスポート層の役割は？
トランスポート層の役割は、「データを通信相手に届けること」であり、通信相手のアプリケーション層にあるどのプロトコルに渡すかまで責任を持ちます。

## TCPとUDPの違い
トランスポート層は上記の役割を担いますが、それを実現しているプロトコルが`TCP`と`UDP`です。取り扱うデータの性質によって使用するプロトコルが異なります。

プロトコル|取り扱うデータの特徴|例
:--:|:--:|:--:
TCP|信頼性が必要とされるデータ|Web、メール、ファイル共有など
UDP|即時性が必要とされるデータ|DNS、音声、映像など

まとめると、`TCP`は**通信相手にデータを確実に届ける（ような仕組み）けど、通信に時間がかかるプロトコル**であり、`UDP`は**データを送ったら送りっぱなしで信頼性は低いけど、通信に時間がかからないプロトコル**という特徴を持っています。

## なぜ通信にかかる時間に違いがあるのか？
なぜ`TCP`と`UDP`とでは、通信にかかる時間に違いがあるのでしょうか。これは`TCP`と`UDP`でのやりとりの様子をそれぞれ知ることで理解することができます。

今回はまず`TCP`に則った通信が実際にどのように行われるかを紹介していきます。

## TCPでの通信の流れ
![network-通信の流れ.png](https://qiita-image-store.s3.amazonaws.com/0/186009/dee15e0e-2399-54ca-a217-156aab3020ab.png)

### 1. 準備（ソケットの作成）
#### Webブラウザ
アプリケーション（ここではWebブラウザ）が`Socket`ライブラリの`socket`というプログラムを呼び出して、プロトコル・スタックにソケットを作成するよう依頼します。

#### クライアント側のプロトコル・スタック
ソケットひとつ分のメモリー領域を確保することで、そこにソケットの制御情報を記録していく準備を行います。この段階では初期状態であることを記録します。

### 2. 接続（three-way handshake）

![network-3ウェイ・ハンドシェイク.png](https://qiita-image-store.s3.amazonaws.com/0/186009/40769d30-00b9-8399-70fc-cf2463aea463.png)

#### Webブラウザ
Webブラウザが`Socket`ライブラリの`connect`を呼び出して、プロトコル・スタックに接続処理を依頼します。

#### クライアント側のプロトコル・スタック
クライアントがサーバに対して「通信しましょう！」という合図を送ります。

具体的に説明すると、クライアント側のプロトコル・スタックが「送信元と宛先のポート番号の情報」と「コントロール・ビットの`SYN`を1に設定した」`TCP`ヘッダーを作成し、それをサーバ側のプロトコル・スタックに送信します。

#### サーバ側のプロトコル・スタック
受け取った`TCP`ヘッダー内の宛先ポート番号からソケットを特定します。ソケットが特定できた場合は、そのソケットに接続動作が進行中という情報を記録します。

そのあと、「受け取りました！」という事実と「通信しましょう！」という合図をクライアントに送り返します。

具体的に説明すると、サーバ側のプロトコル・スタックが「送信元と宛先のポート番号の情報」と「コントロール・ビットの`SYN`と`ACK`を1に設定した」`TCP`ヘッダーを作成し、それをクライアント側のプロトコル・スタックに送り返します。

#### クライアント側のプロトコル・スタック
返ってきた`TCP`ヘッダーの`SYN`ビットが1であれば、ソケットにサーバ側に接続完了を示す情報を記録します。

最後に`TCP`ヘッダーを受け取ったことをサーバ側に伝えるために、`ACK`ビットが1の`TCP`ヘッダーをサーバに送り返して、サーバがそれを受け取った時点で、接続完了となります。

### 3. 送信（リクエスト・メッセージの送信）
![network-データ送受信.png](https://qiita-image-store.s3.amazonaws.com/0/186009/b5064912-2f23-4964-947e-c00110408b73.png)

#### Webブラウザ
`Socket`ライブラリの`write`プログラムを呼び出して、送信データ（ここではリクエスト・メッセージ）を指定したデータ長に分割した状態でプロトコル・スタックに渡します。

#### クライアント側のプロトコル・スタック
`MSS`（ヘッダーを除いて1つのパケットで運べる`TCP`データの最大長）を超えるか、ある一定時間待った後に、バッファ・メモリー領域にたまったデータを送信するようにします。

またバッファ・メモリー領域にたまったデータが`MSS`を超える場合は、`MSS`のサイズに分割してデータ送信を行うようにします。

クライアント側のプロトコル・スタックは、データを分割する際にデータ断片の先頭が通信開始してから何バイト目に相当するかを数えておきます。そしてその数を`シーケンス番号`として`TCP`ヘッダーに記載します。

#### サーバ側のプロトコル・スタック
サーバ側のプロトコル・スタックがデータ断片をしたら、シーケンス番号にデータ断片のバイト数を加算した`ACK`番号を`TCP`ヘッダーに追加します。そうすることで、クライアント側のプロトコル・スタックに何バイト目までデータを受け取ったことを伝えます。

こうすることで、データの取りこぼしを検知することができます。例えば、`ACK`番号1001までデータを受信したのに、次に受信したデータのシーケンス番号が2001だった場合、1001~2001までのデータが抜けてしまっていることにわかります。

また送信したデータに対応する`ACK`番号が返ってこなかった場合、送信側がデータを送り直すという強力な仕組みを備わっています。

![network-データ.png](https://qiita-image-store.s3.amazonaws.com/0/186009/907f0b09-c6c4-0031-ff3c-7acd2c60a6b1.png)


このような仕組みによって、データを確実に通信相手に届けるようにしています。

### 4. 受信（レスポンス・メッセージの受信）
3.と逆になるだけなので省略

### 5. 切断（ソケットの抹消）
![network-切断処理.png](https://qiita-image-store.s3.amazonaws.com/0/186009/3e1f3659-3a63-4f06-1acd-c352cfcfa056.png)

#### サーバ側のアプリケーション
サーバ側のアプリケーションが`Socket`ライブラリの`close`を呼び出して、サーバ側のプロトコル・スタックに切断処理を依頼します。

#### サーバ側のプロトコル・スタック
サーバ側のプロトコル・スタックがコントロール・ビットの`FIN`を1にセットした`TCP`ヘッダーを作成し、クライアントに送信します。その際に、サーバ側のソケットに切断動作に入ったという情報も記録します。

#### クライアント側のプロトコル・スタック
`FIN`が1にセットされた`TCP`ヘッダーを受けとったら、受け取ったことをサーバ側に知らせるために、`ACK`番号を送り返します。

#### Webブラウザ
Webブラウザが`Socket`ライブラリの`read`プログラムを呼び出すことで、クライアント側のプロトコル・スタックにより、データを全て受信したことを把握します。それがきっかけとなって、Webブラウザが`Socket`ライブラリの`close`プログラムを呼び出して、クライアント側のプロトコル・スタックに切断処理を依頼します。

#### クライアント側のプロトコル・スタック
クライアント側のプロトコル・スタックも、コントロール・ビットの`FIN`を1にセットした`TCP`ヘッダーを作成し、サーバに送信します。すると、サーバから`ACK`番号が返ってくるはずなので、サーバとのやりとりが終了します。

## まとめ
`TCP`に則った通信では、特定のデータ長に分割したデータ断片をクライアントとサーバがお互いに確認を取り合いながら送受信を行う。途中でデータの取りこぼしなどがあったら再送信することで、確実に全てのデータを送受信できる仕組みになっている。

## 参考にした本

- [イラスト図解式 この一冊で全部わかるサーバーの基本](https://www.amazon.co.jp/%E3%82%A4%E3%83%A9%E3%82%B9%E3%83%88%E5%9B%B3%E8%A7%A3%E5%BC%8F-%E3%81%93%E3%81%AE%E4%B8%80%E5%86%8A%E3%81%A7%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8B%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AE%E5%9F%BA%E6%9C%AC-%E3%81%8D%E3%81%AF%E3%81%97-%E3%81%BE%E3%81%95%E3%81%B2%E3%82%8D-ebook/dp/B01DBQQ80A)
- [ネットワークはなぜつながるのか 第２版](https://www.amazon.co.jp/%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AF%E3%81%AA%E3%81%9C%E3%81%A4%E3%81%AA%E3%81%8C%E3%82%8B%E3%81%AE%E3%81%8B-%E7%AC%AC%EF%BC%92%E7%89%88-%E6%88%B8%E6%A0%B9-%E5%8B%A4-ebook/dp/B077XSB8BS)
- [TCP/IPの絵本 第2版 ネットワークを学ぶ新しい9つの扉](https://www.amazon.co.jp/dp/4798155152/ref=asc_df_47981551522599934/?tag=jpgo-22&creative=9303&creativeASIN=4798155152&linkCode=df0&hvadid=295719984664&hvpos=1o1&hvnetw=g&hvrand=6310701229822249560&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=20636&hvtargid=pla-526160327923&th=1&psc=1)

## 所感
`TCP`は奥が深すぎます。。。今回この記事でまとめきれなかったことも数多くあります。。。ウィンドウ・サイズを使って効率的に通信を行う仕組みなどもまとめたかったのですが、時間の都合上ここまでにしました。

次回は`UDP`の仕組みを紹介して、`TCP`と`UDP`の違いについてまとめようと思います。