zoukankan      html  css  js  c++  java
  • 粘包,文件传输

    TCP的粘包问题
    TCP 流式协议
    基于数据流的协议


    接收方产生粘包问题
    1. 接收方不清楚数据有多长 只接受了数据的一部分
    2. 接收方多读了数据
    发送方产生的粘包问题
    3.操作系统没有及时发送前一次的数据 导致两次数据黏在了一起

    TCP nigle优化机制
    如果多次发送数据的数据量小并且时间间隔短:会把这一堆数据聚合在一起一次性发送
    目的是为了降低网络传输次数


    UDP基于数据报的传输协议 不会发生粘包问题 因为数据是以报文的形式存在
    每次发送都是以数据报的形式 对方接收的也是一个数据报

    粘包产生的根本原因是接收方不清楚数据的长度
    解决粘包的核心思路:就是先通知接收方 要发送的数据的长度
    再发送真实数据



    问题在于 数据长度 也是不确定的
    对方也不清楚 长度信息 到底几个字节

    想办法将长度信息所占的字节数固定下来

    导入struct模块
    q为长整型 8位字节
    l为整型 4位字节


    import struct

    # q表示longlong类型 占八个字节
    b = struct.pack("q",10000000000000)
    print(b)
    print(len(b))

    # 解包 把二进制还原为整型
    # 返回的是一个元组 第0 个表示原始数据
    num = struct.unpack("q",b)

    print(num)


    import socket,struct
    
    c=socket.socket()
    c.connect(('127.0.0.1',8808))
    
    data='hello 我林霄 see you tomorrow'.encode('utf-8')
    #给接收方发送数据的长度
    length=len(data)
    #将整型的长度 转为固定长度的字节
    len_data=struct.pack('q',length)
    #发送长度信息
    c.send(len_data)
    #发送真实数据
    c.send(data)
    import socket,struct
    s=socket.socket()
    s.bind(('127.0.0.1',8808))
    s.listen()
    c,addr=s.accept()
    # 先接收长度
    # 有可能 长度信息和真实数据也黏在一起 无法取出长度信息
    
    # 解决方案是  把长度信息 转换为一个固定字节数的二进制数据
    # 1      4个字节的bytes
    # 2      4个字节的bytes
    # 20000  4个字节的bytes
    # 接收数据的长度信息
    length=struct.unpack('q',c.recv(8))[0]
    print('长度为:%s'%length)
    data=c.recv(length).decode('utf-8')
    print(data)

     文件传输:

    import hashlib
    def get_MD5(file_name):
        # 用于计算某个文件的MD5值
        with open(file_name,"rb") as f:
            m = hashlib.md5()
            while True:
                data = f.read(1024)
                if not data:
                    break
                m.update(f.read())
            return m.hexdigest()
    
    if __name__ == '__main__':
        print(get_MD5(r"1.网络协议回顾.mp4"))
    tool
    """
    发送文件
    1.连接服务器
    2.打开文件
    3.读取文件的长度信息并发送给服务器
    4.读取文件内容
    5.发送文件数据
    
    
    不仅要上传文件
    还要传一些文件的相关信息
    
    文件名
    MD5
    
    """
    
    import socket
    import struct
    import json
    import os
    import tool
    c = socket.socket()
    c.connect(("127.0.0.1",1688))
    
    path = r"D:python6期视频1.网络协议回顾.mp4"
    
    # 待发送的两段数据
    file_name = "1.网络协议回顾.mp4"
    MD5 = "ASAASAS121212"
    # 发送的文件长度
    file_size = os.path.getsize(path)
    
    #将数据组装为字典
    info_dic = {"file_name":file_name,"MD5":tool.get_MD5(path),"file_size":file_size}
    # 将字典转为json的字符串
    json_str = json.dumps(info_dic)
    
    # 获取文件信息的长度
    json_len = struct.pack("q",len(json_str.encode("utf-8")))
    
    # 发送长度
    c.send(json_len)
    
    # 发送文件信息
    c.send(json_str.encode("utf-8"))
    
    
    # 循环发送文件数据
    with open(path,"rb") as f:
        while True:
            data = f.read(1024)
            if not data:
                break
            c.send(data)
    发送文件
    import socket
    import struct
    import json
    """
    接收文件
    1.建立连接
    2.获取文件的长度信息
    3.接收文件数据写入文件中
    
    """
    import os
    import tool
    s = socket.socket()
    s.bind(("127.0.0.1",1688))
    s.listen()
    c,addr = s.accept()
    
    # 先接受文件信息的字典
    length = struct.unpack("q",c.recv(8))[0]
    # 文件信息
    info = c.recv(length).decode("utf-8")
    
    # 反序列化
    info_dic = json.loads(info)
    print(info_dic)
    
    
    print("文件总长:%s" % info_dic["file_size"])
    
    #已经接收的长度
    curren_size = 0
    file = open(info_dic["file_name"],"wb")
    # 接收真实数据  # 建议循环接收 以保证缓冲区不会超出内存
    while curren_size < info_dic["file_size"]:
        data = c.recv(1024)
        if not data:
            print("对方下线了")
            break
        # 写入数据
        file.write(data)
        curren_size += len(data) # 记录已经接收的长度
        # print("当前已经接收:%s" % curren_size)
    
    file.close()
    print("接收完毕!")
    
    if info_dic["MD5"] == tool.get_MD5(info_dic["file_name"]):
        print("MD5校验成功!")
    else:
        print("MD5校验失败! 你下载的是盗版的 请到官网下载 www.oldboyedu.com!")
    接收文件
  • 相关阅读:
    12345679*81=?
    怪异,漂亮的几个数学恒等式(转)
    道路着色问题
    一组数学算式的欣赏(转)
    数学中奇妙的“金蝉脱壳”(转)
    数学中的分分合合(转)
    四方定理和卡布列克常数(转)
    简单的题目 有趣的现象
    Android学习笔记 第三节 基本控件学习
    Android学习笔记 第二节 HelloWorld程序
  • 原文地址:https://www.cnblogs.com/gengbinjia/p/10457222.html
Copyright © 2011-2022 走看看