zoukankan      html  css  js  c++  java
  • 基于tcp协议的套接字通信:远程执行命令

    要解决粘包问题:
    TCP:流式协议
    特点:
    1、数据流没有开头也没有结果,像水流一样
    2、TCP协议有一个nagle算法,
    nagle算法会将数据量较小,并且时间间隔较短的数据合成一条数据发送,
    这么做可以减少网络IO次数,进而提升传输效率

    1.struct模块

    #1、把整型数字转成bytes类型
    #2、转成的bytes是固定长度的
    
    import struct
    import json
    
    header_dic = {
        'total_size': 31222222222121,
        'md5': '123svsaef123sdfasdf',
        'filename': 'a.txt'
    }
    
    #序列化:内存中的数据结构----》转成一种中间格式(字符串)----》存到文件中
    header_json=json.dumps(header_dic)
    print(header_json,type(header_json))
    
    #编码:编码后的结果为bytes类型
    header_bytes=header_json.encode('utf-8')
    header_size=len(header_bytes)
    print(header_size)  # 81
    
    #打包
    obj=struct.pack('i',header_size)
    print(obj,len(obj))  # b'Qx00x00x00' 4
    
    #解包
    obj2=struct.unpack('i',obj)
    print(obj2)  # (81,)
    View Code

    打印结果:

    {"total_size": 31222222222121, "md5": "123svsaef123sdfasdf", "filename": "a.txt"} <class 'str'>
    81
    b'Qx00x00x00' 4
    (81,)
    result

    2.通讯整个流程:

    '''
    流程:
        服务端:制作报头,把报头信息丢到报头字典里,字典序列化得到json字符串,encode得到bytes
              ---->发报头长度(struct.pack打成4个bytes)--->发送报头---->发真实数据
              
        客户端:先接收4个bytes:struct.unpack解包报头长度--->接收报头-->
                 解析报头:decode得到字符串,反序列化得到报头--->根据报头内的信息,收取真实的数据
    
    '''

    3.具体代码如下:

    服务端:

    from socket import *
    import subprocess
    import struct
    import json
    
    server=socket(AF_INET,SOCK_STREAM)
    server.bind(('127.0.0.1',8080))
    server.listen(5)               #半连接池:限制的是请求数,而不是连接数
    
    while True:
        conn,client_addr=server.accept() #(连接对象,客户端的ip和端口)  conn:tcp三次握手的一个产物,可以用来收发消息
        print(client_addr)     #此处client_addr的作用是可以知道哪个客户端建的链接,和通讯无关
        while True:
            try:
                cmd=conn.recv(1024)   #cmd为bytes类型,
                obj=subprocess.Popen(cmd.decode('utf-8'),   
                                     shell=True,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE
                                     )
                stdout=obj.stdout.read()  #拿到系统执行的结果(subprocess执行的是window系统命令,解码需要gbk)
                stderr=obj.stderr.read()
    
                # 1、制作报头
                header_dic={
                    'total_size':len(stdout) + len(stderr),
                    'md5':'123svsaef123sdfasdf',
                    'filename':'a.txt'
                }
                header_json = json.dumps(header_dic)         #json序列化报头
                header_bytes = header_json.encode('utf-8')   #字符串类型---->bytes类型,发送
    
                # 2、先发送报头的长度
                header_size=len(header_bytes)
                conn.send(struct.pack('i',header_size))
    
                # 3、发送报头
                conn.send(header_bytes)
    
                # 4、发送真实的数据
                conn.send(stdout)     #send只能发bytes类型
                conn.send(stderr)
            except ConnectionResetError:
                break
        conn.close()
    server.close()
    
    

    客户端:

    from socket import *
    import struct
    import json           
    
    client=socket(AF_INET,SOCK_STREAM)
    client.connect(('127.0.0.1',8080))
    # print(client)
    
    while True:
        cmd=input('>>>: ').strip()
        if not cmd:continue
        client.send(cmd.encode('utf-8'))     #把命令结果发给服务器
        #1、先收报头的长度根据报头内的信息,收取真实的数据
        header_size=struct.unpack('i',client.recv(4))[0]    #bytes类型,想拿到报头长度要对bytes进行解出
    
        #2、接收报头
        header_bytes=client.recv(header_size)   #对应服务端的发送报头
    
        #3、解析报头
        header_json=header_bytes.decode('utf-8')    #bytes类型---->字符串类型
        header_dic=json.loads(header_json)         #反序列化拿到报头
        print(header_dic)
    
        total_size=header_dic[ 'total_size']
        # print(total_size) #1025
        #4、接收数据
    
        recv_size=0
        res=b''
        while recv_size < total_size:
            recv_data=client.recv(1024)
            res+=recv_data
            recv_size+=len(recv_data)
    
        print(res.decode('gbk'))
    client.close()
  • 相关阅读:
    Zookeeper 源码(七)请求处理
    Zookeeper 源码(六)Leader-Follower-Observer
    Zookeeper 源码(五)Leader 选举
    Zookeeper 源码(四)Zookeeper 服务端源码
    Zookeeper 源码(三)Zookeeper 客户端源码
    Zookeeper 源码(二)序列化组件 Jute
    Zookeeper 目录
    分布式理论系列(三)ZAB 协议
    分布式理论系列(二)一致性算法:2PC 到 3PC 到 Paxos 到 Raft 到 Zab
    分布式理论系列(一)从 ACID 到 CAP 到 BASE
  • 原文地址:https://www.cnblogs.com/zh-xiaoyuan/p/11783058.html
Copyright © 2011-2022 走看看