RST報文段的意義
客戶端代碼,服務(wù)端代碼如下
客戶端代碼
import socket
SERVER_ADDR = '127.0.0.1'
PORT = 18000
CHUNK_SIZE = 1024 * 4
def main():
""" echo 客戶端: 基于 AF_INET domain and TCP type 的 socket """
# socket -> s.connect -> s.sendall -> s.shutdown -> loop s.recv -> s.close
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((SERVER_ADDR, PORT))
s.sendall(b"hello")
s.shutdown(socket.SHUT_WR) # if without this line code, the server and client will be deadlocked!
response = b""
while data := s.recv(CHUNK_SIZE):
response += data
print(response.decode())
if __name__ == "__main__":
main()
服務(wù)端代碼
import socket
HOST = '0.0.0.0'
PORT = 18000
BACKLOG = 16
CHUNK_SIZE = 1024 * 4
def handle_client(conn, addr):
with conn:
print(f"{addr[0]}:{addr[1]}", flush=True, end=' ')
request = b""
while data := conn.recv(CHUNK_SIZE):
request += data
print(request.decode(), flush=True)
conn.sendall(request)
def main():
""" echo 服務(wù)器: 基于 AF_INET domain and TCP type 的 socket """
# socket -> s.bind -> s.listen -> s.accept -> s.close
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(BACKLOG)
print(f"Listening on {HOST}:{PORT}\n", flush=True)
try:
while True:
conn, addr = s.accept()
handle_client(conn, addr)
except KeyboardInterrupt:
print("\nServer shutting down...")
if __name__ == "__main__":
main()
運(yùn)行結(jié)果如下

刪除客戶端一行代碼就會發(fā)生死鎖,如下
s.shutdown(socket.SHUT_WR) # if without this line code, the server and client will be deadlocked!
死鎖發(fā)生的時候,按下Ctrl + C 結(jié)束客戶端的運(yùn)行,則有以下過程
- 客戶端的內(nèi)核開始清理客戶端的socket資源,首先向服務(wù)端發(fā)送一個FIN報文
- 服務(wù)端內(nèi)核收到FIN報文,然后服務(wù)端從recv返回,打印數(shù)據(jù),然后sendall發(fā)送數(shù)據(jù)
- 客戶端收到服務(wù)端發(fā)送的數(shù)據(jù),不處理,向客戶端發(fā)送RST報文,表示客戶端的socket已經(jīng)不存在,不要再發(fā)送數(shù)據(jù)了
- 服務(wù)端收到RST報文,關(guān)閉conn socket,重新回到main函數(shù)的while循環(huán)中

浙公網(wǎng)安備 33010602011771號