python 中黏包的处理(实现简单的ssh)
黏包的处理
- 首先黏包就是连续发送两个数据,且中间没有阻塞时,操作系统自动将两次数据打包到一起发送
- 黏包的发生会造成数据传输后,数据丢失,不完整,接收到数据不能使用
- 通过阻塞解决黏包问题(影响效率)
- 通过添加数据长度解决黏包问题(常用解决方式,如下ssh的实例)
ssh的实例
- 服务器端代码如下:
import socket
import subprocess #使用cmd命令的模块
import struct #压缩包的模块,将整形数字压缩成4个字节
#ret=struct.pack("i",1211)#i为整数模式,最小-2147483648,最大压缩2147483647,压缩后为4个字节
ssh_Server = socket.socket()
ssh_Server.bind(('127.0.0.1',8000))
ssh_Server.listen(5)
while 1:
print('等待连接')
conn,addr = ssh_Server.accept()
print('连接成功')
while 1:
try:
cmd = conn.recv(1024).decode('gbk') #接受客户端输入的字符串形式的cmd命令
#在服务器端实现字符串形式的cmd命令,并获取到结果,stderr为错误命令结果,stdout为正确命令结果
ret = subprocess.Popen(cmd,
shell = True,
stderr = subprocess.PIPE,
stdout = subprocess.PIPE,
)
err = ret.stderr.read()#获取错误命令结果的字节,(windows默认gbk编码)
out = ret.stdout.read()#获取正确命令结果的字节
if err:#如果错误名存在值,说明客户端输入的是错误的cmd命令,则返回错误信息
print(len(err))#显示错误信息字节长度
len_err = struct.pack("i", len(err))#将错误信息字节长度压缩成4个字节
conn.send(len_err)#发给客户端要接受的数据长度,方便客户端接受数据
conn.send(err)#发给客户端提示错误的数据信息
else:
print(len(out))#显示正确信息字节长度
len_out = struct.pack("i", len(out))#将正确信息字节长度压缩成4个字节
conn.send(len_out)
conn.send(out)#发给客户端提示错误的数据信息
except Exception as e:
print('连接已断开')
break
- 客户端代码如下:
import socket
import struct
ssh_Client = socket.socket()
ssh_Client.connect(('127.0.0.1', 8000))
while 1:
cmd = input('请输入命令:')#输入字符串形式的cmd命令
ssh_Client.send(cmd.encode('gbk'))#将字符串形式的命令转换成字节(Windows中cmd编码默认gbk)
len_data1 = ssh_Client.recv(4)#先接受接下来要接受数据的具体长度
len_data = struct.unpack("i",len_data1)[0]#解压后获取int型数据的具体长度
print(len_data)#输出接下来要接受的数据长度
len_res = 0#初始化接受数据总长
res=b""#初始化接受的数据(字节)
while len_res < len_data:#判断已经获取的总长是否小于数据总长,如果小于继续获取
data = ssh_Client.recv(1024)#每次接受1024字节数据
res = res + data#将数据累加到总的数据中
len_res = len_res + len(data)#将已经获取的数据长度累加
print(res.decode('gbk'))#将获取的数据解码输出
运行的效果图: