ポートの概念
実際の通信において、ポートという概念が登場します。 ローカルでのサーバー開発において、地味にトラブルの元にもなるため、ポートの概念の理解は重要です。
ポートとは?
イーサネット(Wi-Fi)では、両者(自分と接続先)のことをMACアドレスで比較していました。 IPでは、両者のことをIPアドレスで比較していました。 このつながりで、トランスポート層ではポート番号が登場します。
良くあるたとえでは『道路はIP』『車はポート』というものがあります。 道路の存在により、2点間の通信経路が確立されています。その中を走る車が情報であり、車を見分けるために使っているのがポートという風に考えてみるといいでしょう。
もうすこし具体的なところでは、以下のようになります。
IPではあくまで信号という形でデータが流れています
トランスポートでは、信号の中に『どのアプリケーションが受け取るべきか』という情報が含まれています。
このため、トランスポートのレベルでは、ポート番号を使ってアプリケーションを識別し、適切なアプリケーションにデータを届ける役割を果たしています。
ポート番号の範囲
ポート番号は、0から65535までの範囲で指定されます。ポート番号には以下のような分類があります。
ウェルノウンポート(0-1023): これらのポート番号は、特定のサービスやプロトコルに予約されています。例えば、HTTPはポート80、HTTPSはポート443、FTPはポート21などです。
登録済みポート(1024-49151): これらのポート番号は、特定のアプリケーションやサービスに登録されており、一般的に使用されます。例えば、MySQLはポート3306、PostgreSQLはポート5432などです。
動的ポート(49152-65535): これらのポート番号は、クライアントアプリケーションが一時的に使用するために割り当てられます。通常、クライアントがサーバーに接続する際に、動的に選択されます。別名として『エフェメラルポート』とも呼ばれます[1][2]。
注釈
なお、ウェルノウンポートは、現代では『システムポート』と呼ばれているそうですが、佐藤は未だかつてその呼び方を見たことがありません。
ポートは発信側だって使うことになる
ポートについて「ああ、Webサーバーだと80番だよね」という感じで話を聞くことがありますが、80番ポートを使うということはトランスポートでの通信となるわけで、同レベルでの通信であれば自分の側にもポート番号が必要です。 では、その『自分の使うポート番号』はどうやって決まるのでしょうか。
このことに関しては、雑に2つに分類することができます。
自分で決める
おまかせ(システムに決めてもらう)
自分で決める場合、ポート番号を明示的に「この番号から発信する」と宣言することになります。 ポート番号自体は前述の通り、0〜65535の範囲で指定できますが、『空いていれば使える』ため、他のアプリケーションが使用中のポートは使用できません。 ポート番号は早い者勝ちというルールとなっているのです。 この問題は、サーバーの開発を行うときに地味に効いてくる問題です。
おまかせの場合、システムが自動的に空いているポート番号を選択してくれます。 システム(OS)は通常、自分のシステム内で『現在使用中』のポート情報はビットマップ的に管理しています。 そのため、空いているポート番号を効率的に見つけることができます。 この場合、ポート番号はシステムが自動的に選択するため、開発者は特に意識する必要はありません。
この時に「どのあたりのポート番号を拾いやすいか」については、OSの実装によって少し差が出ているようです。
Windowsの場合、49152〜65535の範囲から選択されることが多い(ポート数は16384)。
Linuxの場合、32768〜60999の範囲から選択されることが多い(ポート数は28232、他より少し多い)
macOSの場合、49152〜65535の範囲から選択されることが多い(ポート数は16384)
注釈
各OSの範囲は以下の方法で確認できます。
Windowsの場合
PS> netsh int ipv4 show dynamicport tcp
プロトコル tcp の動的ポートの範囲
---------------------------------
開始ポート : 49152
ポート数 : 16384
Linuxの場合
$ cat /proc/sys/net/ipv4/ip_local_port_range
32768 60999
macOSの場合
% sysctl net.inet.ip.portrange.first
net.inet.ip.portrange.first: 49152
% sysctl net.inet.ip.portrange.last
net.inet.ip.portrange.last: 65535
こうして確認するとLinuxだけずれている感じになりますが、過去からの経緯というものがあるのでしょう。