【Django】runserver 0.0.0.0:0 後,究竟發生了什麼

luozx207發表於2020-04-30

WSGI協議

Django是遵循WSGI協議設計的

WSGI協議主要包括server和application兩個部分:

  1. WSGI server:負責從客戶端接收請求,將request轉發給application,將application返回的response返回給客戶端
  2. WSGI application:接收由server轉發的request,處理請求,並將處理結果返回給server。application中可以包含多個棧式的中介軟體,這些中介軟體需要同時實現server與application:對server來說,中介軟體扮演應用程式;對應用程式來說,中介軟體扮演伺服器

可以選擇任意的server和application組合實現自己的web應用。

runserver後到底發生了什麼

通過runserver執行的Django主程式會建立一個WSGIServer的例項,WSGIServer父類是操作socket的TCPServer。

WSGIServer將開啟一個socket,並將此socket繫結到runserver引數中指定的ip和埠,然後呼叫socket.listen()開始監聽請求。

當請求來臨,WSGIServer會呼叫WSGIHandler這個application,在application中執行Django框架對請求資料的一系列處理。

runserver 0.0.0.0:8000

runserver 0.0.0.0:8000表示將django程式使用的socket繫結ip設定為INADDR_ANY(0),因此socket會在8000埠監聽從本機所有網路卡發來的資料,相當於繫結了本機的所有ip地址。

比如你的機器有三個ip

  192.168.1.1   
  202.202.202.202   
  61.1.2.3   

使用runserver 0.0.0.0:8000啟動的django程式可以通過伺服器的所有ip訪問到,而使用runserver 192.168.1.1:8000,只有通過192.168.1.1:8000才能夠訪問

如果本機有唯一的ip地址192.168.1.1,那麼runserver 0.0.0.0:8000 就等同於 runserver 192.168.1.1:8000

runserver 127.0.0.1

表示將socket繫結到本機迴環地址,只能監聽本機對此服務的請求

runserver 0.0.0.0:0

如果不為socket指定繫結任何埠,或者將繫結的埠設定為0時,系統會在本機可選的埠中為socket隨機繫結一個

下面來實驗一下:

$ python manage.py runserver 0.0.0.0:0       
Performing system checks...

System check identified no issues (0 silenced).
April 29, 2020 - 19:53:25
Django version 2.0.13, using settings 'qaboard.settings'
Starting development server at http://0.0.0.0:0/
Quit the server with CONTROL-C.

嘗試找到這個服務繫結的埠:

$ ps -ef|grep 0.0.0.0:0
luozx   896 19075  0 19:53 pts/28   00:00:00 python manage.py runserver 0.0.0.0:0
luozx   901   896  4 19:53 pts/28   00:00:04 /home/luozixi/myserver/venv/bin/python manage.py runserver 0.0.0.0:0
luozx  1070 28816  0 19:54 pts/37   00:00:00 grep 0.0.0.0:0

發現有兩個程式,這是因為runserver預設啟動兩個程式,一個程式是提供服務的django應用,一個程式用於檢測專案程式碼修改,如果有修改則自動重啟主程式

如果在runserver時使用 "--noreload" 引數則不會啟動檢測程式

$ python manage.py runserver 0.0.0.0:0 --noreload
$ ps -ef|grep 0.0.0.0:0 
luozx  1429 19075 38 19:56 pts/28   00:00:01 python manage.py runserver 0.0.0.0:0 --noreload
luozx  1447 28816  0 19:56 pts/37   00:00:00 grep 0.0.0.0:0

檢視程式識別符號為1429的程式使用的socket繫結了哪個埠

$ netstat -nltp|grep 1429
Proto Recv-Q Send-Q Local Address           Foreign Address         State        PID/Program name
tcp        0      0 0.0.0.0:48381           0.0.0.0:*               LISTEN      1429/python    

從伺服器的48381埠就可以訪問我們的django服務了

參考資料

Python Web開發最難懂的WSGI協議,到底包含哪些內容?
python從小白到入門:10分鐘搞懂WSGI協議
About IP 0.0.0.0 in Django
Socket.Bind(EndPoint) 方法
socket INADDR_ANY 監聽0.0.0.0地址 socket只繫結埠讓路由表決定傳到哪個ip

相關文章