粘包问题
描述:接收到传来的数据过大时,会残留数据,下次软件会在操作系统拿到上次遗留的数据就为粘包问题
tcp协议的nagle算法会将数据量较小,并且发送时间间隔较短的多个数据合在一起发
解决办法
自定义报头
服务端
from socket import * #优化代码
import subprocess
import struct #pack将整型的数字转换成固定长度的bytes类型 unpick则相反
import json
server=socket(AF_INET,SOCK_STREAM) #建立服务端对象,用tcp
server.bind(('127.0.0.1',8080)) #绑定端口
server.listen(5) #半连接池同时请求数
while True:
conn,client_addr=server.accept() #建立与客户端链接
print('新的客户端',client_addr)
while True:
try:
cmd=conn.recv(1024) #cmd=b'dir'为bytes类型
if len(cmd) == 0:break #出现客户端断开时解决方案
# 运行系统命令
obj=subprocess.Popen(cmd.decode('utf-8'),#要为字符串类型
shell=True,
stderr=subprocess.PIPE,#错误结果
stdout=subprocess.PIPE#正确结果
)
stdout=obj.stdout.read()#得到的结果为bytes,windows运行为gbk
stderr=obj.stderr.read()
#先制作报头
header_dic={
'filename':'a.txt',
'total_size':len(stdout) + len(stderr),#数据的总大小
'hash':'xasf123213123'
}
header_json=json.dumps(header_dic) #得到的结果为字符串类型
header_bytes=header_json.encode('utf-8')#转换为bytes发送
#1、先把报头的长度len(header_bytes)打包成4个bytes,然后发送
conn.send(struct.pack('i',len(header_bytes))) #报头长度固定,用i格式
#2、发送报头
conn.send(header_bytes)
#3、再发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break
conn.close()
客户端
from socket import *
import struct
import json
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
cmd=input('>>: ').strip()
if len(cmd) == 0:continue
client.send(cmd.encode('utf-8'))
#1、先收4个字节,该4个字节中包含报头的长度
header_len=struct.unpack('i',client.recv(4))[0] #uupack的结果为只有一个值的元组,取第一个值,为传来数据的bytes长度。
# 将收到bytes类型解析成元组
#2、再接收报头
header_bytes=client.recv(header_len) #收到序列化的bytes数据
#从报头中解析出想要的内容
header_json=header_bytes.decode('utf-8')#将bytes类型转换成字符串
header_dic=json.loads(header_json) #反序列化出存取的字典
print(header_dic)
total_size=header_dic['total_size'] #拿到服务端发过来真实的数据bytes的总长度
#3、再收真实的数据
recv_size=0 #定义变量,接受字节长度的初始值
res=b'' #接收到的数据初始值
while recv_size < total_size : #小于所有的数据长度继续循环
data=client.recv(1024) #1024变成更大跟缓存有关,且不合理,最大为8096
res+=data
recv_size+=len(data) #date为实际接收到的数据
print(res.decode('gbk')) #通过解码打印数据
struct 模块的运用
import struct
import json
header_dic={
'filename':'a.txt',
'total_size':222222222222222222222222222222222222222222222222222222222222222222223,
'hash':'asdf123123x123213x'
}
header_json=json.dumps(header_dic)
header_bytes=header_json.encode('utf-8') #把str类型转成bytes类型
obj=struct.pack('i',len(header_bytes)) #固定报头长度
print(obj,len(obj))
#
# res=struct.unpack('i',header)
# print(res[0])#读出的为元组,第一个值为报头长度
描述:接收到传来的数据过大时,会残留数据,下次软件会在操作系统拿到上次遗留的数据就为粘包问题
tcp协议的nagle算法会将数据量较小,并且发送时间间隔较短的多个数据合在一起发
解决办法
自定义报头
服务端
from socket import * #优化代码
import subprocess
import struct #pack将整型的数字转换成固定长度的bytes类型 unpick则相反
import json
server=socket(AF_INET,SOCK_STREAM) #建立服务端对象,用tcp
server.bind(('127.0.0.1',8080)) #绑定端口
server.listen(5) #半连接池同时请求数
while True:
conn,client_addr=server.accept() #建立与客户端链接
print('新的客户端',client_addr)
while True:
try:
cmd=conn.recv(1024) #cmd=b'dir'为bytes类型
if len(cmd) == 0:break #出现客户端断开时解决方案
# 运行系统命令
obj=subprocess.Popen(cmd.decode('utf-8'),#要为字符串类型
shell=True,
stderr=subprocess.PIPE,#错误结果
stdout=subprocess.PIPE#正确结果
)
stdout=obj.stdout.read()#得到的结果为bytes,windows运行为gbk
stderr=obj.stderr.read()
#先制作报头
header_dic={
'filename':'a.txt',
'total_size':len(stdout) + len(stderr),#数据的总大小
'hash':'xasf123213123'
}
header_json=json.dumps(header_dic) #得到的结果为字符串类型
header_bytes=header_json.encode('utf-8')#转换为bytes发送
#1、先把报头的长度len(header_bytes)打包成4个bytes,然后发送
conn.send(struct.pack('i',len(header_bytes))) #报头长度固定,用i格式
#2、发送报头
conn.send(header_bytes)
#3、再发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break
conn.close()
客户端
from socket import *
import struct
import json
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
cmd=input('>>: ').strip()
if len(cmd) == 0:continue
client.send(cmd.encode('utf-8'))
#1、先收4个字节,该4个字节中包含报头的长度
header_len=struct.unpack('i',client.recv(4))[0] #uupack的结果为只有一个值的元组,取第一个值,为传来数据的bytes长度。
# 将收到bytes类型解析成元组
#2、再接收报头
header_bytes=client.recv(header_len) #收到序列化的bytes数据
#从报头中解析出想要的内容
header_json=header_bytes.decode('utf-8')#将bytes类型转换成字符串
header_dic=json.loads(header_json) #反序列化出存取的字典
print(header_dic)
total_size=header_dic['total_size'] #拿到服务端发过来真实的数据bytes的总长度
#3、再收真实的数据
recv_size=0 #定义变量,接受字节长度的初始值
res=b'' #接收到的数据初始值
while recv_size < total_size : #小于所有的数据长度继续循环
data=client.recv(1024) #1024变成更大跟缓存有关,且不合理,最大为8096
res+=data
recv_size+=len(data) #date为实际接收到的数据
print(res.decode('gbk')) #通过解码打印数据
struct 模块的运用
import struct
import json
header_dic={
'filename':'a.txt',
'total_size':222222222222222222222222222222222222222222222222222222222222222222223,
'hash':'asdf123123x123213x'
}
header_json=json.dumps(header_dic)
header_bytes=header_json.encode('utf-8') #把str类型转成bytes类型
obj=struct.pack('i',len(header_bytes)) #固定报头长度
print(obj,len(obj))
#
# res=struct.unpack('i',header)
# print(res[0])#读出的为元组,第一个值为报头长度