【Flask官方文檔經典示例】 hello.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
輸入以下命令啟動應用程序:
$ python hello.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
打開你的瀏覽器并在地址欄輸入http://127.0.0.1:5000/ ?!緢D1-1】顯示連接到應用程序后的瀏覽器。

圖1-1 hello.py Flask應用程序
服務是怎么啟動的
從app.run()開始,這行代碼表示啟動一個服務。我們看到app是Flask一個對象,而run()是該對象的一個方法。我們先簡單的認為定義了一個類,然后實例化這個類并調用該類的一個方法,如下:
【示例1-1】example-1-1.py
class Flask(object):
def run(self):
pass
app = Flask()
app.run()
如果我們運行【示例1-1】這段代碼,會發(fā)現什么都沒有發(fā)生。然而,【Flask官方文檔經典示例】不是這樣的,當你運行后它是下面這樣的:
$ python hello.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
很自然的可以想到,【Flask官方文檔經典示例】中的app.run()不簡單,我們可以看看run()方法定義,如下:
def run(self, host=None, port=None, debug=None, **options):
from werkzeug.serving import run_simple
...
try:
run_simple(host, port, self, **options)
finally:
self._got_first_request = False
在這個方法中,我們先忽略一些配置操作,重點關注run_simple()函數,發(fā)現該函數是從werkzeug.serving模塊中導入的。
到了這里我們就不得不提一下Werkzeug了,官方文檔定義:Werkzeug是為Python設計的HTTP和WSGI實用程序庫。至于它有什么作用,我們在這里暫且不討論,先跟到代碼里面看看它都做了什么。
我們看到這個run_simple()函數里面還嵌套了一個inner()函數,里面有幾行關鍵代碼,如下:
srv = make_server(hostname, port, application, threaded,
processes, request_handler,
passthrough_errors, ssl_context,
fd=fd)
...
srv.serve_forever()
從上面的代碼,我們看到在inner()函數里面調用了make_server()函數來創(chuàng)建一個類實例,該實例會調用serve_forever()方法讓服務一直運行,等待客戶端的請求。到這里我們大概找到了服務啟動的入口了,想知道具體是怎么啟動,我們還需要深入挖掘一下。
因為調用run_simple()函數時參數threaded和processes給的都是默認值,分別為False和1,所以在這里make_server()函數其實是創(chuàng)建了一個BaseWSGIServer類實例,并調用該實例的serve_forever()方法,具體make_server()函數如下:
def make_server(host=None, port=None, app=None, threaded=False, processes=1,
request_handler=None, passthrough_errors=False,
ssl_context=None, fd=None):
if threaded and processes > 1:
raise ValueError("cannot have a multithreaded and "
"multi process server.")
elif threaded:
return ThreadedWSGIServer(host, port, app, request_handler,
passthrough_errors, ssl_context, fd=fd)
elif processes > 1:
return ForkingWSGIServer(host, port, app, processes, request_handler,
passthrough_errors, ssl_context, fd=fd)
else:
return BaseWSGIServer(host, port, app, request_handler,
passthrough_errors, ssl_context, fd=fd)
找到BaseWSGIServer類,如下代碼:
class BaseWSGIServer(HTTPServer, object):
...
def serve_forever(self):
self.shutdown_signal = False
try:
HTTPServer.serve_forever(self)
except KeyboardInterrupt:
pass
finally:
self.server_close()
...
【注意】接下來的代碼嵌套調用比較多,所以最好是能對照著源碼來看。
srv.serve_forever()其實是BaseWSGIServer類中的serve_forever()方法,然后我們發(fā)現BaseWSGIServer類繼承了HTTPServer類,且BaseWSGIServer的serve_forever()方法中調用了HTTPServer的serve_forever()方法。找到HTTPServer類,如下代碼:
class HTTPServer(SocketServer.TCPServer):
allow_reuse_address = 1
def server_bind(self):
SocketServer.TCPServer.server_bind(self)
host, port = self.socket.getsockname()[:2]
self.server_name = socket.getfqdn(host)
self.server_port = port
HTTPServer類中并沒有serve_forever()方法,且這個類繼承了SocketServer.TCPServer,我們再找到TCPServer類,然而它也沒有serve_forever()方法,且這個類繼承了BaseServer類,所以再去BaseServer里面看看,如下代碼:
def serve_forever(self, poll_interval=0.5):
self.__is_shut_down.clear()
try:
while not self.__shutdown_request:
r, w, e = _eintr_retry(select.select, [self], [], [], poll_interval)
if self in r:
self._handle_request_noblock()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
所以前面看到的srv.serve_forever()其實是調用了BaseServer里面的serve_forever()方法,它接受一個參數poll_interval,用于表示select輪詢的時間。然后進入一個無限循環(huán),調用select方式進行網絡IO監(jiān)聽。也就是說app.run()啟動的是一個BaseWSGIServer,該服務通過一層一層的繼承創(chuàng)建socket來進行網絡監(jiān)聽,等待客戶端連接。
至此,Flask服務是怎么啟動的應該有個基本的了解了。
整理一下相關server類的繼承關系,如下:
BaseWSGIServer-->HTTPServer-->SocketServer.TCPServer-->BaseServer
從上面的類繼承關系,我們可以很容易的理解,因為Flask是一個Web框架,所以需要一個HTTP服務,而HTTP服務是基于TCP服務的,而TCP服務最終會有一個基礎服務來處理socket。這一條線都能夠解釋的通。但是,那個BaseWSGIServer是個什么鬼?為什么會需要一層這個服務?這也是我想要去研究的,所以我會在下一篇里面進行講解。