struct解决socket黏包问题 (指令传输)
服务端代码如下
import struct import subprocess import socket server = socket.socket() server.bind(('127.0.0.1',8900)) server.listen(5) coon,addr = server.accept() cmd = coon.recv(1024).decode('utf8') obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) obj1 = obj.stdout.read() obj2 = obj.stderr.read() len_obj = len(obj1+obj2) len_obj = struct.pack('i',len_obj) coon.send(len_obj) coon.send(obj1+obj2) coon.close() server.close()
客户端代码
import struct import socket client = socket.socket() client.connect(('127.0.0.1',8900)) cmd = input('>>>') client.send(cmd.encode('utf8')) form_server_len = client.recv(4) print(form_server_len) form_server_len = struct.unpack('i',form_server_len)[0] print(form_server_len) read_len = b'' while len(read_len) < form_server_len: data = client.recv(1024) read_len += data print(read_len.decode('gbk')) client.close()
每次发送总数据时,要提前将总数据的字节数发过去.
b1 = b'fjdklsfjdsklfjdslfdljskfa' 总长度为:6000个字节 len(b1) = 6000int的字节数
b2 = b'fdisfkljdsjafkl' 总长度为:400个字节 len(b2) = 400 int的字节数
int类型不能直接发送 你要将不同长度的数字类型转化成bytes
6000 ----> str(6000) ----> bytes(6000) b'6000'
此数据的构成: | 数据的总字节数(b'6000')| 具体数据
send(b'6000')
send(b'fjdklsfjdsklfjdslfdljskfa')
由于粘包现象,两次send可能会结合成一个数据发送:
b'6000fjdklsfjdsklfjdslfdljskfa
len(b'6000') 4个字节
recv(4) ---> b'6000'
剩下的6000个字节的数据我要循环recv() b'fjdklsfjdsklfjdslfdljskfa'
你面临的问题: 要将不固定长度的int 转化成固定长度的bytes 利用struct模块
# ret = struct.pack('i',6000)
# print(ret,type(ret),len(ret)) # 固定长度的bytes 4个字节 'b\xe5\x2c\xe1\xe7\'
此数据的构成: | 数据的总字节数(b'6000') (固定长度 4个字节)| 具体数据
send(ret)
send(b'fjdklsfjdsklfjdslfdljskfa')
由于粘包现象,两次send可能会结合成一个数据发送:
b'6000fjdklsfjdsklfjdslfdljskfa
len(b'6000') 4个字节
recv(4) ---> ret 根据struct反解出ret
# w = struct.unpack('i',ret)[0]
# w = 6000 int类型
total_data = b''
while len(total_data) < w:
data = conn.recv(1024)
total_data += data