tcp套接字ssh远程命令和解决粘包

粘包问题
描述:接收到传来的数据过大时,会残留数据,下次软件会在操作系统拿到上次遗留的数据就为粘包问题


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])#读出的为元组,第一个值为报头长度

猜你喜欢

转载自blog.csdn.net/qq_35540539/article/details/80991487