使用Flask,如何获取烧瓶连接的当前端口号?我想使用端口 0 在随机端口上启动服务器,但我还需要知道我在哪个端口上。
编辑
我想我已经找到了解决我的问题的方法,尽管它不是问题的答案。我可以遍历以 49152 开头的端口并尝试通过app.run(port=PORT)
. 我可以在 try catch 块中执行此操作,这样如果出现Address already in use
错误,我可以尝试下一个端口。
使用Flask,如何获取烧瓶连接的当前端口号?我想使用端口 0 在随机端口上启动服务器,但我还需要知道我在哪个端口上。
编辑
我想我已经找到了解决我的问题的方法,尽管它不是问题的答案。我可以遍历以 49152 开头的端口并尝试通过app.run(port=PORT)
. 我可以在 try catch 块中执行此操作,这样如果出现Address already in use
错误,我可以尝试下一个端口。
您不能轻易获得 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/时,我看到了
你好世界!在本地主机上运行:34447
在我的浏览器中。
当然,如果在您关闭套接字和 Flask 使用该端口打开套接字之间有其他东西使用该端口,您会收到“正在使用的地址”错误,但您可以在您的环境中使用此技术。
正如@VinaySajip Flask 所指出的,它使用标准服务器套接字,但它从不将实例分配给任何变量,只是构造它并直接调用serve_forever()
。
无论如何,如@ThiefMaster 所说,尝试从烧瓶的应用程序中提取套接字,我们可以拦截bind_socket()
调用并读取地址,而无需处理并发套接字创建。这是我的解决方案:
from flask import Flask, request
import socketserver
app = Flask("")
original_socket_bind = SocketServer.TCPServer.server_bind
def socket_bind_wrapper(self):
ret = original_socket_bind(self)
print("Socket running at {}:{}".format(*self.socket.getsockname()))
# Recover original implementation
socketserver.TCPServer.server_bind = original_socket_bind
return ret
@app.route("/")
def hello():
return 'Hello, world! running on {}'.format(request.host)
socketserver.TCPServer.server_bind = socket_bind_wrapper #Hook the wrapper
app.run(port=0, debug=True)
我同意接受的答案
您不能轻易获得 Flask 使用的服务器套接字,因为它隐藏在标准库的内部(Flask 使用 Werkzeug,其开发服务器基于 stdlib 的 BaseHTTPServer)。
但是,我刚刚发现 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
环境变量的支持程度),但到目前为止,我更喜欢它而不是建议的解决方案,因为:
上面的代码还记录正在使用的端口,并可选择将当前正在使用的端口写入配置选项指定的文件。
如今,大多数操作系统都有一个名为的命令,该命令netstat
将为您提供当前正在使用的所有端口的列表,以及如果您问得足够好,哪些应用程序正在其上运行。:)
os.popen
使用orsubprocess
模块应该很容易解析。
除此之外,您可以在启动每个服务器时跟踪您正在使用的端口......
此外,如果您碰巧在 http 请求中执行此操作,您可以查看 wsgi 环境中的 SERVER_PORT cgi 变量。
绑定到端口 0 是正确的。这将使操作系统为您选择 1024 到 65535 之间的可用端口。
要在绑定后检索所选端口,请使用your_socket.getsockname()[1]
.
所以你需要知道的是如何访问 Flask 使用的监听套接字。
socket.getsockname()
文档:http ://docs.python.org/library/socket.html#socket.socket.getsockname