了解套接字行為:為什麼Socket.recv() 在沒有發送資料的情況下停止
Python 套接字與TCP連接一樣,表現為資料流在客戶端和伺服器之間流動。本文深入探討了修改資料傳輸後,socket.recv()呼叫無法傳回資料的原因。
Echo Server 範例
考慮官方文件中的 Python echo 伺服器範例。此伺服器偵聽傳入連線、接收資料並回顯給客戶端。以下程式碼片段複製了原始伺服器行為:
import socket HOST = '' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT)) s.listen(1) conn, addr = s.accept() print('Connected by', addr) while True: data = conn.recv(1024) if not data: break conn.sendall(data) conn.close()
更改伺服器行為
將程式碼修改為不將資料傳回客戶端時會出現此問題:
while True: data = conn.recv(1024) if not data: break conn.close()
在這段修改後的程式碼中,while循環不斷地從客戶端接收數據,但伺服器卻從不發送數據後退。這會導致客戶端在 socket.recv() 呼叫處無限期地停止。
理解通訊流程
TCP 套接字不維護一對一關係不同端點上的發送和接收呼叫之間。相反,協定定義了通訊規則。在這種情況下,原始的回顯伺服器實作了一個規則,即伺服器將回顯接收到的數據,直到客戶端關閉連線。
當伺服器行為發生變更時,規則實際上已被修改。伺服器現在只接收資料並丟棄它,直到客戶端關閉連線。伺服器永遠不會將資料傳回客戶端。
調整客戶端行為
要使用修改後的伺服器,客戶端必須調整其行為。由於伺服器不再主動發送數據,客戶端認為收到回數據表示連線已完成。為了實現這一點,客戶端應該關閉其連接的傳出端,以向伺服器發出訊號已完成發送資料。然後,客戶端可以執行多個 recv 呼叫來處理傳入資料的任何潛在碎片。
更新的程式碼
以下是伺服器和客戶端的更新程式碼,遵守修改後的規則通訊:
伺服器:
import socket HOST = '' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((HOST, PORT)) s.listen(1) conn, addr = s.accept() print('Connected by', addr) while True: data = conn.recv(1024) if not data: break conn.sendall(b'ok') conn.shutdown(socket.SHUT_WR) conn.close()
客戶端:
import socket HOST = 'localhost' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) s.sendall(b'Hello, world') s.shutdown(socket.SHUT_WR) data = b'' while True: buf = s.recv(1024) if not buf: break data += buf s.close() print('Received', repr(data))
透過了解基於流的本質TCP套接字並相應地調整通訊規則,可以解決socket.recv()在沒有資料的情況下停止的問題已發送。
以上是當伺服器不發回資料時,為什麼 `socket.recv()` 會停止?的詳細內容。更多資訊請關注PHP中文網其他相關文章!