ネットワークやTCP/IPやHTTPの基本（初学者向け）

[Ateam Lifestyle x cyma Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ateam-lifestyle-cyma)、10日目は株式会社エイチームライフスタイルの @ryosuketter が担当します。

# 自己紹介

前職では、Web制作事業にて、HTML、CSS、JavaScriptを使ってインタラクティブなWeb表現を得意としていましたが、バックエンドやインフラもできるエンジニアになりたいと思い、それができる環境として、株式会社エイチームライフスタイルにて、今年からお世話になっています。
現在、バックエンドのWebエンジニアとして挑戦中で、仕事では主にRailsやReactなどとを日々触っております。

# この記事の対象者

- これからネットワークやHTTPの勉強を始める方
- パフォーマンス改善に取り組みたいけどネットワークの知識はあまりない方
- フロントエンドエンジニアの方

## なぜフロントエンドエンジニアにも読んでもらいたいか？

Webページの表示速度に関する著書「ハイパフォーマンスWebサイト」の著者曰く「[エンドユーザーに対するレスポンスタイムのうち80〜90%はWebフロントエンドで発生している](https://www.stevesouders.com/blog/2012/02/10/the-performance-golden-rule/)」と言われているので、**これからパフォーマンス改善をしたいけど、なにからやったらいいか分からないとお悩みのフロントエンドエンジニアの方に読んでいただきたいと思っております。**

Webフロントエンドを高速化するポイントの１つに、サーバから配信されるHTMLやそのサブリソース（CSS,JSや画像ファイルのこと）をダウンロードする過程（ネットワーク処理）を最適化することが挙げられます。

ネットワーク処理を最適化するためには、TCP/IPやHTTPの理解が必要になります。なので、これまでネットワークやHTTPをろくに勉強してこなかった自分のような人が知っておくべき「ネットワークやHTTP」の勉強のために、覚えたことを書きたいと思います。

**これからネットワークやHTTPの勉強をはじめる「最初の一歩」の参考**になれば幸いです。

# ネットワークやHTTPを勉強しようと思ったきっかけ

普段は、業務に直結する、Rails や React などの勉強をしていますが、そんな中、以下のツイートを発見しました。

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">Webエンジニアになりたい、なりたての人が本来真っ先に勉強すべきはRailsでもフロントエンドでもなく、TCP/IPです。入門書くらいは手元に置いて理解できるまで読み進めておくべきですね。</p>&mdash; ひさじゅ@すたてく社長（PG） (@hisaju01) <a href="https://twitter.com/hisaju01/status/1064678372125552640?ref_src=twsrc%5Etfw">November 20, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

TCP/IPと聞くと、ネットワークエンジニアやインフラエンジニアの仕事で、自分はアプリケーションレイヤーのエンジニアなので、そんなの関係ないや、と（恥ずかしながら）思っていました。

しかし、エイチームライフスタイルに入社して以降、バックエンドのエンジニアとして、例えばRailsを触っていると、HTTPメソッド（のCRUDとか）を意識してないといけないシーンがあります。

そんなところから、TCP/IPも含め、ネットワークやHTTPの勉強しないと思いました。

まずは、それぞれの基礎知識から見ていきましょう。

# ネットワーク, TCP/IP, HTTPの基礎知識

はじめに、Webページが表示されるまでの過程を例にとって、ネットワーク処理の流れをみて行きましょう。

例えば、Webブラウザでエイチームのコーポレートサイト（ https://www.a-tm.co.jp/ ）にアクセスするときを考えます。

まず、IPアドレスを特定するため、DNSサーバに通信が行き、URLに対応したIPアドレスを取得します（キャッシュがない場合）。URLに対応したIPアドレスがわかった（名前解決した）ら、IPアドレスは住所の役割があるので、そのIPアドレスが示すWebサーバへ通信することができます。Webサーバが特定できたら、TCPの接続を確立させて、サーバへHTTPのリクエストを送り、サーバからWebブラウザへHTTPのレスポンスが返ってきて、エイチームのサイトがそのまま表示されます。

それぞれの工程をもう少し詳しく見ていきましょう。

## ネットワークとTCP/IPの基礎知識

ネットワークとは複数のコンピュータがお互いに通信を行う仕組みのことです。そして、**TCP/IPとは、コンピュータネットワークの通信ルールの一つ**です。

TCP/IPの通信は、大きく4つの階層に分かれています。

上位のレイヤーから、

- アプリケーション層
- トランスポート層
- インターネット層
- ネットワークインターフェイス層

となっていて、それぞれが以下の表ようなプロトコルを持っています。

|TCP/IPの機能階層  |主なプロトコル  |
|---|---|
|アプリケーション層  |HTTP,DNS,SMTP,FTP  |
|トランスポート層  |TCP  |
|インターネット層  |IP  |
|ネットワークインターフェイス層  | Ethernet  |

TCP/IPによる通信は、**PDU（Protocol Data Unit）** という単位でやりとりされます。PDUは、通信プロトコルで定義されたヘッダ部分と、正味のデータ部分（ペイロード）で構成されています。

通信の際は、送信側のアプリケーション層からヘッダの情報が各階層ごとに付加され積み重なっていき、ネットワークインターフェイス層を介して、受信側のコンピュータへ通信データが届けられます。

![送信側.png](https://qiita-image-store.s3.amazonaws.com/0/14191/118eb84b-288a-328c-06a5-a6e117ded537.png)


FCSはFrame Check Sequenceの略で、エラーを検出するためのエリアです。

## HTTPの基礎知識

上記に書いたように、HTTPは、TCP/IP通信のアプリケーション層にあるプロトコルの１つです。**Webページを呼び出すためのプロトコル**と言い換えてもいいと思います。

例えば、エイチームライフスタイルのコーポレートサイト（ https://life.a-tm.co.jp/ ）というURLは、HTTP（HTTPS）を用いて通信するよ、と宣言している事になります。

HTTPが誕生したのは今から28年前の1990年です。当時、ティム・バーナーズ・リーという人がクリスマス休暇で`CERN HTTPd`という名前のWebサーバを開発したそうです。最初のバージョン（HTTP/0.9）はHTMLのドキュメントを要求して取得するだけのプロトコルでした。

その後、HTTPリクエストにヘッダの情報を追加したり、GETメソッド以外のリクエストを追加したりして現在のWebの基本形であるHTTP/1.1と呼ばれるバージョンが誕生しました。ちなみに最新はHTTP/2.0ですが、基本的な要素は1.1と大きな変化はありません。

### HTTPリクエストとHTTPレスポンス

WebブラウザがWebサーバに対して出すリクエストをHTTPリクエストと言います。また、WebサーバがWebブラウザのリクエストに対して返すレスポンスをHTTPレスポンスと呼びます。そして、その両者をHTTPメッセージと呼びます。

どういうメッセージがやりとりされているかを確認するために、ChromeのDevToolでヘッダー情報を確認してみましょう。

エイチームライフスタイルのコーポレートサイト（ https://life.a-tm.co.jp/ ）を見てみます。

<img width="1436" alt="スクリーンショット 2018-11-30 22.04.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/14191/51f3c3bc-40de-870b-643b-2777c920609f.png">

**手順**

- ChromeのDevToolを開く
- 1. Networkパネルをクリック
- リロードすると各リソース一覧のネットワーク処理が行われます
- 2. Allボタンをクリックすると計測された全てのリソースのネットワーク処理が見れます
- 3. Nameエリアに、各リソース一覧があります
- 4. HeadersをクリックするとHTTPメッセージが表示されます

少し脱線しますが、パフォーマンス改善の際のネットワーク処理の最適化として、データの転送量や転送回数を少なくすることが挙げられます。

例で示したエイチームライフスタイルのコーポレートサイトの計測結果を再度見て見ましょう。

<img width="1097" alt="スクリーンショット 2018-12-01 10.48.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/14191/7877ee5f-5ccd-a82e-99b8-c35604e0261a.png">

- 155 requests　（リクエスト数）
- 211 KB transferred（転送量）
- Finish 4.5s（ページが表示されるまでの時間）
- DOMContentLoaded 1.20s（HTMLの読み込みと解析が終わるまでの時間）
- Loadが2.83s（ページの読み込みが終わるまでの時間）

という結果が出ています。[^1]
このリクエスト数や転送量を少なくすることでパフォーマンス改善が期待できます。

ChromeのDevToolのHTTPメッセージは、読みやすく成形されていますが、[MDNのHTTP メッセージ](https://developer.mozilla.org/ja/docs/Web/HTTP/Messages)を見ると、実際のHTTPメッセージの形式は

```
メソッド URL HTTPのバージョン
ヘッダ部（付加情報）
（空行）
ボディ部
```

だとわかります。例えば、HTTPリクエストのメソッドが`GET`である場合、ページの読み込みだけなので、HTTPレスポンスのメッセージのボディ部はHTMLになります。[^2]

メソッドは `GET`だけでなく、`POST`、`PUT`、`DELETE`などがあります。

### HTTPリクエストの4つのメソッド

さきほど、`GET`とか、`POST`とか書きましたが、これは、HTTPリクエストのメソッドです。 Web上のコンテンツは、基本的には４つの操作が可能で、それが`CRUD`呼ばれる操作です。また、HTTPリクエストメッセージ内のメソッドは `CRUD`と言い換えることもできます。

| 英語 | 日本語 | HTTPメソッド |
|------------|-------------|--------------|
| Create       |   作成        | POST|
| Read     | 取得      | GET|
| Update       | 更新        | PUT|
| Delete         | 削除          | DELETE|

ここを理解できていると、Railsでは、ルーティングの設定や、コントローラーのアクションに関するこコードの理解が進むと思います。

### HTTP通信をやってみる

HTTPのヘッダ情報の理解をさらに深めるために、HTTP通信を実装してみましょう。

そのために、curlコマンドを用いてHTTPリクエストをサーバに送って、サーバからのHTTPレスポンスを確認してみます。レスポンスは、受け取った文字列（リクエスト）をそのままクライアントへ返すエコーサーバをGo言語で作ってみました。

Goのバージョンは以下の通りです。

```bash
$ go version go1.11.2 darwin/amd64
```

#### 実装してみました

受け取った文字列（リクエスト）をそのままクライアントへ返すエコーサーバをGo言語で記述しました。[^3]

```go:server.go
package main

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
)

func handler(w http.ResponseWriter, r *http.Request) {
	dump, err := httputil.DumpRequest(r, true)
	if err != nil {
		http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
		return
	}
	fmt.Println(string(dump))
	fmt.Fprintf(w, "<html><body>Hello HTTP</body></html>\n")
}

func main() {
	var httpServer http.Server
	http.HandleFunc("/", handler)
	log.Println("start http listening :18888")
	httpServer.Addr = ":18888"
	log.Println(httpServer.ListenAndServe())
}
```

#### 実行してみましょう

実行時に、待ち受けポート番号が出力されたら準備完了です。

```bash
$ go run server.go
2018/11/23 15:40:03 start http listening :18888
```

HTTPサーバは起動したままにして、今度は別のターミナルで、リクエストを送ってみましょう。

```bash
$ curl -v http://localhost:18888/
```

curlコマンドでリクエストした時にヘッダ情報も見たいので、オプション`-v`で指定します。

```bash
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 18888 (#0)
> GET / HTTP/1.1
> Host: localhost:18888
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sat, 01 Dec 2018 10:24:34 GMT
< Content-Length: 37
< Content-Type: text/html; charset=utf-8
<
<html><body>Hello HTTP</body></html>
* Connection #0 to host localhost left intact
```

これを見ると、実際のHTTPメッセージの形式が、[MDNのHTTP メッセージ](https://developer.mozilla.org/ja/docs/Web/HTTP/Messages)と同じであるとわかります。

```
メソッド URL HTTPのバージョン
ヘッダ部（付加情報）
（空行）
ボディ部
```

だとわかります。

#### HTTPリクエストの内容

`>`で始まる行が、クライアントからのリクエスト内容です。上から

- HTTPメソッドの指定 / HTTPのバージョン
- ヘッダ情報（Host / User-Agent / Accept）

#### HTTPレスポンスの内容

`<`で始まる行が、サーバからのレスポンス内容です。上から

- HTTPのバージョン / ステータスコード
- レスポンスを返した日時
- ボディのデータ容量（Content-Length）
- ファイルの種類（Content-Type）や文字コードの情報
- ボディの情報（今回の例ではHTML）

この情報は、HTTPの最新バージョンになっても残っています。

# まとめ

ネットワーク, TCP/IP, HTTPの基礎を理解することで、例えばRailsではルーティングの設定やコントローラーのアクションの設定に関するコードの理解が進むと思いました。

また、Webのパフォーマンス改善において、例えばパフォーマンスが悪い場合、ネットワーク処理を通った各リソースのどのファイルが原因なのかが分かるようになったかと思います。そして、データの転送量や転送回数を指標にして、どんな部分を改善すればパフォーマンスに寄与するか当てをつけられるようになったと思います。[^4]

上記ができるようになるためにも、**ネットワーク, TCP/IP, HTTPの基礎の理解は大切だと思いました。** なので、本記事がこれからネットワークなどを学ぶ方や、パフォーマンス改善に取り組むけどネットワークの知識はあまりない方の学びの一助になれば幸いです。

最後まで読んでいただきありがとうございました。

# 参考文献

- 佐藤歩, 泉水翔吾（2017）『超速! Webページ速度改善ガイド』技術評論社．
- 山本陽平（2010）『Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)』技術評論社．
- [ASCII.jp - TCP/IPの基礎の基礎を理解していますか？](http://ascii.jp/elem/000/000/424/424788/index-2.html)
- [EagleLand - Webにおけるネットワーク通信](https://1000ch.net/posts/2014/networking-in-web.html)
- [ハイパテキスト転送プロトコル HTTP/1.1](http://www.y-adagio.com/public/standards/tr_http11_2068/http.htm)
- [cloudflare - HTTP/2 For Web Developers](https://blog.cloudflare.com/http-2-for-web-developers/)
- [The Go Programming Language Specification](https://golang.org/ref/spec)

---

[Ateam Lifestyle x cyma Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ateam-lifestyle-cyma)、明日の11日目は、@okonomiさんに書いてもらう予定です。お楽しみに！

---

エイチームグループでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。
https://www.a-tm.co.jp/recruit/

[^1]: この計測時点での結果です
[^2]: ファイルの種類（Content-Type）がHTMLの場合
[^3]: 渋川よしき（2017）『Real World HTTP ―歴史とコードに学ぶインターネットとウェブ技術』オライリージャパン．を参考にしています。
[^4]: 遅延の原因のとして、サーバのレスポンス速度やデータの転送距離など、他にも様々あります