socket 是一種經常使用的進程間通訊接口。服務器
Python 實現 socket 的主體對象是 socket.socket
類。兩個互相鏈接的 socket 對象之間是對等的,所以他們的鏈接過程基本上是這樣的:框架
用代碼來解釋就是這樣: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 請求,他就會當即收到一個顯式的(積極的)拒絕鏈接響應。進程
socket 由於是語言無關的接口,因此只能用它發送字節碼(二進制)。因此你須要 encode/decode
一下你的字符串對象。而數據流(socket.SOCK_STREAM
)又沒有既定的邊界。因此須要使用者自行管理邊界問題。即甲方前後發送的兩段數據,在乙方的緩衝中雖然有前後順序,卻沒有間隔。ip
socketserver 是 Python 標準庫的一個包,功能如其名,是一個 socket 服務器開發框架。服務器開發