出现黏包问题的原因:
首先,只有在TCP协议中才会出现黏包现象,因为TCP协议是面向流的协议
在发送数据的传输过程中存在缓存机制来避免数据丢失
因此,在连续发送小数据 以及 接受大小不符的时候都容易出现黏包现象
本质还是因为我们在接收数据的时候不知道发送的数据的长短
解决黏包问题的方法:
在传输大量数据之前先告诉接收端要发送数据的大小
一般我们使用struct模块来定制协议
struct模块:
pack # 将真正的文件大小打包成一个4字节数据
unpack # 将传来的4字节打包数据解压,得到一个具有真正大小的元祖(即uppack[0]才是真正的数据大小)
# 出现黏包的场景
# 连续send两个小数据
# 两个recv,第一个recv特别小
# 本质上:你不知道到底要接受多大的数据
# 解决
# 首先:发送一下这个数据到底有多大
# 再按照数据的长度接收数据
#这种解决方式的好处:
#确定了我到底要接收多大的数据
#在文件中配置一个配置项:就是每一次recv的大小 buffer=4096
# 当我们要发送大数据的时候,要明确的告诉接收方要发送多大的数据,以便接收方能够
# 准确的接收到所有的数据
# 多在文件的传输过程中
# 大文件的传输一定是按照字节读,每一次读固定的字节
# 服务端:一边读,一边传 ---------------------- 接收端:一边收,一边写
# send这个大文件之前,40000个字节,send(4096) 40000-4096-4096... -->0以此类推,一点点传
# recv这个大文件之前,recv 40000字节,recv(4096) 40000-4096-4096 -->0以此类推,一点点接
#但是为了不让你发送的数据大小也遇到黏包问题,在此引入struct模块
#以shell命令为例
import struct import socket sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.listen(0) conn,addr = sk.accept() while True: cmd = input('>>>') if cmd == 'q': conn.send(b'q') break conn.send(cmd.encode('gbk')) num = conn.recv(4) num = struct.unpack('i',num)[0] res = conn.recv(int(num)).decode('gbk') print(res) conn.close() sk.close()
import socket import subprocess import struct sk = socket.socket() sk.connect(('127.0.0.1',8080)) while True: cmd = sk.recv(1024).decode('gbk') if cmd == 'q': break res = subprocess.Popen(cmd,shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) std_out = res.stdout.read() std_err = res.stderr.read() len_num = len(std_err)+len(std_out) num_by = struct.pack('i',len_num) sk.send(num_by) sk.send(std_out) sk.send(std_err) sk.close()