25

Flaskを使用して、フラスコが接続されている現在のポート番号を取得するにはどうすればよいですか? ポート 0 を使用してランダムなポートでサーバーを起動したいのですが、どのポートを使用しているかを知る必要もあります。

編集

質問に対する回答ではありませんが、問題の回避策を見つけたと思います。49152 から始まるポートを反復処理し、そのポートをapp.run(port=PORT). Address already in useエラーが発生した場合に次のポートを試すことができるように、try catch ブロックでこれを行うことができます。

4

5 に答える 5

45

Flaskが使用するサーバーソケットは、標準ライブラリの内部に隠されているため、簡単に入手することはできません(FlaskはWerkzeugを使用しており、その開発サーバーはstdlibに基づいていますBaseHTTPServer)。

ただし、エフェメラルポートを自分で作成し、それを作成するソケットを閉じてから、そのポートを自分で使用することができます。例えば:

# hello.py
from flask import Flask, request
import socket

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello, world! running on %s' % request.host

if __name__ == '__main__':
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost', 0))
    port = sock.getsockname()[1]
    sock.close()
    app.run(port=port)

使用するポート番号が表示されます。実行例:

$ python hello.py 
* Running on http://127.0.0.1:34447/

そして、http:// localhost:34447 /を参照すると、

こんにちは世界!localhost:34447で実行中

私のブラウザで。

もちろん、ソケットを閉じてからFlaskがそのポートでソケットを開く間に他の何かがそのポートを使用すると、「使用中のアドレス」エラーが発生しますが、環境でこの手法を使用できる場合があります。

于 2011-02-23T10:59:30.757 に答える
3

私は受け入れられた答えに同意します

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に渡します。これは最終的に通信用のソケットとして使用されます。fdmake_server

このアプローチの安定性を保証することはできませんが (環境変数がどれだけ適切にサポートされているかはわかりませんWERKZEUG_SERVER_FD)、これまでに提案されたソリューションよりも好ましいと思います。理由は次のとおりです。

  1. 例外をキャッチする一連のポートをループする必要はありません。OS から最初に使用可能なポートを取得するだけです。
  2. ランダム ポートをバインドしてからアプリケーションを実行するまでの間に、選択したランダム ポートが使用される可能性はありません。

上記のコードは、使用されているポートもログに記録し、オプションで現在使用されているポートを構成オプションで指定されたファイルに書き込みます。

于 2018-08-24T21:53:47.240 に答える
0

ポート0へのバインドは正しいです。これにより、オペレーティングシステムは1024〜65535の使用可能なポートを選択します。

バインド後に選択したポートを取得するには、を使用しますyour_socket.getsockname()[1]

したがって、調べる必要があるのは、Flaskが使用するリスニングソケットにアクセスする方法だけです。

socket.getsockname()ドキュメント:http ://docs.python.org/library/socket.html#socket.socket.getsockname

于 2011-02-23T08:08:30.117 に答える
0

最近のほとんどのオペレーティング システムnetstatには、現在使用されているすべてのポートのリストと、適切に尋ねると、それらのポートで実行されているアプリケーションを表示するというコマンドがあります。:)

os.popenまたはsubprocessモジュールで解析するのはかなり簡単なはずです。

それとは別に、各サーバーを起動するときに使用しているポートを追跡することができます...

また、たまたま http リクエスト内からこれを行っている場合は、wsgi 環境から SERVER_PORT cgi 変数を調べることができます。

于 2011-02-23T03:21:03.340 に答える