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

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 //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

Tags: