コンテンツにスキップ

Pythonで使えるポート番号を探す方法

[質問]

Pythonで、localhost:8000にサーバーを立てるとき、すでにそのポート8000が使われているか調べるにはどうすればいいですか

[回答] Gemini

開発中、ポート8000が塞がっていてサーバーが起動できない場面、よくありますよね。「Address already in use」というエラーは開発者あるあるです。

Pythonの標準ライブラリを使って、そのポートが空いているか(接続可能か)を確認する方法と、すでに使われている場合に「どのプログラムが使っているか」を特定する方法をご紹介します。


1. Pythonでポートの空き状況を確認する

Pythonのsocketライブラリを使って、実際にそのポートに接続を試みるのが一番確実です。

import socket

def is_port_in_use(port):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        # 指定したポートにバインド(占有)できるか試す
        return s.connect_ex(('localhost', port)) == 0

port = 8000
if is_port_in_use(port):
    print(f"ポート {port} は既に使用されています。")
else:
    print(f"ポート {port} は空いています。")
  • connect_ex: 接続に成功すると 0 を返します。つまり、0 が返ってきたら「誰かがそのポートで待ち構えている(=使用中)」ということです。

2. コマンドラインで確認する(推奨)

「何が原因でポートが埋まっているか」を調べるには、OSのコマンドを使うのが最も手っ取り早いです。

macOS / Linux の場合

ターミナルで以下のコマンドを叩きます。

lsof -i :8000
もし使用中であれば、実行しているアプリの PID(プロセスID) が表示されます。それを確認して kill -9 <PID> で終了させることも可能です。

Windows の場合

コマンドプロンプトまたは PowerShell で以下を実行します。

netstat -ano | findstr :8000
一番右側に表示される数字が PID です。


3. 解決策:自動的に空いているポートを探す

もし特定のポートにこだわらないのであれば、Pythonで「空いているポートを自動で割り当てる」テクニックもあります。

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind(('', 0))  # ポート番号に 0 を指定する
    free_port = s.getsockname()[1]
    print(f"空いているポートが見つかりました: {free_port}")
bind0 を渡すと、OSがその時点で空いているポートをランダムに割り振ってくれます。


使用中のプロセスを特定して強制終了させるための具体的なコマンドを知りたい、あるいは特定のWebフレームワーク(DjangoやFlaskなど)での回避策を知りたい場合は、続けて教えてくださいね!

★続き

localhostでの使用を前提として、8000から1ずつポート番号を増やしながらスキャンし、使えるポートを探すのは、問題がありますか

結論から言うと、技術的な仕組みとしては全く問題ありません。むしろ、多くの開発ツールやライブラリ(Jupyter Notebookや各種Webフレームワークのデバッグサーバなど)で採用されている非常に一般的な手法です。

ただし、実装する上で知っておくべき「作法」や「注意点」がいくつかあります。


1. ポートスキャンの仕組み(インクリメント方式)

以下のコードのように、8000番から順に try-exceptsocket でチェックしていく方法は、ローカル開発環境では非常に効率的です。

import socket

def find_free_port(start_port=8000, max_tries=100):
    for port in range(start_port, start_port + max_tries):
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            try:
                # ポートを占有できるか試みる
                s.bind(('localhost', port))
                return port  # 使えるポートが見つかった
            except OSError:
                continue  # 使用中なら次へ
    raise IOError("利用可能なポートが見つかりませんでした")

port = find_free_port()
print(f"使用を開始するポート: {port}")

この方法のメリット

  • ユーザー体験が良い: 8000番がダメなら8001番、という挙動は予測しやすく、ユーザーが手動で設定し直す手間を省けます。
  • シンプル: 特殊な権限も不要で、標準ライブラリだけで完結します。

2. 気をつけるべき「3つのポイント」

① 競合状態(TOCTOU問題)

「空いていることを確認した瞬間」と「実際にサーバーを起動する瞬間」のわずかな隙間に、他のプログラムがそのポートを奪ってしまう可能性(Time-of-check to time-of-use)が理論上あります。 * 対策: 「空きを確認する」だけでなく、そのままそのソケットを保持してサーバーに渡すか、サーバー起動時のエラーハンドリングで再度スキャンを回すのが安全です。

② 無限ループの防止

スキャンする範囲(max_tries)は必ず決めておきましょう。何らかの理由でポートが異常に塞がっている場合、無限に探し続けるとプログラムがフリーズしたように見えてしまいます。

③ セキュリティソフトの反応

稀に、短時間に大量のポートへ接続試行(スキャン)を行うと、PCにインストールされているセキュリティソフトが「不審な挙動」として検知し、警告を出すことがあります。localhost内であれば基本的にはスルーされますが、スキャン範囲が広すぎると注意が必要です。


3. もっとスマートな代替案

もし「特定の番号から始めたい」というこだわりがなく、単に「どこでもいいから空いているポートが欲しい」のであれば、前述の port=0 を指定する方法が最もOSの作法に則っています。

  • ポート8000付近: 開発者が手動でアクセスしやすい。
  • ポート0(OSお任せ): システムが確実に空いている「エフェメラルポート」を割り当てるため、競合がほぼ発生しない。

まとめ

8000番から1ずつ増やして探すのは、ローカル開発ツールの実装として「正解」の一つです。 安心してください。

もしよろしければ、このスキャン機能を使って「空いているポートで自動的にブラウザを開く」ようなスクリプトの書き方も紹介しましょうか?