7.1 什麼是socket?
讓我們挖得更深一點。首先我們學會了如何使用 request
,接著是 http.client
,還有proxy。接下來呢?我們將深入了解這些庫的內部...
Socket(字面意思:插座)是在網路中的一個點, 通過它數據可以發送和接收。Socket可以被看作是在同一或不同機器上運行的兩個程序之間的雙向通信通道的終點。
Socket支持不同的網路協議,但最常用的是兩种:
-
TCP
(Transmission Control Protocol):可靠的協議,提供連接的建立、數據完整性檢查和正確的順序。 -
UDP
(User Datagram Protocol):无连接的协议,不保证数据的交付,但是对于某些类型的应用程序而言更快和更高效。
為了識別socket,使用了IP地址(識別網路中的設備)和端口(識別設備上的特定應用程序或服務)。
重要!
IP地址和端口唯一識別網路中的程序。這就像房子地址和公寓號碼。房子地址(IP地址)是您計算機在網路中的地址,而端口則是程序用來接收和發送消息的公寓號碼。
您可以在講解網路組成的講座中更詳細地了解IP地址和端口是什麼。
程序使用socket的基本步驟:
- 創建socket: 程序創建一個socket,指明協議類型(TCP或UDP)。
- 與地址綁定: socket與IP地址和端口號綁定,以便可供連接或發送/接收數據。
- 監聽和建立連接(對於TCP):
- 監聽: 服務器端的socket被轉換為監聽模式,等待來自客戶端的連接。
- 建立連接: 客戶端發起連接,服務器接受連接,創建一個新的socket用於與客戶端交互。
- 數據交換: 數據在客戶端和服務器之間傳輸。對於TCP,數據以可靠的順序傳輸。
- 關閉連接: 在數據交換完成后,連接被關閉。
使用socket的好處:
- 靈活性: socket允許應用程序無論其位置或平台如何進行數據交換。
- 性能: socket提供快速和高效的數據傳輸方式,特別是使用UDP時。
- 可靠性(對於TCP): TCP協議提供可靠的數據傳送,带有完整性檢查和丟失包的恢復。
7.2 創建socket服務器
在Python中,使用內建的模組 socket
來進行socket通信,它提供了一個低階網路編程的界面。
透過socket,你可以創建一個socket服務器
——一個會接收客戶端請求並回應它們的應用程序/對象。同時也可以創建socket客戶端
——會向socket服務器
發送請求並從中接收回應的應用程序/對象。
為了創建socket服務器
,需要執行三個步驟:
- 創建socket服務器對象。
- 將其綁定(
bind
)到某個IP和端口。 - 開啟監聽模式(
listen
)以接收傳入消息。
這段程式碼看起來大致如下:
import socket
# 創建socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 將socket綁定到地址和端口
server_socket.bind(('localhost', 12345))
# 監聽傳入連接
server_socket.listen(5)
print("服務器正在等待連接...")
這裡 socket.AF_INET
指明我們使用的是IPv4協議,而 socket.SOCK_STREAM
表示我們使用的是TCP。這些參數在創建網路應用程序時最為常用。
在接收到一個傳入消息後,還需要執行四個步驟:
- 接受
(accept)
與客戶端的連接。 - 接收
(receive)
來自客戶端的請求(數據)。 - 向客戶端發送
(send)
回應——也是一些數據。 - 關閉
(close)
與客戶端的連接。
這段程式碼看起來大致如下:
# 接受一個新的連接
client_socket, client_address = server_socket.accept()
print(f"已與 {client_address} 建立連接")
# 從客戶端接收數據
data = client_socket.recv(1024)
print(f"接收到:{data.decode('utf-8')}")
# 向客戶端發送數據
client_socket.sendall(b'Hello, client!')
# 關閉與客戶端的連接
client_socket.close()
sendall()
方法被用於代替 send()
,因為它保證所有數據將被發送出去。send()
方法可能僅會在緩衝區滿時發送部分數據。
在 recv(1024)
中的1024指出一次可以接收的最大字節數。這有助於控制每次操作處理的數據量。
最後一個例子的代碼通常是在無限循環中執行的——服務器處理請求,然後等待新的請求,然後再處理,如此反复。
如果你想在自己的機器上運行它或者只是看看完整的例子,我將它寫在這裡:
import socket
# 創建socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 將socket綁定到地址和端口
server_socket.bind(('localhost', 12345))
# 監聽傳入連接
server_socket.listen(5)
print("服務器正在等待連接...")
while True:
# 接受新的連接
client_socket, client_address = server_socket.accept()
print(f"已與 {client_address} 建立連接")
# 從客戶端接收數據
data = client_socket.recv(1024)
print(f"接收到:{data.decode('utf-8')}")
# 向客戶端發送數據
client_socket.sendall(b'Hello, client!')
# 關閉與客戶端的連接
client_socket.close()
7.3 創建socket客戶端
我們已經創建了socket服務器,現在讓我們來編寫一個socket客戶端,它將訪問服務器並從中接收數據。
為此需要執行五個步驟:
- 創建
socket-client
對象。 - 與我們的
socket-server
的IP地址和端口建立連接(connect)
。 - 向服務器發送
(send)
消息。 - 從服務器接收
(receive)
數據。 - 關閉
(close)
連接。
其實這比看起來簡單。這段代碼大致如下:
import socket
# 創建socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 與服務器建立連接
client_socket.connect(('localhost', 12345))
# 向服務器發送數據
client_socket.sendall(b'Hello, server!')
# 從服務器接收數據
data = client_socket.recv(1024)
print(f"從服務器接收到:{data.decode('utf-8')}")
# 關閉socket
client_socket.close()
如果在另一端沒有運行socket-server
或連接中斷,則會拋出一個socket.error
類型的異常。所以別忘了處理異常。
今天我們就到這裡結束有關sockets的內容。
每當你進行網路相關的工作時,總會出現主機、端口、IP地址、建立連接、監聽請求等等。因此理解這些深層次的運作方式會極大地簡化你的工作並幫助將分散的知識整合成完整的畫面。
GO TO FULL VERSION