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()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM