目錄python
什麼是粘包問題呢?shell
在咱們寫 tcp socket編程的時候,tcp協議是一個流式的協議,服務端第一次發送的數據,客戶端沒法準確一次性的接收完畢,下一次發送的數據與上一次數據粘在一塊兒。編程
即:sass
一、 沒法預測對方須要接收的數據大小長度安全
二、 屢次連續發送數據量小的,而且時間間隔短的數據 會一次性打包一塊兒發送服務器
TCP 協議的特性:socket
會將屢次連續發送的數據量小的,而且時間間隔短的數據一次性發送完畢tcp
咱們用subprocess 模塊來演示一個粘包問題。code
# 服務端 # coding=utf-8 import socket import subprocess server = socket.socket() address = ("127.0.0.1",8888) server.bind(address) server.listen(5) while True: conn , addr = server.accept() while True: try: cmd = conn.recv(1024).decode("utf-8") print(cmd) if cmd == "q": break obj = subprocess.Popen( cmd,shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) res = obj.stdout.read() + obj.stderr.read() conn.send(res) except Exception: break conn.close()
# 客戶端 # coding=utf-8 import socket client = socket.socket() address = ("127.0.0.1",8888) client.connect(address) while True: cmd = input("請輸入>>>") client.send(cmd.encode("utf-8")) if cmd == "q": break data = client.recv(1024) print(data.decode("gbk")) client.close()
終端打印結果server
請輸入>>>tasklist 映像名稱 PID 會話名 會話# 內存使用 ========================= ======== ================ =========== ============ System Idle Process 0 Services 0 24 K System 4 Services 0 3,172 K smss.exe 352 Services 0 1,200 K csrss.exe 464 Services 0 6,656 K wininit.exe 572 Services 0 5,168 K csrss.exe 588 Console 1 77,948 K services.exe 636 Services 0 12,288 K lsass.exe 652 Services 0 11,164 K lsm.exe 660 Services 0 4,664 K winlogon.exe 744 Console 1 8,180 K svchost.exe 812 Services 0 10,040 K svchost. 請輸入>>>dir exe 892 Services 0 8,280 K svchost.exe 980 Services 0 21,744 K svchost.exe 168 Services 0 21,060 K svchost.exe 388 Services 0 40,792 K svchost.exe 908 Services 0 12,252 K WUDFHost.exe 1100 Services 0 8,096 K ZhuDongFangYu.exe 1188 Services 0 23,784 K svchost.exe 1236 Services 0 17,532 K wlanext.exe 1412 Services 0 5,268 K conhost.exe 1420 Services 0 2,860 K dwm.exe 1536 Console 1 38,436 K explorer.exe 1588 Console 1 70,028 K spoolsv.exe 1612 Services 0 12,204 K svchost.exe
咱們看到在輸完tasklist 命令以後,再次輸入其餘命令,仍是上次命令的結果,
那麼久證實了 服務端第一次發送的數據,客戶端沒法準確一次性的接收完畢,下一次發送的數據與上一次數據粘在一塊兒。咱們在客戶端接收的時候,接收的數據大小是1024個字節,服務器執行結果 超出了接收的大小,因此至關於把結果堆到了後面,一塊兒發送,因此下次執行命令得不到正確的結果,那麼咱們須要解決這個問題就須要用到 struct 模塊
struct 模塊必須先定義報頭,,先發送報頭,再發送真實數據
# 服務端 # coding=utf-8 import struct import socket import subprocess server = socket.socket() address = ("127.0.0.1",8888) server.bind(address) server.listen(5) while True: conn,addr = server.accept() while True: try: cmd = conn.recv(1024).decode("utf-8") print(cmd) if cmd == "q": break obj = subprocess.Popen( cmd ,shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) res = obj.stdout.read() + obj.stderr.read() # 將執行結果計算長度用i模式打包 res_len = struct.pack("i",len(res)) # 先發送數據長度 conn.send(res_len) # 再發送真實數據 conn.send(res) except Exception: break conn.close()
# 客戶端 # coding=utf-8 import socket import struct client = socket.socket() address = ("127.0.0.1",8888) client.connect(address) while True: cmd = input("請輸入命令>>>") client.send(cmd.encode("utf-8")) if cmd == "q": break # 用struct模塊接收的長度統一是4個字節, head = client.recv(4) # 而後用struct模塊解包獲得數據的真實長度,返回的是元組類型,0表示第一個元素,就是真實長度 data_len = struct.unpack("i",head)[0] # 而後再把真實長度接收便可。 data = client.recv(data_len) print(data.decode("gbk")) client.close()
udp也是一種傳輸協議
1)不須要創建雙向通道
2)不會粘包
3)客戶端給服務端發送數據,不須要等待服務端返回接收成功
4)數據容易丟失,數據不安全。
TCP:就至關於與在打電話
UDP:就至關於與在發短信
# 服務端 # coding=utf-8 import socket server = socket.socket(type=socket.SOCK_DGRAM) address = ("127.0.0.1",8888) server.bind(address) while True: msg,addr = server.recvfrom(1024) print(msg.decode("utf-8")) # 服務端往客戶端發送消息 send_msg = input("服務端發送消息") server.sendto(send_msg.encode("utf-8"),addr)
# 客戶端 # coding=utf-8 import socket client = socket.socket(type=socket.SOCK_DGRAM) address = ("127.0.0.1",8888) while True: send_msg = input("請輸入信息") client.sendto(send_msg.encode("utf-8"),address) data = client.recv(1024) print(data.decode("utf-8"))