住所を書いただけでは、荷物は届かない
안녕하신게라!パナソニック コネクト株式会社クラウドソリューション部の加賀です。
前回「DNSとIPアドレスの基本の"キ"」では、広大なインターネットの海からたった1台のサーバを見つけ出す「海図」の仕組みを解説しました。相手の住所(IPアドレス)が分かり、いよいよデータを送り届けるゾという段階です。
当然ですが、データに宛先を書いただけでは荷物は届きません。誰にどう依頼するのかというプロトコル(手続き)に沿って、荷物を発送する必要があります。
今回はその配送を担うトランスポート層に話を絞り、TCP/UDPとポート番号を中心に、ネットワーク伝達の基本の"キ"を解説します。まず荷物の「宛名」にあたるポート番号を押さえ、そのうえで「配送方法」にあたるTCP/UDPへ進みます。
ネットワークの「宛名」がポート番号
IPアドレスが「建物の住所」だとすれば、ポート番号は荷物に書かれた「宛名」、つまりビルの中のどの窓口宛てか、にあたります。
大きなオフィスビルを思い浮かべてください。住所だけを頼りに荷物を運んでも、たどり着くのはビルの受付(サーバ)までです。そのビルには、Webサーバ(NginxやApache)、メールサーバ、データベース(MySQLやPostgreSQL)など、複数の部署(プログラム)が同居しています。「Web窓口(80番)宛て」「データベース窓口(3306番)宛て」と宛名が書かれていなければ、受付はどの部署に回せばいいのか分かりません。この宛名にあたるのがポート番号です。
ポート番号は16ビットなので、0番から65535番まで存在します。このうち用途がおおむね決まっているものを一覧にしておきます。
| 区分 | 範囲 | 用途 |
|---|---|---|
| ウェルノウンポート | 0〜1023 | HTTP(80)、HTTPS(443)、SSH(22)、DNS(53)など、世界中で「このサービス用」と約束された番号 |
| 登録済みポート | 1024〜49151 | MySQL(3306)、PostgreSQL(5432)など、IANAに登録され特定の製品・サービスが使う番号 |
| エフェメラルポート | 49152〜65535 | クライアントが通信に出かける際、自分用に一時的に確保する返信窓口1 |
おもしろいのは、同じ「Webを見る」行為でも、送り方が変わればポート番号も分かれる点です。郵便にたとえるなら、平文のHTTP(80番)は誰にでも読めるハガキ、暗号化するHTTPS(443番)は封をした封書。さらにデータベース(MySQLなら3306番)のように決まった相手と決まった作法でやり取りする通信は、名宛人にしか開けない信書のような専用便です。宛先のサーバが同じでも、届ける手段・作法が変われば番号も変わるわけです。
これはHTTPとHTTPSに限った話ではありません。メール送信のSMTPは25番、受信のIMAPは143番、リモート操作のSSHは22番というように、世の中の通信は「この用途にはこのポート」と役割ごとに番号を使い分けて成り立っています。ちなみにこの「どの番号をどのサービスに割り当てるか」を取りまとめているのはIANAという組織で、ウェルノウンポートの一覧は今でも普通に公開されています。HTTPがなぜ80番なのか、SSHがなぜ22番なのか、今もネタ的にあらゆる機器へ移植され続けるあのゲームに由来する番号があったり……みたいな話は、調べ出すと初期インターネットの歴史に頭を突っ込むことになるので、気になる方はぜひ沼にハマってみてください。
ともあれ、サーバはひとつの住所(IP)で荷物を受けつつ、宛名(ポート)の違いで「今届いたのはWebの問い合わせか、メールの配送か、リモート操作か」を判別し、担当の窓口へ振り分けています。ブラウザでサイトを開き、メールを受け取り、サーバにログインできるのは、この用途ごとの使い分けが裏で守られているおかげです。
インフラエンジニアが「セキュリティグループを開ける」「ファイアウォールに穴を開ける」と言うとき、その実態はこの窓口(ポート)への通り道を開通させる作業です。住所(IP)だけでなく宛名(ポート)まで意識して、初めて通信の許可・不許可を正しく設計できます。
なお、このエフェメラルポート(クライアントが一時的に確保する返信窓口)は、ファイアウォールのルール設計で役立ちます。AWSのセキュリティグループのように通信状態を覚える(ステートフルな)仕組みなら、行きの通信さえ許可しておけば戻りの返事は自動で通ります。一方、同じAWSでもネットワークACL(NACL)はステートレスなので、行きを許可しても戻り(エフェメラルポート宛て)を別途許可しないと通信が成立しません。セキュリティグループの感覚でNACLをいじり「ルールは合っているのに通らない」とハマるのは、一度は通る道です。
荷物の運び方を決めるTCPとUDP
届け先の窓口(=プログラム)が分かったとして、ではそこへ荷物(データ)を実際にどうやって運びましょうか。ここで登場するのが、トランスポート層の二大主役であるTCP(Transmission Control Protocol)とUDP(User Datagram Protocol)です。同じポートへ運ぶにしても、この2つは性格が正反対です。
確実に届ける「書留」のTCP
TCPは「確実性」に全振りしたプロトコルです。荷物を出す前に、まず「今から送るけど受け取れる?」「受け取れるよ」「では送るね」という三度のやり取りで接続(コネクション)を確立します。これが俗にいう3ウェイハンドシェイクで、いきなり荷物を投げつけるのではなく、相手の準備が整ったことを確認してから送り始めるわけです。
送り始めてからも芸が細かい。荷物すべてに通し番号を振り、受け取った側は「ここまで届いた」と逐一応答します。番号が抜けていれば「28番が来ていないからもう一度」と再送を依頼し、順序が前後すれば並べ直す。こうしてデータが順番どおり、1バイトも欠けずに届くのを保証します。しかもこの再送や並べ替えはOSが裏で面倒を見てくれるので、アプリ側は「TCPを使う」と決めるだけで恩恵にあずかれます。
終わり方も同じ調子で、「もう送るものはないよ」「了解、こちらも終わる」と切断の合図を交わしてからコネクションを閉じます。始まりも終わりもきちんと区切るわけです。
その代わり、この几帳面さは速度を犠牲にします。挨拶と確認(オーバーヘッド)が積み重なるぶん、UDPに比べれば動きは重い。それでもHTTP/HTTPSやデータベース、ファイル転送など、1文字でも欠けたら困る世界はTCPの独壇場です。書留や宅配便のように、確実に届くことそのものに価値がある荷物を運ぶ手段だと考えれば分かりやすいでしょう。
投げっぱなしの「普通郵便」のUDP
UDPは「速度」に全振りしたプロトコルです。相手への挨拶もなければ、届いたかどうかの確認もありません。とにかくデータを一方的に送り続けます。
余計なやり取りがないぶん、動きは軽く速い。ただし届かなければそれっきりで、順番が前後することもあります。これは欠点に見えて、用途によっては美点です。動画のライブ配信やオンラインゲーム、音声通話などは、数フレームの欠けより「今この瞬間のデータが遅れず届くこと」のほうが大事。再送を待って映像が止まるくらいなら、多少カクついても先へ進んでほしい。そういう世界でUDPの割り切りが活きます。
身近なところでは、前回扱ったDNSの名前解決もUDPを使っています。「このドメインのIPは?」という小さな問い合わせと短い返事で済むなら、わざわざTCPで接続を確立するより、UDPで軽く投げて答えをもらうほうが速い(応答が大きい場合などはTCPに切り替わります)。
確実だが遅い書留のTCPと、速いが取りこぼす普通郵便のUDP。どちらが偉いという話ではなく、運ぶ荷物に合った手段を選べるかどうかです。この対比を頭に入れておけば、なぜこのサービスはこちらを使うのか、という勘所が見えてきます。
ここまでの違いを表にまとめておきます。
| 観点 | TCP(書留) | UDP(普通郵便) |
|---|---|---|
| 接続の確立 | 送る前に3ウェイハンドシェイク | なし(いきなり送る) |
| 順序の保証 | あり(番号順に並べ直す) | なし(前後しうる) |
| 到達の保証 | あり(届かなければ再送) | なし(届かなければそれっきり) |
| 速度・軽さ | オーバーヘッド大で重め | オーバーヘッド小で軽快 |
| 代表的な用途 | Web(HTTP/HTTPS)、DB、ファイル転送 | 動画・音声配信、オンラインゲーム、DNS |
【コラム】TCPでもUDPでもない「ICMP(Ping)」
ネットワークが繋がらないとき、誰もがまず「Ping飛ぶ?」と口にしますよね。このPingで使われているのはTCPでもUDPでもなく、ICMP(Internet Control Message Protocol)という別のプロトコルです。
ICMPはそもそもポート番号の概念を持たず、ネットワークの導通確認やエラー報告(宛先に到達できません、TTLが尽きました等)専用に使われます。だからこそ「セキュリティグループでTCPを全開にしたのにPingが返ってこない」という現象が起こります。TCPを許可してもICMPは別枠なので、Pingを通したければICMPを明示的に許可する必要がある、というのはインフラ初心者が一度は踏む罠です。
いいとこ取りで進化する、TCP/UDPのその先へ
先ほどのコラムでは、TCPでもUDPでもないICMPという第3の住人を紹介しました。とはいえ世の中の通信の大半は、やはりTCPとUDPが土台です。そして現代のアプリケーションでは、この2つをそのまま使うだけでなく、互いの良いところを取り込んだり足りないところを補ったりする技術が活躍しています。少し寄り道してみましょう。
TCPを捨てたHTTP/3とQUIC
Webの通信は長らくTCPの上にHTTPを載せて成り立ってきました。しかしTCPのハンドシェイクとTLSのハンドシェイクが重なると、通信を始めるまでの往復回数が増えてしまいます。この遅さを根本から解決すべく登場したのがHTTP/3です。
HTTP/3は、確実性が売りだったTCPをあえて捨て、UDPの上にQUICというプロトコルを載せます。「取りこぼすUDPの上で大丈夫なのか」と思いますが、QUICは順序制御や再送、暗号化といったTCPとTLSの仕事を自前で実装し直しています。とりわけ大きいのは、TCPとTLSで別々だった2段階のハンドシェイクを1回にまとめ、一度つないだ相手とは次回ほぼ往復なしで再開(0-RTT)できる点です。軽いUDPを土台に選び、足りない確実性は自分で作り込む。基本の組み合わせを一度ばらして組み直した、なかなか思い切ったプロトコルです。
IoTの省エネ通信MQTT
数百万台のセンサから温度や位置のデータを吸い上げるIoTの世界では、事情がまた変わります。1回あたりのデータはごく小さいのに、TCPのヘッダや確認応答がそのつど付いて回り、限られた電池や通信帯域をじわじわ食いつぶしていきます。
そこで重宝されるのがMQTT(Message Queuing Telemetry Transport)です。土台はTCPですが、ヘッダを極限まで切り詰め、必要最小限のやり取りで動くよう設計されています。TCPの確実性は借りつつ、上に乗せる荷造りだけを軽くした、省エネ特化型の通信です。
切らないTCP、WebSocket
通常のWebの通信は、リクエストを送り、レスポンスを受け取り、コネクションを切る一問一答が基本です。ところがチャットや通知のように「サーバから随時データを受け取り続けたい」場合、その都度TCPの挨拶からやり直すのは無駄が多い。
そこで使われるのがWebSocketです。最初に一度だけHTTPの「Upgrade」で挨拶を済ませ、そのTCPコネクションをWebSocketプロトコルへ切り替えて繋ぎっぱなしにし、サーバとクライアントの双方が好きなタイミングで喋れるようにします。一問一答だったTCPの使い方を、開きっぱなしの双方向トンネルへと発想転換したわけです。
おわりに
住所(IP)が分かっても、宛名(ポート)と配送方法(TCP / UDP)を決めてやらなければ、荷物は相手のプログラムまで届きません。確実さを取るか速さを取るか、その一見地味な選択が、Webやデータベースからライブ配信、IoTまで、あらゆる通信の土台を支えています。
時計が合い(NTP)、相手が本物だと確かめられ(TLS)、住所が分かり(DNS)、そして宛先の窓口まで適切な手段で荷物が届く(TCP / UDP)。前回までの「NTPと時刻同期」「SSL/TLSと証明書」「DNSとIPアドレス」と同じく、トランスポート層もまた「動いて当たり前」と思われがちな縁の下のインフラです。普段意識されないからこそ、基本の"キ"を押さえておくと、いざ通信が繋がらないときの切り分けの初動がまるで違ってきます。
さて、こうして宛先の窓口まで届いたパケットを、サーバの中では誰が受け取り、どうやって荷物を処理しているのでしょうか。次回「コンピュート、基本の"キ"(プロセスとメモリ)」へ続きます。
お断り
記事内容は個人の見解であり、所属組織の立場や戦略・意見を代表するものではありません。
あくまでエンジニアとしての経験や考えを発信していますので、ご了承ください。
-
49152〜65535はIANAが定める区分上の範囲で、実際にOSが動的ポートとして使う範囲はこれと異なる場合があります(例:多くのLinuxは32768〜60999、Windowsは概ね49152〜65535)。 ↩