所谓粘包问题主要还是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] 把成自己解包会数字
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | # 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()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南