Python 標準庫 18.1 - socket

socket 是一種經常使用的進程間通訊接口。服務器

socket object


Python 實現 socket 的主體對象是 socket.socket 類。兩個互相鏈接的 socket 對象之間是對等的,所以他們的鏈接過程基本上是這樣的:框架

  1. 乙方首先監聽一個端口,並將本身的 ip 和 port 經過其餘方式告知甲方
  2. 甲方向該 (ip, port) 發起鏈接請求
  3. 乙方接受此請求,鏈接創建成功,雙方能夠通訊

用代碼來解釋就是這樣:socket

乙:code

import socket

sock = socket.socket()
sock.bind(('127.0.0.1', 2333))

sock.listen(1)
conn, addr = sock.accept()  # 這裏可能會阻塞
data = conn.recv(1024)  # 同上

甲:server

import socket

sock = socket.socket()
sock.connect(('127.0.0.1', 2333))
sock.send(b'hello')

其中乙方的 .bind 方法就是先聲明並佔用一個通訊端口,這樣甲方纔知道第一次的鏈接請求應該發送到哪。而後乙方調用 .listen 方法開始監聽,當甲方的 connect 請求發送過來後,調用 accept 方法便可接受甲方的鏈接請求,此方法返回一個新的 socket 對象(conn)和甲方的地址。對象

因此這裏 type(conn) is type(sock) 是會返回 True 的,即當你調用一個已綁定的 socket 對象的 listen 方法時,他實際會調起一個服務器監聽綁定的地址,並返回一個 新的 socket 對象用於通訊,而後原 socket 對象繼續監聽,並在 accept 時繼續建立新的 socket 對象。這裏的甲乙 sock 對象是一種 C/S 模型。剛纔說的對等模型實際上是指 甲方的 sock 對象和乙方的 conn 對象。接口

所以這裏的一個問題在於,乙方的 Server 在面對多個甲方的隨機 connect 請求時,極可能沒辦法作到當即接受(.accept),而又不可能讓甲方一直等待。因此 listen 方法提供了一個整型的 backlog 參數,在上例中其爲 1. 這個參數表示在 accept 以前最多能夠積壓多少個 connect 請求。實際上說是積壓,實際上是直接返回了確認接受的信息。即,若是上面代碼中乙方先不調用 accept,甲方也是能夠 send 的,b'hello' 會被緩衝起來。乙方再調用 accept 和 recv 依然能夠拿到數據。而由於上面設置的 backlog 是 1,因此若是在乙方 accept 以前又有一個 socket 向乙方發起 connect 請求,他就會當即收到一個顯式的(積極的)拒絕鏈接響應。進程

send & recv


socket 由於是語言無關的接口,因此只能用它發送字節碼(二進制)。因此你須要 encode/decode 一下你的字符串對象。而數據流(socket.SOCK_STREAM)又沒有既定的邊界。因此須要使用者自行管理邊界問題。即甲方前後發送的兩段數據,在乙方的緩衝中雖然有前後順序,卻沒有間隔。ip

socketserver


socketserver 是 Python 標準庫的一個包,功能如其名,是一個 socket 服務器開發框架。服務器開發

相關文章
相關標籤/搜索