zoukankan      html  css  js  c++  java
  • 粘包问题解决

     send和recv

    一个send可以对应多个recv

    # 服务端:
    import socket
    
    server = socket.socket()
    server.bind(('127.0.0.1',9045))
    server.listen(5)
    conn,addr = server.accept()
    print(conn.recv(10))
    print(conn.recv(10))
    print(conn.recv(10))
    print(conn.recv(10))
    print(conn.recv(10))
    print(conn.recv(10))        #在数据取完了之后再recv的数据是空
    conn.close()
    server.close()
    
    # 客户端:
    import socket
    
    client = socket.socket()
    client.connect(('127.0.0.1',9045))
    client.send(b'sfaugsdaifjaskdbvziwadF')
    client.close()
    
    # 结果:
    b'sfaugsdaif'
    b'jaskdbvziw'
    b'adF'
    b''
    b''
    b''

    一个recv可以对应多个send

    # 服务端:
    import socket
    
    server = socket.socket()
    server.bind(('127.0.0.1',9045))
    server.listen(5)
    conn,addr = server.accept()
    print(conn.recv(1024))     # send多次发送少量数据,一次打印出来
    conn.close()
    server.close()
    
    # 客户端:
    import socket
    
    client = socket.socket()
    client.connect(('127.0.0.1',9045))
    client.send(b'sfa')
    client.send(b'as')
    client.send(b'iwa')
    client.send(b'tf')
    client.close()
    
    
    # 结果:
    b'sfaasiwatf'

    总结:

    1.send和recv不是必须要一一对应的

    2.只要通道不关闭的状态下,而且客户端不给服务端发数据,服务端就会一直处于recv状态

    粘包问题解决

     low版

    # 服务端:
    import socket
    import subprocess
    import struct
    
    server = socket.socket()
    server.bind(('127.0.0.1',8848))
    server.listen(5)
    while 1:
        conn,addr = server.accept()
        while 1:
            try:
                cmd = conn.recv(1024).decode('utf-8')
                obj = subprocess.Popen(cmd,
                                       shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE)
                right_msg = obj.stdout.read()
                error_msg = obj.stderr.read()
                # 获取数据总长度
                total_data_size = len(right_msg + error_msg)
                print(total_data_size)
                # 将总长度转化成固定长度的字节
                total_data_size_bytes = struct.pack('i',total_data_size)    #无论总长度是几位,转化后长度都是4
                # 发送总长度字节和总数据
                conn.send(total_data_size_bytes)
                conn.send(right_msg + error_msg)
            except Exception:
                break
        conn.close()
    server.close()
    
    
    # 客户端:
    import socket
    import struct
    
    client = socket.socket()
    client.connect(('127.0.0.1',8848))
    while 1:
        cmd = input('>>>').strip()
        client.send(cmd.encode('utf-8'))
        # 接收固定长度
        head_bytes = client.recv(4)
        # 将head_bytes还原成int类型
        total_data_len = struct.unpack('i',head_bytes)[0]   # unpack转化之后是元祖的形式,用下标将int取出来
        print('长度:',total_data_len)
        # 循环接收所有的数据
        total_data = b''
        while len(total_data) < total_data_len:
            data = client.recv(1024)
            total_data += data
        print(total_data.decode('gbk'))
    client.close()

    缺点:

    1.数据如果过大,struct就会报错

    2.如果上传下载文件(视频,音频,文件等),需要自定义报头(文件名,路径,大小,md5值等)

    高端版

    # 服务端:
    import socket
    import subprocess
    import struct
    import json
    
    server = socket.socket()
    server.bind(('127.0.0.1',8888))
    server.listen(5)
    
    while 1:
        conn, addr = server.accept()
        while 1:
            try:
                cmd = conn.recv(1024).decode('utf-8')
                obj = subprocess.Popen(
                    cmd,
                    shell=True,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                )
                right_msg = obj.stdout.read()
                error_msg = obj.stderr.read()
    
                # 1, 自定制报头
                head_dic = {
                    'file_name': 'xx.mp4',
                    'file_path': r'C:UsersoldboyPycharmProjectss19day304 recv的问题server.py',
                    'file_size': len(error_msg + right_msg),
                }
                # 2,将head_dic利用json转化成json字符串
                head_dic_json = json.dumps(head_dic)
    
                # 3,将json字符串转化成bytes
                head_dic_json_bytes = head_dic_json.encode('utf-8')
    
                # 4,利用strcut将head_dic_json_bytes转化成固定的4个字节
                head_dic_json_bytes_struct = struct.pack('i',len(head_dic_json_bytes))  # 内容bytes长度固定的4个字节
                # print(head_dic_json_bytes_struct,len(head_dic_json_bytes_struct))
    
                # 5,发送固定4个字节
                conn.send(head_dic_json_bytes_struct)
    
                # 6,发送bytes类型的字典的报头数据head_dic_json_bytes
                conn.send(head_dic_json_bytes)
    
                # 7, 发送总数据
                conn.send(right_msg + error_msg)
            except Exception:
                break
        conn.close()
    server.close()
    
    
    # 客户端:
    import socket
    import struct
    import json
    
    client = socket.socket()
    client.connect(('127.0.0.1',8888))
    while 1 :
        cmd = input('>>>').strip()
        client.send(cmd.encode('utf-8'))
    
        # 1,接受4个字节
        head_dic_json_bytes_size_strcut = client.recv(4)
    
        # 2,利用struct反解出head_dic_json_bytes的具体size
        head_dic_json_bytes_size = struct.unpack('i',head_dic_json_bytes_size_strcut)[0]
    
        # 3,接受head_dic_json_bytes具体数据
        head_dic_json_bytes = client.recv(head_dic_json_bytes_size)
    
        # 4,将head_dic_json_bytes转化成json的格式
        head_dic_json = head_dic_json_bytes.decode('utf-8')
    
        # 5, head_dic_json 反序列化成字典类型
        head_dic = json.loads(head_dic_json)
    
        # 6 循环接收数据
        total_data = b''
        while len(total_data) < head_dic['file_size']:
            total_data += client.recv(1024)
        print(total_data.decode('gbk'))
    client.close()
  • 相关阅读:
    Django之model补充:一对多、跨表操作
    Ajax
    Django之model详解
    Django补充之模板语言
    Django基础篇
    web框架
    linux下命令学习
    make: Warning: File `Makefile' has modification time 17 s in the future
    linux下复制文件报cp: omitting directory `XXX'
    关于控制台程序下使用mfc库中的函数时断言
  • 原文地址:https://www.cnblogs.com/sandy-123/p/10420704.html
Copyright © 2011-2022 走看看