所謂粘包問題主要仍是C/S兩端數據傳輸時 由於接收方不知道消息之間的界限,不知道一次性提取多少字節的數據所形成的
根本緣由:
粘包是由TCP協議自己形成的,TCP爲提升傳輸效率,發送方每每要收集到足夠多的數據後才發送一個TCP段。若連續幾回須要send的數據都不多,一般TCP會根據優化算法把這些數據合成一個TCP段後一次發送出去,這樣接收方就收到了粘包數據。
解決方法:
一、自定義字典類型 的數據報頭{文件名:a,文件的size:1090}計算出該報頭的長度(len(字節)),
二、使用struct.pack('i',報頭長度(一個數字))把一個數字壓縮成固定的size 4個字節,發送給對端。
三、對端 struct.unpack(‘i’,recv(4))接收固定大小4個字節;這就是接收到了 報頭的長度。
4.recv(報頭長度)這就是發送過來的報頭信息了
import struct
a='您好'
a=len(a.encode('utf-8')) #字節的長度=====這個數據有多大字節
# 1英文字母utf-8編碼後=1字節
# #1中文字符 utf-8編碼後=3個字節
#
a=struct.pack('i',a) #struct.pack把數字轉換成 固定大小 4個字節的 字節
print(len(a)) #4個字節
print(struct.unpack('i',a)[0]) #struct.unpack[0] 把成本身解包會數字
服務端
# import socket # import subprocess # iphon=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #(創建一個socket對象) # iphon.bind(('127.0.0.1',8080)) #綁定到 IP+端口上 成爲惟一的socket # iphon.listen(5) #設置鏈接池的個數 # print('starting........') # while True: #鏈接循環 # conn,addr=iphon.accept() #等待電話鏈接 # print('電話線路是',conn) # print('客戶手機號:',addr) # while True: #通訊循環 發送和接收 # try: # data=conn.recv(1024) #接受消息 最大從內存裏接受1024MB數據 # print('客戶端發來的消息是%s'%data) # data=data.decode('utf-8') #從客戶端發來的數據是通過編碼的字節數據 因此須要解碼 成Unicode # res=subprocess.Popen( data, shell=True, stdout=subprocess.PIPE) #解碼後傳進subprocess.Popen去cmd執行 # data1 = res.stdout.read().decode('gbk') #cmd是gbk編碼因此須要gbk解碼 # print(data1) #打印解碼後的結果 # data1=data1.encode('gbk') #編碼 # conn.send(data1) #發送消息 #編碼後再傳輸給客戶端 # except Exception: # break # conn.close() # iphon.close() import socket import struct import json phon=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phon.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phon.bind(("127.0.0.1",8090)) phon.listen(80) # while True: conn,addr=phon.accept() while True: try: data=conn.recv(4) #接受4個字節的報頭 data=struct.unpack('i',data)[0] data1=conn.recv(data).decode('utf-8') #接受 字節類型的報頭信息 #{"file_name": "\u4f60\u597d", "file_size": 6} data1=json.loads(data1) print(data1) da=conn.recv(data1['file_size']).decode('utf-8') #接收真實數據 print(da) # print("接受到來自客戶端發來的消息",data) conn.send('sss'.encode('utf-8')) #發送接受的消息 給某一個客戶端 except Exception: break conn.close() phon.close()
客戶端
import socket import struct import json phon=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phon.connect(('127.0.0.1',8090)) #客戶端的phon.connect正好對於服務端的phon1.accept() while True: #循環通訊 mes=input('---->: '.strip()) if not mes: continue mes = mes.encode('utf-8') mes_len = len(mes) head = {'file_name': mes.decode('utf-8'), 'file_size': mes_len} head_json = json.dumps(head) # {"file_name": "a", "file_size": 1} head_bytes = head_json.encode('utf-8') head_bytes_len = len(head_bytes) # 51 struct1 = struct.pack('i',head_bytes_len) send_=phon.send(struct1) #發送4個字節的 報頭長度 data=phon.send(head_bytes) #發送報頭 da=phon.send(mes) #發送真實數據 phon.close()