ネットワークとHTTP:パケットになって旅行を去ろう

📖 7min read

localhostの平和、そして壊れた幻想

学生時代の私の世界のすべてはlocalhostでした。 XAMPPのようなものを敷いてPHPで掲示板を組んでも、それはあくまでも私のコンピュータの中だけで回る世界だった。

入社初期には幸運にフロントエンドメンテナンス業務を主に引き受けた。 Quasar(Vue.js)ベースのアドミンページだったが、業務難易度は高くなかった。タイプミスを修正したり、上級者がすでによく作っているAPIをaxios.get()で呼び出して画面に振り分けるだけでよい。

それから私にaxiosは魔法の杖のようでした。複雑な原理は知らなくてもURLだけ入れればデータをたっぷり持って来てくれたから。 「フロントエンドとバックエンドで通信することはあまりありませんか?」という生意気な考えもしました。

しかし、その平和は長続きしませんでした。私は人材不足の中小企業の「生計型フルスタック」開発者だったからです。

しばらく行って画面修正ではなく、新機能のためのAPIを直接作成しなければならない瞬間が来た。 YouTubeで急いで学んだSpring Bootでサーバーを浮かべ、好奇心が強くフロントエンドでリクエストを送った。しかし、私の画面に表示されたのはデータではなく、赤いCORSエラーとTimeoutエラーだけでした。

「明らかにローカル変数に渡すとうまくいきましたが、なぜネットワークに乗ってはいけませんか?」

マイコンピュータ(Localhost)内で変数Aを変数Bに移動するのは、100%保証された安全な長さでした。だが、ランソン外の世界は違った。そこは信号機が故障した交差点と同じで、私のデータはその危険な道路を走るトラックでした。私はこれまでトラックに荷物を乗せて送るだけだったし、そのトラックがどのような経路で、どのように割れていくのか全く知らなかったのだ。

私のコンピュータを離れた瞬間、データは荒い野生の道路を走らなければなりません。

デジタル物流センターの配送システム

私たちの「デジタル物流センター」の世界観を拡大してみましょう。今、私たちの工場(コンピュータ)で作ったもの(データ)を遠く離れた顧客(サーバー)に出荷する必要があります。

1.パケット:標準配送ボックス

私たちが送ろうとするデータがいくら大きくても(例えば1GB動画)、一度に送ることはできない。道路は狭く、トラックは小さいからだ。だから私たちはデータを非常に小さな部分に切り取り、標準化されたボックスに入れます。これが「Packet」です。

2. IP(Internet Protocol):アドレスとナビゲーション

ボックスがあれば何をしますか?どこに行くかを知る必要があります。

3. TCP/UDP: 配送方法の違い

今すぐボックスをどのトラックに乗せるかを決める必要があります。

確実に与えるか(TCP)、早く投げるか(UDP)。

[Code Verification] HTTPの敏感さはただのテキストです

私たちがよく使うHTTPは実際にTCPという宅配トラックの上に載せた「手紙内容」にすぎない。ブラウザやライブラリなしで、最も原始的な方法(Socket)でネイバーサーバーに話しかけましょう。 HTTPがどれほど単純なテキストのかを知るでしょう。

import socket

# 1. TCPソケット生成(受話器を取る)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2. Naverサーバー(223.130.195.200)の80番ポートに接続(電話をかける)
# 実際のNaver IPは変わる可能性あり(nslookup [www.naver.com](https://www.naver.com) で確認可能)
target_host = "[www.naver.com](https://www.naver.com)"
target_port = 80
sock.connect((target_host, target_port))

# 3. HTTPリクエストメッセージ作成(話す内容を書く)
# 最も生のHTTPリクエスト形式
request = "GET / HTTP/1.1rnHost: [www.naver.com](https://www.naver.com)rnrn"

# 4. 送信(話す)
sock.send(request.encode())

# 5. レスポンス受信(聞く)
response = sock.recv(4096)
print(response.decode())

# 6. 接続終了(切る)
sock.close()

実行結果(一部):

HTTP/1.1 200 OK
Server: NWS
Date: Mon, 01 Jan 2024 00:00:00 GMT
Content-Type: text/html; charset=UTF-8
...
<html>...</html>

分析:私たちがaxios.get()を呼び出すときに内部的に起こるのはこれです。

HTTPは特別な技術ではありません。

実務におけるTrade-off:信頼性かスピードか

実務、特にバックエンド開発をしてみると、TCPとUDPの間で悩む時が来る。 (もちろん、ほとんどはTCPベースのHTTPを使いますが)

最近のインタビューの質問でもよく出てくるHTTP / 3が、このTrade-offの産物です。私たちが書いているインターネット(HTTP / 1.1、HTTP / 2)はこれまで TCP 上で戻ってきました。データが絶対に壊れてはいけません。

しかし時代は変わった。人々は4K動画を絶えず見たいと思う。 TCPのその入念な確認手続き(Handshake)と「順番に並んでください(Head of Line Blocking)」という特徴が今は苦しくなったのです。

だからGoogle(Google)は考えた。 「ああ、ただ UDP 書いてみましょう。不安なのは、私たちがアプリケーションレベルで一気に打たれたらいいのです。早く過ごすことが重要です!」

これはQUICプロトコルであり、HTTP / 3の基盤です。無条件の安定性(TCP)を捨てて、わずかなリスクを負っても圧倒的な速度(UDP)を選んだ現代技術の流れだ。

より速いスピードのために、私たちは最も下の交通機関(TCP -> UDP)まで変えています。

終了:見えない道路を想像する

今、私たちはデータがどのように分割され(パケット)、どのトラック(TCP / UDP)に乗って旅行するかを知りました。

フロントエンドでAPIリクエストが失敗したとき、以前のように単に「サーバーが死んだのか」とだけ考えてはいけません。 「ああ、3ウェイハンドシェイクが失敗しましたか?途中でルーターからパケットがドロップされましたか?それともDNSがアドレスを見つけられませんでしたか?」このようにネットワーク層を想像できれば、あなたはすでに「ただのコーダー」ではありません。

さて、今私たちの工場のものが顧客(クライアント)に無事に到着しました。しかし、顧客はこの商品を受け取り、どのように梱包を開けて画面に見せますか?私たちが送ったHTMLコードはブラウザでどのように絵になりますか?

次回は、Web開発の目的地、ブラウザレンダリングの原理(Browser Rendering)について話しましょう

コメントする