python客户端软件开发_用 Python 实现一个简易版 HTTP 客户端
此文為《用 Python 擼一個 Web 服務器》系列教程的一個補充,這個系列教程介紹了如何使用 Python 內置的 socket 庫實現一個簡易版的 Web 服務器。
之所以寫這篇文章,是因為我發現很多人并不清楚 HTTP 客戶端的概念,以為只有瀏覽器才叫 HTTP 客戶端。事實上并非如此,我們在 Web 開發中常見的 Postman、爬蟲程序、curl 命令行工具 等,這些都可以稱為 HTTP 客戶端。
服務器程序示例
這里以一個 Hello World 程序來作為示例服務器,實現如下:# server.py
import socket
import threading
def process_connection(client):
"""處理客戶端連接"""
# 接收客戶端發來的數據
data = b''
while True:
chunk = client.recv(1024)
data += chunk
if len(chunk) < 1024:
break
# 打印從客戶端接收的數據
print(f'data: {data}')
# 給客戶端發送響應數據
client.sendall(b'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n
Hello World
')# 關閉客戶端連接對象
client.close()
def main():
# 創建 socket 對象
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 允許端口復用
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 綁定 IP 和端口
sock.bind(('127.0.0.1', 8000))
# 開始監聽
sock.listen(5)
while True:
# 等待客戶端請求
client, addr = sock.accept()
print(f'client type: {type(client)}\naddr: {addr}')
# 創建新的線程來處理客戶端連接
t = threading.Thread(target=process_connection, args=(client,))
t.start()
if __name__ == '__main__':
main()
極簡客戶端
知道了如何用 socket 庫實現服務器端程序,那么理解客戶端程序的實現就非常容易了。客戶端程序代碼實現如下:# client.py
import socket
# 創建 socket 對象
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 指定服務器 IP 和端口,進行連接
sock.connect(('127.0.0.1', 8000))
# 向 URL "/" 發送 GET 請求
sock.send(b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8000\r\n\r\n')
# 接收服務端響應數據
data = b''
while True:
chunk = sock.recv(1024)
data += chunk
if len(chunk) < 1024:
break
# 打印響應數據
print(data)
# 關閉連接
sock.close()
相對來說客戶端程序要簡單一些,創建 socket 對象的代碼與服務器端程序并無差別,客戶端 socket 對象根據 IP 和端口來連接指定的服務器,建立好連接后就可以發送數據了,這里根據 HTTP 協議構造了一個針對 / URL 路徑的 GET 請求,為了簡單起見,請求頭中僅攜帶了 HTTP 協議規定的必傳字段 Host,請求發送成功后便可以接收服務器端響應,最后別忘了關閉 socket連接。
僅用幾行代碼,我們就實現了一個極簡的 HTTP 客戶端程序,接下來對其進行測試。
首先在終端中使用 Python 運行服務器端程序:python3 server.py。然后在另一個終端中使用 Python 運行客戶端程序:python3 client.py。
可以看到客戶端打印結果如下:b'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n
Hello World
'以上,我們實現了一個極簡的 HTTP 客戶端。
參考 requests 實現客戶端
用 Python 寫過爬蟲的同學,一定聽說或使用過 requests 庫,以下是使用 requests 訪問 Hello World 服務端程序的示例代碼:# demo_requests.py
import requests
response = requests.request('GET', 'http://127.0.0.1:8000/')
print(response.status_code) # 響應狀態碼
print('--------------------')
print(response.headers) # 響應頭
print('--------------------')
print(response.text) # 響應體
在終端中使用 python3 demo_requests.py 運行此程序,將打印如下結果:200
--------------------
{'Content-Type': 'text/html'}
--------------------
Hello World
接下來修改我們上面實現的極簡 HTTP 客戶端程序,使其能夠支持 response.status_code、response.headers 和 response.text功能。# client.py
import socket
from urllib.parse import urlparse
class HTTPClient(object):
"""HTTP 客戶端"""
def __init__(self):
# 創建 socket 對象
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 初始化數據
self.status_code = 200
self.headers = {}
self.text = ''
def __del__(self):
# 關閉連接
self.sock.close()
def connect(self, ip, port):
"""建立連接"""
self.sock.connect((ip, port))
def request(self, method, url):
"""請求"""
# URL 解析
parse_result = urlparse(url)
ip = parse_result.hostname
port = parse_result.port or 80
host = parse_result.netloc
path = parse_result.path
# 建立連接
self.connect(ip, port)
# 構造請求數據
send_data = f'{method} {path} HTTP/1.1\r\nHost: {host}\r\n\r\n'.encode('utf-8')
# 發送請求
self.sock.send(send_data)
# 接收服務端響應的數據
data = self.recv_data()
# 解析響應數據
self.parse_data(data)
def recv_data(self):
"""接收數據"""
data = b''
while True:
chunk = self.sock.recv(1024)
data += chunk
if len(chunk) < 1024:
break
return data.decode('utf-8')
def parse_data(self, data):
"""解析數據"""
header, self.text = data.split('\r\n\r\n', 1)
status_line, header = header.split('\r\n', 1)
for item in header.split('\r\n'):
k, v = item.split(': ')
self.headers[k] = v
self.status_code = status_line.split(' ')[1]
if __name__ == '__main__':
client = HTTPClient()
client.request('GET', 'http://127.0.0.1:8000/')
print(client.status_code)
print('--------------------')
print(client.headers)
print('--------------------')
print(client.text)
代碼實現比較簡單,我寫了較為詳細的注釋,相信你能夠看懂。其中使用了內置函數 urlparse ,此函數能夠根據 URL 格式規則將 URL 拆分成多個部分。
在終端中使用 python3 client.py 運行此程序,打印結果與使用 requests 的結果完全相同。200
--------------------
{'Content-Type': 'text/html'}
--------------------
Hello World
僅用幾十行代碼,我們就實現了一個簡易版的 HTTP 客戶端程序,并且還實現了類似 requests 庫的功能。
接下來你可以嘗試用它去訪問現實世界中真實的 URL,比如訪問 http://httpbin.org/get,看看打印結果如何。
P.S.
Web 開發本質是圍繞著 HTTP 協議進行的,HTTP 協議是 Web 開發的基石。所以對于何為 HTTP 服務端、何為 HTTP 客戶端的概念不夠清晰的話,實際上都是對 HTTP 協議不夠理解。
最后,給大家留一道作業題,實現 requests 庫的 response.json() 方法。
聯系我:
總結
以上是生活随笔為你收集整理的python客户端软件开发_用 Python 实现一个简易版 HTTP 客户端的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 压缩和解压命令
- 下一篇: 死锁产生的原因及条件、如何避免死锁