• Python学习笔记33:用struct模块解决tcp协议传输过程中的黏包问题


    关于TCP协议容易出现的黏包问题说明可以参考:https://www.cnblogs.com/Eva-J/articles/8244551.html#_label6

    本篇内容大多数也是参考上面博客学习而来,记录一下。

    # struct模块:-->模块可以把一个类型,如数字,转成固定长度的bytes
    import struct
    ret = struct.pack('i',4096) # 'i'代表int, 就是即将要把一个数字转换成固定长度(4个字节)的bytes类型
    print(ret)
    
    num = struct.unpack('i',ret) # 输出一个元组
    print(num[0])
    

    使用pack可以把一个数字转化成一个固定长度(4个字节)的bytes类型,在recv的时候就可以只接收这4个字节,然后unpack解析出来就能知道接下来需要传输文件的大小。

    下面展示基于TCP协议,利用struct进行的视频文件的传输过程:

    server.py

    # 实现一个大文件的上传或者下载
    # 配置文件 ip地址 端口号
    import socket
    import struct
    import json
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',8080))
    sk.listen()
    buffer = 4096
    
    conn,addr = sk.accept()
    # 接收
    head_len = conn.recv(4)
    head_len = struct.unpack('i',head_len)[0]
    json_head = conn.recv(head_len).decode('utf-8')
    head = json.loads(json_head)
    filesize = head['filesize']
    with open(head['filename'],'wb') as f:
        while filesize:
            if filesize >= buffer:
                content = conn.recv(buffer)
                f.write(content)
                filesize -= buffer
            else:
                content = conn.recv(filesize)
                f.write(content)
                break
    
    conn.close()
    sk.close()
    

     

    client.py

    # 发送端
    import socket
    import os
    import json
    import struct
    
    sk = socket.socket()
    sk.connect(('127.0.0.1',8080))
    buffer = 4096
    
    # 发送文件
    head = {'filepath':r'/Users/zxx/Downloads',
            'filename':r'test.mp4',
            'filesize':None}
    
    file_path = os.path.join(head['filepath'],head['filename'])
    filesize = os.path.getsize(file_path)
    head['filesize'] = filesize
    json_head = json.dumps(head) # 字典转成了字符串
    bytes_head = json_head.encode('utf-8') # 字符串转bytes
    # print(json_head)
    # print(bytes_head)
    # 计算head的长度
    head_len = len(bytes_head)
    pack_len = struct.pack('i',head_len)
    # print(head_len,pack_len)
    
    sk.send(pack_len)  # 先发报头的长度
    sk.send(bytes_head) # 在发送bytes类型报头
    with open(file_path,'rb') as f:
        while filesize:
            if filesize >= buffer:
                content = f.read(buffer)  # 每次读出来的内容
                sk.send(content)
                filesize -= buffer
            else:
                content = f.read(filesize)
                sk.send(content)
                break
    
    sk.close()
    

    先后执行完server.py 和client.py文件后,即可把本地在下载目录下面的test.mp4文件传输到python文件工作目录中。

    结果如下:

     

  • 相关阅读:
    通信中几种复用方式的介绍
    通信的一些基本概念整理
    网易有道2017内推选择题
    腾讯2017暑期实习生编程题
    MATLAB的一些应用--最近用的比较多
    (十六)命令模式-代码实现
    (十四)观察者模式-代码实现
    (十三)备忘录模式-代码实现
    (十二)模板模式-代码实现
    (十一)享元模式-代码实现
  • 原文地址:https://www.cnblogs.com/zheng1076/p/11311084.html
Copyright © 2020-2023  润新知