zoukankan      html  css  js  c++  java
  • 解决粘包现象

    简单版

    服务端

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:Mr.yang
    import socket
    import struct
    import subprocess
    
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.bind(('127.0.0.1',8080))
    phone.listen(5)
    
    print('setting...')
    while True: # 链接循环
        conn,A = phone.accept()
        while True: # 通信循环
            try:
                #1.接收数据
                data = conn.recv(8096)
                print('客户端数据:',data)
    
                #2.执行命令,拿到结果
                obj = subprocess.Popen(data.decode('utf-8'), shell=True,  # shell 可以解析前面的字符串,相当于cmd
                                       stdout=subprocess.PIPE,  # 正确管道
                                       stderr=subprocess.PIPE)  # 错误管道
    
                stdout = obj.stdout.read() #bytes类型
                stderr = obj.stderr.read()
    
                #3.将结果返回给客户端
                #第一步: 制定固定长度的报头
                total_size = len(stdout) + len(stderr)
                header = struct.pack('i',total_size)
    
                #第二步: 把报头发送给客户端
                conn.send(header)
    
                #第三步: 在发送真实的数据
                conn.send(stdout)
                conn.send(stderr) #分开写的原因,TCP会自动粘包,可以起到优化的作用
    
            except ConnectionResetError:
                break
        conn.close
    phone.close()

    客户端

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:Mr.yang
    '''
    recv不能设置数值特别大的原因:
    1.在接收文件的时候可能超过指定数值
    2.自己的操作系统的缓存不能无限大,最大也不能超过操作系统的缓存
    '''
    import socket,struct
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.connect(('127.0.0.1',8080))
    
    while True:
        #1.发命令
        cmd = input('>>:').strip()
        if not cmd:continue
        phone.send(cmd.encode('utf-8'))
    
        #2.拿到命令结果
    
        #第一步: 先收报头
        header = phone.recv(4)
    
        #第二步: 从报头中解析出对真实数据的描述信息 (数据的长度)
        tolal_size = struct.unpack('i',header)[0]
    
        #第三步: 接收真实的数据
        recv_size=0
        recv_data=b''
        while recv_size < tolal_size:
            res = phone.recv(100)
            recv_data += res
            recv_size += len(res)
    
        print(recv_data.decode('gbk'))
    phone.close()

    终极版

    服务端

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:Mr.yang
    import socket
    import struct
    import json
    import subprocess
    '''
    相对于简单版的优化
    1.报头信息少
    2.struct的i格式有限制
    '''
    
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.bind(('127.0.0.1',8080))
    phone.listen(5)
    
    print('setting...')
    while True: # 链接循环
        conn,A = phone.accept()
        while True: # 通信循环
            try:
                #1.接收数据
                data = conn.recv(8096)
                print('客户端数据:',data)
    
                #2.执行命令,拿到结果
                obj = subprocess.Popen(data.decode('utf-8'), shell=True,  # shell 可以解析前面的字符串,相当于cmd
                                       stdout=subprocess.PIPE,  # 正确管道
                                       stderr=subprocess.PIPE)  # 错误管道
    
                stdout = obj.stdout.read() #bytes类型
                stderr = obj.stderr.read()
    
                #3.将结果返回给客户端
                #第一步: 制定固定长度的报头
                header_dic={
                    'filename':'a.txt',
                    'md5':'xxdxxx',
                    'total_size':len(stdout) + len(stderr)
                }
    
                header_json=json.dumps(header_dic)
                header_bytes = header_json.encode('utf-8')
    
                #第二步:先发报头的长度
                conn.send(struct.pack('i',len(header_bytes)))
    
                #第三步:再发报头
                conn.send(header_bytes)
    
                #第四步: 在发送真实的数据
                conn.send(stdout)
                conn.send(stderr) #分开写的原因,TCP会自动粘包
    
            except ConnectionResetError:
                break
        conn.close
    phone.close()

    客户端

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:Mr.yang
    '''
    recv不能设置数值特别大的原因:
    1.在接收文件的时候可能超过指定数值
    2.自己的操作系统的缓存不能无限大,最大也不能超过操作系统的缓存
    '''
    import socket
    import struct
    import json
    
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.connect(('127.0.0.1',8080))
    
    while True:
        #1.发命令
        cmd = input('>>:').strip()
        if not cmd:continue
        phone.send(cmd.encode('utf-8'))
    
        #2.拿到命令结果
    
        #第一步: 先收报头的长度
        obj = phone.recv(4)
        header_size = struct.unpack('i',obj)[0]
    
        #第二步: 再收报头
        header_bytes = phone.recv(header_size)
    
        #第三步: 从报头中解析出对真实数据的描述信息
        header_json = header_bytes.decode('utf-8')
        header_dic = json.loads(header_json)
        print(header_dic)
        total_size = header_dic['total_size']
    
        #第四步: 接收真实的数据
        recv_size=0
        recv_data=b''
        while recv_size < total_size:
            res = phone.recv(1024)
            recv_data += res
            recv_size += len(res)
    
        print(recv_data.decode('gbk'))
    phone.close()
  • 相关阅读:
    SpringCloud入门
    SpringBoot自动配置的演示
    SpringBoot自动配置原理
    SpringBoot整合Junit、Mybatis以及Redis
    SpringBoot介绍
    面向对象编程
    Spring MVC介绍
    Queue
    springcloud项目 报错数据库未配置
    linux环境下mongoDB主从复制搭建
  • 原文地址:https://www.cnblogs.com/Mryang123/p/8719097.html
Copyright © 2011-2022 走看看