zoukankan      html  css  js  c++  java
  • python 解决粘包现象(struct模块)

    一. struct模块

       该模块可以把一个类型,转换为固定长度的bytes

    import struct
    lst  = [1,2,4,3,5,]
    lst1  = [1,2,4,3,5,7,8,9,]
    a = struct.pack('i',len(lst))#将列表的长度转化为固定的4字节
    b = struct.pack('i',len(lst1))
    print(a,len(a))
    print(b,len(b))

      还可以将想要让服务端/客户端知道的信息做成字典,将字典的长度和字典打包发送 : 

      符号对应的类型以及转换之后的长度表 : 

      struct模块实现大文件传输 :

    #server端
    import socket
    import struct
    import json
    import os
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',8989))
    sk.listen()
    conn,addr = sk.accept()
    
    len_dic = struct.unpack('i',conn.recv(4))[0]#unpack解包接受的是元组类型,索引为0是字典的长度
    str_dic = conn.recv(len_dic).decode('utf-8')#根据字典的长度将字典接收为字符串类型
    dic = json.loads(str_dic)#将字符串类型的字典转换为字典(dict)
    if dic['opt'] == 'upload':
        up_load = 'D:ac\' + os.path.basename(dic['filename'])#路径拼接
        # up_load = os.path.join('D:ac\',os.path.basename(dic['filename']))
        while dic['filesize'] >0:
            read_size = conn.recv(2048)
            with open(os.path.abspath(up_load),mode='ab') as f1:
                f1.write(read_size)
                dic['filesize'] -= len(read_size)
    
    if dic['opt'] == 'download':
        down_load = 'D:ac'
        conn.send(json.dumps(os.listdir(down_load)).encode('utf-8'))
        while 1:
            s = conn.recv(2048).decode('utf-8')
            file = os.path.abspath(down_load+'/'+s)
            print(file)
            if os.path.isdir(file):
                dic1 = {'tybe':'dir'}
                len_dic1 = struct.pack('i',len(json.dumps(dic1)))
                conn.send(len_dic1 + json.dumps(dic1).encode('utf-8'))
                conn.send(json.dumps(os.listdir(file)).encode('utf-8'))
                down_load = os.path.abspath(file)
                continue
            elif os.path.isfile(file):
                dic2 = {'tybe':'fil','down_size':os.path.getsize(file)}
                len_dic2 = struct.pack('i',len(json.dumps(dic2)))
                conn.send(len_dic2 + json.dumps(dic2).encode('utf-8'))
                with open(file,mode='rb') as f:
                    down_size = os.path.getsize(file)
                    while down_size:
                        a = f.read(2048)
                        print(a)###########
                        conn.send(a)
                        down_size -= len(a)
                    break
    #client端
    import socket
    import struct
    import os
    import json
    
    sk = socket.socket()
    sk.connect(('127.0.0.1',8989))
    def upload():
        dic = {'opt':'upload','filename':None,'filesize':None}
        file = input('请输入一个想要上传的绝对路径: ')
        dic['filename'] = file
        dic['filesize'] = os.path.getsize(file)
        str_dic = json.dumps(dic)
        len_dic = struct.pack('i',len(str_dic))#自动将字典的长度转换为4个bytes类型的长度
        sk.send(len_dic + str_dic.encode('utf-8'))
    
        with open(dic['filename'],mode='rb') as f:
            while dic['filesize'] > 0:
                read_size = f.read(2048)
                sk.send(read_size)
                dic['filesize'] -= len(read_size)
    
    def download():
        dic = {'opt':'download','filename':None,'filesize':None}
        sk.send(struct.pack('i',len(json.dumps(dic)))+json.dumps(dic).encode('utf-8'))
        while 1:
            lst = json.loads(sk.recv(2048).decode('utf-8'))
            for k, v in enumerate(lst, 1):
                print(k, v)
            file = input('请根据序号输入想要下载的文件: ')
            sk.send(lst[int(file) - 1].encode('utf-8'))
            len_dic = struct.unpack('i',sk.recv(4))[0]
            str_dic = sk.recv(len_dic).decode('utf-8')
            if json.loads(str_dic)['tybe'] == 'dir':
                continue
            elif json.loads(str_dic)['tybe'] == 'fil':
                down_file = 'D:ac\'+lst[int(file) - 1]
                while json.loads(str_dic)['down_size']:
                    with open(down_file,mode='ab') as f:
                        down_ = sk.recv(2048)
                        f.write(down_)
                    json.loads(str_dic)['down_size'] -= len(down_)
    
    if __name__ =='__main__':
        lst = ['上传', '下载']
        def mai():
            for k,v in enumerate(lst,1):
                print(k,v)
            c = input('请按序号输入操作: ')
            if c == '1':
                upload()
            if c == '2':
                download()
            else:
                print('输入错误!')
        mai()
  • 相关阅读:
    anaconda的一些命令
    ffmpeg播放RTSP的一点优化
    CUDA JPEG编码
    获取CPU和内存的使用率
    《OpenCL编程指南》之 与Direct3D互操作
    OpenGL全景视频
    win32调用系统颜色对话框
    [转]RGB数据保存为BMP图片
    NVML查询显卡信息
    ffmpeg nvenc编码
  • 原文地址:https://www.cnblogs.com/dong-/p/9494734.html
Copyright © 2011-2022 走看看