zoukankan      html  css  js  c++  java
  • 远程执行命令的C/S架构软件,粘包问题解决

    远程执行命令C/S架构的软件
    什么是套接字:
    套接字位于应用层与传输层之间,将传输层以下的协议都封装成接口
    对于应用层来说只需要调节用套接字的接口,写出的程序自然是遵循tcp或者ubp等协议
    C/S
    server必须遵循:
    1、稳定运行,对外一直提供服务
    2、服务必须绑定ip和端口

    TCP协议又称为流式协议,是像水一样多个数据一起流动,操作系统会将短时间,小数量的所要传的数据,会一次性打包一起传.而其过程形

    成的情况称为粘包,可以用报头方式对数据进行准确划分

    通过模块subprocess可以达成用户端控制服务器进行远程的命令控制,多个命令可以通过分号进行区分隔开多个命令.

    subprocess执行好自动是bytes二进制模式,默认格式为"gbk"格式,用"gbk"进行转换

    当发送的内容大于设置的最大字节数时,后面发送的指令回馈的内容在操作系统内存中会排在最后面,显示的时之前还未从操作系统中,
    拿完的数据内容,可以通过struct模块与循环,解决此问题,在服务器与用户端传输中,服务器将反馈的数据用struct模块将数据的长度
    进行数字转二进制类型
    (struct.pack("i",内容))长度固定时4,作为报头传输给用户端,
    用户端先读取长度为4的报头,再借用struct模块,将数据解包,解包后的内容是元组显示,然后利用索引取值.
    header = client.recv(4)
    total_size = struct.unpack("i",header)[0]
    然后再循环接收真实数据,通过"gbk"解码将内容显示出.(其中有个BUG,就是内容过长的时候用struct模块来转化二进制会报错,所以需
    要额外处理)

    通用的报头内容为:
    header_dic= {
    "filename":"a.txt", #文件名
    "total_size":len(stdout)+len(stderr)#真实数据长度
    "hash":"xsdf3241" #hash值
    }

    字典内容的报头:字典用json模块将内容成为字符串可是,再用encode转为二进制,再用len计算出报头长度,最后用struct将藏毒转为二进
    制发送给用户
    用户接收后以反向推算获得想要的内容

    from socket import *
    import subprocess
    import json
    import struct
    
    client = socket()
    client.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    client.bind(("127.0.0.1",8080))
    client.listen(5)
    while True:
        conn,addr = client.accept()
        print("用户来访",addr)
        while True:
            try:
                cmd=conn.recv(1024)
                if len(cmd) == 0:break
                obj=subprocess.Popen(cmd.decode("utf-8"),
                                     shell=True,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE
                                     )
                stdout = obj.stdout.read()
                stderr = obj.stderr.read()
    
                #制作字典报头
                header_dic={
                    "filename":"a.txt",
                    "total_size":len(stdout)+len(stderr),
                    "hash":"xsdf3241"
                }
    
                #json模块转化为字符串格式
                header_json=json.dumps(header_dic)
                #将json转为二进制bytes
                header_bytes=header_json.encode("utf-8")
                #将二进制计算长度
                header_len=len(header_bytes)
                #再用struct模块将长度转为二进制
                header_struct=struct.pack("i",header_len)
                #发送给客户端
                conn.send(header_struct)
                conn.send(header_bytes)
                conn.send(stdout)
                conn.send(stderr)
            except ConnectionResetError:
                break
        conn.close()
    client.close()
    服务器
    import struct
    from socket import *
    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"))
        #先接收4个字节长度的二进制
        header_struct=client.recv(4)
        #将4个字节内的字节长度取出
        header_len = struct.unpack("i",header_struct)[0]
        #接收报头
        header_bytes=client.recv(header_len)
        #再将header_bytes二进制内容解码,成为json文件
        header_json=header_bytes.decode('utf-8')
        #再将解码后的字符串进行json模块读取
        header_dic=json.loads(header_json)
        #将字典内的需要内容真实数据长度取出
        total_size=header_dic["total_size"]
    
        #接收真实数据
        recv_size=0
        res=b""
        while recv_size<total_size:
            data=client.recv(1024)
            res+=data
            recv_size+=len(data)
        print(res.decode("gbk"))
    client.close()
    客户端
  • 相关阅读:
    vuejs 2 生命周期钩子函数
    js 原型链
    两段代码说明 闭包,变量提升 问题
    node 模块全局位置
    git 提交代码
    mongoose 由一个版本引起的问题
    box-shadow 让div 立体起来
    flexbox 学习笔记 参考阮一峰老师的blog
    Linq的分页与组合查询的配合使用
    发送邮件和数据导出
  • 原文地址:https://www.cnblogs.com/yf18767106368/p/9285342.html
Copyright © 2011-2022 走看看