私は受け入れられた答えに同意します
Flask が使用するサーバー ソケットは、標準ライブラリの内部に隠されているため、簡単には取得できません (Flask は、開発サーバーが stdlib の BaseHTTPServer に基づいている Werkzeug を使用します)。
ただし、Werkzeug が、実行時にソケットとして使用するファイル記述子を渡すオプションを公開していることを発見しましたwerkzeug.serving.BaseWSGIServer
(これは、フラスコのrun()
関数が最終的に行うことです)。この機能を使用すると、使用可能なポートをランダムに選択し、それを使用するように Werkzeug に指示できます。
これが私のアプリケーションの起動です:
import logging
import pprint
import sys
from flask import Flask
applog = logging.getLogger(__name__)
applog.setLevel(logging.INFO)
app = Flask(__name__)
if __name__ == '__main__':
app.config.from_object('myapp.default_settings')
try:
app.config.from_envvar('MYAPP_SETTINGS')
except RuntimeError:
applog.warning("MYAPP_SETTINGS environment variable not set or invalid. Using default settings.")
# SERVER_NAME should be in the form of localhost:5000, 127.0.0.1:0, etc...
# So, split on : and take the second element as the port
# If the port is 0, we need to pick a random port and then tell the server to use that socket
if app.config['SERVER_NAME'] and int(app.config['SERVER_NAME'].split(':')[1]) == 0:
import socket, os
# Chose a random available port by binding to port 0
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((app.config['SERVER_NAME'].split(':')[0], 0))
sock.listen()
# Tells the underlying WERKZEUG server to use the socket we just created
os.environ['WERKZEUG_SERVER_FD'] = str(sock.fileno())
# Update the configuration so it matches with the port we just chose
# (sock.getsockname will return the actual port being used, not 0)
app.config['SERVER_NAME'] = '%s:%d' % (sock.getsockname())
# Optionally write the current port to a file on the filesystem
if app.config['CREATE_PORT_FILE']:
with open(app.config['PORT_FILE'], 'w') as port_file:
port_file.write(app.config['SERVER_NAME'].split(':')[1])
applog.info("Running app on %s" % (app.config['SERVER_NAME']))
applog.info("Active Settings:%s" % pprint.pformat(app.config, compact=True))
app.run()
の内容myapp.default_settings
:
SERVER_NAME = '127.0.0.1:0'
PORT_FILE = 'current_port'
CREATE_PORT_FILE = True
ここで重要なのは設定os.environ['WERKZEUG_SERVER_FD']
です。Werkzeug は、関数中にこの環境変数を調べ、定義されている場合は、それをパラメータとして関数run_simple
に渡します。これは最終的に通信用のソケットとして使用されます。fd
make_server
このアプローチの安定性を保証することはできませんが (環境変数がどれだけ適切にサポートされているかはわかりませんWERKZEUG_SERVER_FD
)、これまでに提案されたソリューションよりも好ましいと思います。理由は次のとおりです。
- 例外をキャッチする一連のポートをループする必要はありません。OS から最初に使用可能なポートを取得するだけです。
- ランダム ポートをバインドしてからアプリケーションを実行するまでの間に、選択したランダム ポートが使用される可能性はありません。
上記のコードは、使用されているポートもログに記録し、オプションで現在使用されているポートを構成オプションで指定されたファイルに書き込みます。