粘包现象与解决方案
粘包
粘包是指两次输出结果粘到一起,它的发生主要是因为socket缓冲区导致的,粘包只在tcp中产生,不在UDP产生
粘包的解决方法:
使用struct模块,先报头长度进行打包发给客户端,客户端收到之后先解包报头长度,再接收真实的数据
例子:
服务端:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import socket
import subprocess
import struct
import json
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',9909)) #0-65535:0-1024给操作系统使用
phone.listen(5)
print('starting...')
while True: # 链接循环
conn,client_addr=phone.accept()
print(client_addr)
while True: #通信循环
try:
#1、收命令
cmd=conn.recv(8096)
if not cmd:break #适用于linux操作系统
#2、执行命令,拿到结果
obj = subprocess.Popen(cmd.decode('utf-8'), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout=obj.stdout.read()
stderr=obj.stderr.read()
#3、把命令的结果返回给客户端
#第一步:制作固定长度的报头
header_dic={
'filename':'a.txt',
'md5':'xxdxxx',
'total_size': len(stdout) + len(stderr)
}
header_json=json.dumps(header_dic)
header_bytes=header_json.encode('utf-8')
#第二步:先发送报头的长度
conn.send(struct.pack('i',len(header_bytes)))
#第三步:再发报头
conn.send(header_bytes)
#第四步:再发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError: #适用于windows操作系统
break
conn.close()
phone.close()
客户端:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import socket
import struct
import json
# 产生对象
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 进行连接
phone.connect(('192.168.43.129',8082))
while True:
# 收发消息
msg = input('>>:').strip()
if not msg:continue
phone.send(msg.encode('utf-8'))
#先收报头长度
obj = phone.recv(4)
header_size = struct.unpack('i',obj)[0]
#接收报头
header_bytes = phone.recv(header_size)
#解析对真实数据的描述信息
header_json = header_bytes.decode('utf-8')
header_dic = json.loads(header_json)
total_size = header_dic['total_size']
#接收真实的数据
rev_size = 0
rev_data = b''
while rev_size < total_size: # 如果接收的数据小于从报头中解析出来的数据会一直循环进行接收
res = phone.recv(1024)
rev_data += res
rev_size += len(res)
print(rev_data.decode('utf-8'))
phone.close()