摘要:怎么寫出更短的代碼并不是這次要討論的話題,今天我們來研究一下:運行代碼的計算機是如何找到目標服務器的?
相信各位 Python 開發者都用過 Requests 庫,有些朋友還用過 WebSockets 庫,這里回顧一下它們的基本用法,例如使用 Requests 庫向目標網站發出 GET 請求:
import requests
url = "https://www.baidu.com"
resp = requests.get(url)
print(resp.status_code) # output -> 200
這里要注意:不管你是為了Python就業還是興趣愛好,記住:專案開發經驗永遠是核心,如果你沒有2020最新python入門到高級實戰視頻教程,可以去小編的Python交流.裙 :七衣衣九七七巴而五(數字的諧音)轉換下可以找到了,里面很多新python教程專案,還可以跟老司機交流討教!
使用起來非常簡單,我們很輕松地向目標網站發出了請求并列印輸出回應狀態碼,當然,你還可以把它縮短:
import requests
print(requests.get("https://www.baidu.com").status_code) # output -> 200
復制代碼
怎么寫出更短的代碼并不是這次要討論的話題,今天我們來研究一下:運行代碼的計算機是如何找到目標服務器的?
顯然,你的第一映象是 IP 地址和埠號,
沒錯,就是 IP 地址和埠號,
但你明明輸入的是 URL 地址,怎么就 IP + 埠號呢?
URL 決議的原因
一下子你也回答不上來吧?
我們可以將上方代碼的邏輯,即計算機向目標服務器發出請求并拿到回應資訊的程序抽象成下圖:
程式輸入的是 https://www.baidu.com,但最終要決議出具體的 IP 地址和埠號才能訪問,例如 183.232.231.172:443,
網路互動實際上屬于 Socket 編程的范疇,無論是 Requests 還是 WebSockets 庫,最終都會通過 Socket 與目標網站的服務器進行互動,而 Socket 編程中并不能直接使用域名,而是采用 IP + 埠號這種形式進行尋址的,
假設你現在需要撰寫一個網路請求庫,有可能是 HTTP 協議的,也有可能是 WebSocket 協議的,你要解決的第一個問題就是決議 URL,將網址轉換成 IP + 埠號,甚至還需要分割出協議型別、資源路徑以及是否采用更安全的傳輸方式等,
URL 決議格式
以 WebSocket 協議方面的客戶端庫為例,在雙端確認連接之前有一個「握手」的程序,這個程序之前已經需要雙端的 IP 和埠號等資訊了,下面的代碼描述了 WebSocket 發出「握手」請求之前,雙端建立連接時需要用到的基本資訊:
# aiowebsocket
reader, writer = await asyncio.open_connection(host=host, port=port, ssl=ssl)
復制代碼
也就是 host、port 和 ssl,
大部分的 WebSocket 服務給出的都是域名,例如 wss://echo.websocket.org,「握手」時還會用到資源路徑,
接下來,我們來嘗試一下,如何將域名轉換為 IP + 埠號和 is ssl 這樣的格式,
代碼實作 URL 決議
開始之前,我們先規劃一下基本步驟:
然后確定要使用的標準庫:決議 URL 當然要用到 urllib 庫中的 url parse;決議 address 則需要用到 socket 庫;為了方面取資料,可以嘗試使用 collections 庫中的 namedtuple,
首先引入這幾個庫:
# 崔慶才和韋世東邀請你關注公眾號:進擊的Coder
import socket
from collections import namedtuple
from urllib.parse import urlparse
復制代碼
然后定義輸出結構,對應代碼如下:
REMOTE = namedtuple('REMOTE', ['scheme', 'hostname', 'address', 'port', 'resource', 'ssl'])
復制代碼
然后定義一個方法,我們傳入 URL,獲得決議好的 REMOTE 物件,方法定義如下:
def parses(url: str) -> REMOTE:
pass
復制代碼
待會我們在 pass 處撰寫屬于該方法的代碼,
最開始要決議 URL,獲得 scheme 和 hostname,對應代碼如下:
url = urlparse(url)
復制代碼
urlparse 方法會回傳一個 ParseResult 物件,物件大體格式如下:
ParseResult(scheme='wss', netloc='echo.websocket.org', path='', params='', query='', fragment='')
復制代碼
有了 scheme 和 hostname 后,就可以得到 port、is ssl 和 address,對應代碼如下:
# 崔慶才和韋世東邀請你關注公眾號:進擊的Coder
scheme = url.scheme
address = url.hostname
port = url.port or (443 if scheme == 'wss' else 80)
ssl = True if scheme == 'wss' else False
復制代碼
WebSocket 協議中只有兩種協議頭:ws 和 wss,它們對應的埠分別是 80、443,這里借助 scheme 的值進行判斷即可得到答案,同理,也直接得到了 is ssl 答案,
拿到 hostname 后,呼叫 socket 庫的 getbyhostname 方法就能夠得到目標服務器的 IP 地址了,對應代碼如下:
address = socket.gethostbyname(hostname)
復制代碼
至于資源路徑,它早已存在于 ParseResult 物件中,直接取出即可:
resource = url.path
復制代碼
要注意的是,有些 URL 中還會攜帶請求正文(即引數和值),所以這里需要取 query,并將其拼接到 resource 中:
if url.query:
resource += '?' + url.query
復制代碼
至此,我們已經拿到了所需的所有資料,
現在將它們裝在到 REMOTE 結構中,回傳給呼叫方:
return REMOTE(scheme, hostname, address, port, resource, ssl)
復制代碼
此時,呼叫 parses 方法后就會拿到 REMOTE 結構,它的取值方式很舒服,用 . 符號取值即可,例如:
# 夜幕團隊邀請你關注公眾號:NightTeam
res = parses("ws://echo.websocket.org?sign=i9878")
print(res.address, res.port, res.resource)
復制代碼
代碼運行結果如下:
174.129.224.73
80
?sign=i9878
復制代碼
這樣,我們就完成了 URL 決議的代碼撰寫,
小結
注意:不管你是為了Python就業還是興趣愛好,記住:專案開發經驗永遠是核心,如果你沒有2020最新python入門到高級實戰視頻教程,可以去小編的Python交流.裙 :七衣衣九七七巴而五(數字的諧音)轉換下可以找到了,里面很多新python教程專案,還可以跟老司機交流討教!
代碼雖然不多,邏輯也并不復雜,但我們完整實作了網路請求庫中的 URL 決議模塊,這代表著完成了撰寫庫的基石之一,
在這個程序當中,我們了解到雙端通信的基本程序和要用到的資訊,在編碼中學會了如何將 urlparse、socket 和 namedtuple 結合到一起,
而且,你今天學到了 namedtuple 這個新姿勢!本文的文字及圖片來源于網路加上自己的想法,僅供學習、交流使用,不具有任何商業用途,著作權歸原作者所有,如有問題請及時聯系我們以作處理,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/151715.html
標籤:Python
上一篇:python學習第一天
下一篇:Flask目錄結構
