首先为什么存在粘包?
1.点连续较小的seed (Nagle算法会进行打包发送)那么就会粘包
2.当发送的数据大于接收的限制也就是发送的seed'>接收的recv字节的数量时,一次接受不完,那么当第二次输入指令的时候就会发生取的是第一次没取完的数据,一直到取完第一次的数据,这也称之为粘包
在解决粘包之前,我们介绍一个概念缓冲区:
什么是缓冲区:?
.在我们接收和发送时接收和发送是存在缓存区的那么他们的作用是什么,
缓存区的作用:
1.暂时储存一些数据
2.1. 缓冲区如果你的网络波动,保证数据的收发稳定,匀速但是:也就造成了粘包现象之一:当出现连续的seed多次数据(微小的数据)时,你的数据会粘在一起发送出去(底层缘由是Nagle算法:将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。)上图
这就是缓冲区!!!!!
那么怎样解决粘包:
思路提供:1. 设服务端发送10000字节
-
客户端收数据的时候循环接收,(1024)例每次接收1024个字节,直至将所有的字节接收完毕最后一起解码
-
遇到问题
1.recv 的次数无法确定
2.你发送的总数据之前先给我发个总的数据长度例:1000字节,然后在发送总数据
3.客户端:先接受一个长度,10000字节然后我再循环只要你接收的数据小于10000字节我就一直接收
4.问题二:总数据长度不固定 -
你要将total_size int类型转化成bytes类型才可以发送
387 ---- > str(387) '387' ---->bytes b'387' 长度 3bytes
4185 ----> str(4185) '4185' ---->bytes b'4185' 长度 4bytes
18000------------------------------------------------------> 长度 5bytes
我们要解决:
将不固定长度的int类型转化成固定长度的bytes并且还可以翻转回来。
struct模块
那么我们就可以解决粘包:这是一个low版
import socket
import struct
import subprocess
phone = socket.socket()
phone.bind(('127.0.01',8878))
Python.listen(5)
while 1:
conn,adds = phone.accept()
while 1:
try:
receives_commands = conn.recv(1024)
receives_commands = receives_commands.decode('utf-8')
if receives_commands = 'Q':break
obj = subprocess.Popen(receives_commands,
shall = True
stdout = subprocess.PIPE
stderr =subprocess.PIPE )
ret = obj.stdout.read()+obj.stderr.read()
ret = ret.encode('utf-8')
ret_len = len(ret)
ret_len_struct = struct.pack('i',ret_len)
conn.send(ret_len_struct)
conn.send(ret)
except ConnectionResetError:
print('客户端终端')
break
conn.cloce()
phone.cloce()
#客户端
import socket
import struct
while 1:
dispatch_orders = inport('请输入您的命令:').strip().encode('utf-8')
if not dispatch_orders:print('不为空')
phone.send(dispatch_orders)
if dispatch_orders.upper() == b'Q':break
receives_commands_hand = phone.recv(4)
receives_commands_hand = struct.unpack('i',receives_commands_hand)
tata =b''
while len(tata)<receives_commands_hand:
tata+=phone.recv(1024)
tata = tata.decode('gbk')
print(f'来自服务端的回执 \n {tata}')
phone.close()
这样我们就解决了一部份粘包问题,那么有low版,也就有高大上版本,那么在这里给大家提供下思路:
- 我们要制作固定的报头
- 你现在有两段不固定长度的bytes类型,我们要固定报头,所以
- 你获取不固定长度的报头
- 利用struct 模块将不固定长度的报头固定成四个字节
- 先发送4字节再发送包头
- 先发送报头,再发总数据(有三部传输数据的过程(1.先发报头的长度,2.再发报头,3再发总文件数据))