Python Socket 程式設計示例 Echo Server
簡評:我們已經從「Python Socket 程式設計概覽」瞭解了 socket API 的概述以及客戶端和伺服器的通訊方式,接下來讓我們建立第一個客戶端和伺服器,我們將從一個簡單的實現開始,伺服器將簡單地回顯它接收到客戶端的任何內容。本文將詳細解釋伺服器部分的程式碼。
下面是伺服器程式碼儲存到 echo-server.py檔案:
#!/usr/bin/env python3 import socket HOST = '127.0.0.1' # Standard loopback interface address (localhost) PORT = 65432 # Port to listen on (non-privileged ports are > 1023) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() conn, addr = s.accept() with conn: print('Connected by', addr) while True: data = conn.recv(1024) if not data: break conn.sendall(data)
socket.socket()建立一個支援上下文管理器型別的 socket 物件,因此可以在 with 語句中使用它,沒有必要去呼叫 s.close():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
pass # Use the socket object without calling s.close().
傳遞給socket()的引數指定地址族和 socket 型別。 AF_INET 指的是 IPv4 的網路地址。 SOCK_STREAM是 TCP 的 socket 型別,TCP 用於在網路中傳輸訊息。
bind()用於將 socket 與特定網路介面和埠號相關聯:
HOST = '127.0.0.1' # Standard loopback interface address (localhost)
PORT = 65432 # Port to listen on (non-privileged ports are > 1023)
# ...
s.bind((HOST, PORT))
傳遞給bind()的值取決於 socket 的地址族。在這個例子中,我們使用的是socket.AF_INET(IPv4)所以它接受一個(host, port)元組。
host 可以是主機名、IP 地址或空字串。如果使用 IP 地址,則主機應為 IPv4 格式的地址字串,127.0.0.1 是環回介面的標準 IPv4 地址,因此只有主機上的程序才能連線到伺服器。如果傳遞空字串,則伺服器將接受所有可用 IPv4 介面上的連線。
port 應為 1-65535 之間的整數(0 被保留),它是接受來自客戶端連線的 TCP 埠號,如果埠號 <1024,某些系統可能需要超級使用者許可權。
listen()使伺服器能夠 accept()連線,這使它成為一個「listening」socket:
s.listen()
conn, addr = s.accept()
accept()阻塞並等待傳入請求連線。當客戶端連線時,它返回一個表示連線的 socket 物件和一個儲存客戶端地址的元組,該元組包含用於 IPv4 連線的(host, port)或用於 IPv6的(host, port, flowinfo, scopeid)。
必須要理解的一件事是我們現在有一個來自accept()的新 socket 物件,這很重要,因為它是用於與客戶端通訊的 socket,它與伺服器用於接受新連線的偵聽 socket 不同:
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
從accept()獲取客戶端 socket 物件conn後,使用無限迴圈來迴圈阻塞對 conn.recv()的呼叫。這將讀取客戶端傳送的任何資料,並使用 conn.sendall()將其回送回來。
如果conn.recv()返回一個空位元組物件b'',則客戶端關閉連線並終止迴圈。 with 語句與 conn 一起使用以自動關閉塊末尾的 socket。