所謂粘包問題主要還是C/S兩端數據傳輸時 因為接收方不知道消息之間的界限,不知道一次性提取多少字節的數據所造成的
根本原因:
粘包是由TCP協議本身造成的,TCP為提高傳輸效率,發送方往往要收集到足夠多的數據后才發送一個TCP段。若連續幾次需要send的數據都很少,通常TCP會根據優化算法把這些數據合成一個TCP段后一次發送出去,這樣接收方就收到了粘包數據。
解決方法:
1、自定義字典類型 的數據報頭{文件名:a,文件的size:1090}計算出該報頭的長度(len(字節)),
2、使用struct.pack('i',報頭長度(一個數字))把一個數字壓縮成固定的size 4個字節,發送給對端。
3、對端 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()