ポートとプロトコル(TCP/UDP)
1台の機器では複数のサービスが同時に動くため、IPアドレスだけでなく「ポート番号」で通信相手のサービスを区別します。Webは80や443、SSHは22といった具合です。通信方式にはTCPとUDPがあり、TCPは到達と順序を保証する確実な方式、UDPは確認をしない代わりに高速・軽量な方式です。どのポートが待ち受けているかは ss コマンドで確認します。
IPアドレスを頼りに目的の機器までたどり着けても、これだけではまだ通信相手を特定しきれない。1台のサーバの上では、Webサーバ・メールサーバ・SSHなど複数のサービスが同時に動いているのが普通だからだ。
住所までは分かっても、その建物のどの部屋を訪ねればいいのかが分からない。この「何号室か」にあたるのがポート番号である。
IPアドレスが建物の住所だとすれば、ポート番号はその建物の何号室か(どのサービスの窓口か)を表す部屋番号だ。住所と部屋番号の両方がそろってはじめて、目的のサービスへ正確に話しかけられる。
ポート番号は0〜65535の範囲の値を取り、これから登場するTCPとUDPというプロトコルが共通して持っている仕組みだ。
🚪 ポート番号を打たなくても通じる理由
ブラウザでサイトを開くとき、私たちは部屋番号など指定した覚えがない。それでも正しい窓口につながるのは、「世界共通の約束」があるからだ。
ポート番号のうち0〜1023の範囲は「ウェルノウンポート」と呼ばれ、主要なサービスにあらかじめ用途が割り当てられている。
代表的なものとして、Webの通信に使うHTTPは80番、その暗号化版であるHTTPSは443番、リモート操作に使うSSHは22番、名前解決のDNSは53番、メール送信のSMTPは25番だ。これらは世界共通の慣習なので、ブラウザはユーザに代わって自動的に相手の443番(または80番)へ接続しに行く。
逆にサーバを公開する側は、提供したいサービスに対応するポートで待ち受けるよう設定する。
一方、サービスを利用する側(クライアント)が使う送信元のポートには、その都度OSが空いている高めの番号(エフェメラルポート)を自動で割り当てる。サーバは要求に応答するとき相手の送信元ポート宛てに返すので、複数の通信が同時に流れても、要求と応答を取り違えずに対応づけられる。
⚖ 確実に届けるか、とにかく速くか
ポート番号と並んで、もう一つ決めるべきことがある。データの運び方だ。ここにTCPとUDP(あわせてTCP/UDPと書かれることもある)という、性格が正反対の2つのプロトコルがある。
TCPは到達と順序を保証する確実な方式だ。通信の前に相手と「これから話します」「いいですよ」と確認し合ってから(コネクションを確立してから)データを送り、受信側が「ここまで受け取った」と応答を返す。このコネクション確立の最初のやり取りは、SYN・SYN+ACK・ACKという3回の手続き(3ウェイ・ハンドシェイク)で行われる。
途中でデータが欠けたり壊れたりすれば再送するので、ファイルの転送やWebページの表示のように、一文字でも欠けては困る用途に向く。
一方UDPは、こうした確認をいっさい行わず、相手が受け取ったかを気にせずデータを送りつける高速・軽量な方式だ。手紙をポストに入れて出すように送りっぱなしにするイメージで、多少の欠落が許される音声・動画のストリーミングや、やり取りが小さくて速さを優先したいDNS・NTPなどで使われる。
正反対のものが2つ用意されているのは、確実さと速さがトレードオフだからだ。TCPは確実さと引き換えに、コネクションの確立や応答確認のぶん通信のやり取りが増え、わずかに遅くなる。UDPは確実さを捨てる代わりに、送りたいタイミングでそのまま送れるため遅延が小さく、リアルタイム性が求められる通信に強みがある。
「確実に届けるTCP、速さ優先のUDP」と覚えておけば、どのサービスがどちらを使うかの見当がつく。たとえばHTTP・HTTPSやSSHはTCP、DNSの問い合わせや時刻同期のNTPは主にUDP、という具合だ。
なお近年は、UDPの上で動きながらTCP並みの信頼性と暗号化を実現するQUICという新しいプロトコルも登場し、HTTP/3として一部のWebサービスで使われ始めている。「速いが不確実」というUDPの弱点を、上の層で補ってしまおうという発想だ。
🔍 どのサービスが待ち受けているかを覗く
理屈は、自分の機器で確かめられる。どのポートが待ち受けているか、どんな接続が成立しているかを調べるには ss コマンドを使う。
よく使うのが ss -tuln で、-t はTCP、-u はUDP、-l は待ち受け(listen)状態のもの、-n は名前解決せず番号のまま表示、という意味の組み合わせだ。
これを実行すると、Local Address:Port の欄に 0.0.0.0:22 や [::]:443 のように、待ち受け中のポートが一覧される。22番が出ていればSSHサーバが、443番が出ていればHTTPSのサーバが起動して待ち受けている、と読み取れる。
いま確立しているTCP接続だけを見たいときは ss -t state established とすると、相手のアドレスとポートの組が並び、ブラウザを開いていれば相手側443番への行が見えるはずだ。何も表示されないときは、通信中のアプリが無いだけのことが多いので、ブラウザでページを開いてから再実行してみるとよい。
⚠ つまずいたら、まずここ
この ss -tuln が活躍するのは、「サービスを立ち上げたのに外からつながらない」という場面だ。まず狙ったポートが待ち受け一覧に出ているかを確認する。出ていなければ、サービス自体が起動していないか、設定したポートが違う可能性がある。
逆に、相手側のポートが開いているか(接続を受け付けるか)を外から確かめたいときは curl -I https://例.example/ とすればよい。TCP接続が成立すればHTTPのステータス行(例: HTTP/2 200)とヘッダだけが返り、接続できなければ Connection refused や timed out が返る。
この2つは似て非なるサインだ。Connection refused は「相手まで届いたがそのポートで待ち受けていない」、timed out は「そもそも相手まで届いていない、あるいは途中でパケットが捨てられている」ことが多い。だから前者ならサービスの起動やポート番号を、後者なら経路やファイアーウォールを疑う。メッセージの違いから、次に調べる場所が変わってくる。
古い環境では netstat -tuln でも近い情報が得られるが、現在は net-tools という古いパッケージから iproute2 の ss への置き換えが進んでいる。ss -tuln を手の内に入れておけば現行の環境でそのまま通用する。UDPの待ち受けを見たいときは ss -u を、待ち受けだけでなく確立中のものも含めて見たいときはオプションを足して使い分ける。