1.粘包现象
TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
粘包出现原因
使用了优化方法(Nagle算法),将多次间隔较小、数据量小的数据,合并成一个大的数据块,然后进行封包。
简单得说,在流传输中出现,UDP不会出现粘包,因为它有消息边界
1发送端需要等缓冲区满才发送出去,造成粘包
2接收方不及时接收缓冲区的包,造成多个包接收
解决方法
接收方创建一预处理线程,对接收到的数据包进行预处理,将粘连的包分开。
TCP无保护消息边界的解决
针对这个问题,一般有3种解决方案:
(1)发送固定长度的消息
(2)把消息的尺寸与消息一块发送
(3)使用特殊标记来区分消息间隔
2.struct模块
该模块可以把一个类型,如数字,转成固定长度的bytes
可以转的类型:
用法:
import struct ret = struct.pack('i',23333) #i表示int类型,把23333转成固定长度的bytes类型 struct.pack('i',ret) #把bytes转回int
3.例子
#以远程执行命令为例讲解决方法
#先发送传输的大小
服务端:
import socket
import struct
sk = socket.socket()
s = ('127.0.0.1', 8081)
sk.bind(s)
sk.listen(2)
conn, addr = sk.accept()
while 1:
cmd = input('[cmd] #')
if cmd == 'q':
break
conn.send(cmd.encode('utf-8'))
lens = conn.recv(4) #接收包长度
lens = struct.unpack('i',lens)[0]
info = conn.recv(lens)
print(info.decode('gbk')) 客户端:
import socket
import subprocess
import struct
sk = socket.socket()
sk.connect(('127.0.0.1',8081))
while 1:
cmd = sk.recv(1024).decode('gbk')
res = subprocess.Popen(cmd,shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
std = res.stdout.read()+res.stderr.read()
lens = len(std)
lens = struct.pack('i', lens) #把长度转成4个字节的bytes
sk.send(lens)
sk.send(std)