python 解决粘包现象(struct模块)

Posted 唯你如我心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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:\\a\\b\\c\\\\\' + os.path.basename(dic[\'filename\'])#路径拼接
    # up_load = os.path.join(\'D:\\a\\b\\c\\\\\',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:\\a\\b\\c\'
    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:\\a\\b\\c\\\\\'+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()

 

以上是关于python 解决粘包现象(struct模块)的主要内容,如果未能解决你的问题,请参考以下文章

20 网络编程 粘包现象与解决方案

101 解决粘包问题

利用struct模块解决int类型粘包问题

python3全栈开发-什么是粘包粘包现象如何解决粘包

峰哥解决粘包的方式

解决粘包问题