2011-02-23 39 views
13

使用Flask,如何獲得燒瓶連接的當前端口號?我想使用端口0在隨機端口上啓動服務器,但我也需要知道我在哪個端口上。如何獲取Flask中的當前端口號?

編輯

我想我已經找到一個變通爲我的問題,但它不是一個問題的答案。我可以遍歷從49152開始的端口,並嘗試通過app.run(port=PORT)使用該端口。我可以在try catch塊中這樣做,這樣如果我得到一個Address already in use錯誤,我可以嘗試下一個端口。

+0

而raúnning樣本瓶節目我收到此錯誤:.....文件「/usr/lib/python2.7/socket.py」,線路228,在甲基 返回getattr(self._sock,name)(* args) socket.error:[Errno 13]權限被拒絕 請幫助我如何更改端口 – 2016-12-07 10:48:15

回答

29

你不能很容易地得到在由瓶使用的服務器套接字,因爲它隱藏在標準庫的內部(瓶使用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/,我看到

Hello, world! running on localhost:34447

在我的瀏覽器。

當然,如果其他東西在你關閉套接字之間使用了那個端口,然後Flask用這個端口打開套接字,你會得到一個「Address in use」錯誤,但是你也許能夠使用這種技術你的環境。

0

目前大多數操作系統都有一個叫做netstat的命令,它會給你一個當前正在使用的所有端口的列表,以及如果你問得很好的話,它們上面正在運行哪些應用程序。 :)

它應該很容易與os.popensubprocess模塊解析。

除此之外,你可以只跟蹤您正在使用的端口,當你開始每個服務器...

另外,如果你碰巧從HTTP請求中這樣做,你可以看看SERVER_PORT cgi變量來自wsgi環境。

+2

我覺得必須有比這更好的方法。 – david4dev 2011-02-23 07:46:18

1

綁定到端口0是正確的。這將使操作系統爲您選擇1024到65535之間的可用端口。

要在綁定後檢索選定的端口,請使用your_socket.getsockname()[1]

因此,您需要了解的是如何訪問Flask使用的偵聽套接字。

socket.getsockname()文檔:http://docs.python.org/library/socket.html#socket.socket.getsockname

+1

不是那麼簡單.... Flask不存儲'HTTPServer'實例,但只是創建它,然後調用'serve_forever()' – 2014-12-20 21:28:28

1

正如@VinaySajip所指出的一樣,Flask使用標準服務器套接字,但它從不將該實例分配給任何變量,只是構造它並調用serve_forever()

不管怎麼說,我們可以攔截bind_socket()調用並讀取地址,而無需考慮併發套接字的創建,而是嘗試從flask應用中提取套接字作爲@ThiefMaster。這裏是我的解決方案:

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) 
+0

這是一個好方法,但它有一個垮臺。當使用更多使用TCPServer的代碼時,您的電話也將被調用,並且您將接到多個電話給您的功能 – Fruch 2017-01-06 05:41:21

+0

@Fruch您是對的,這只是一個概念證明。也許最好在'with'上下文管理器中使用'mock.patch'來以安全和乾淨的方式進行操作。 – 2017-01-06 17:41:05

相關問題