zoukankan      html  css  js  c++  java
  • socket大文件传输(解决粘包)

    解决粘包
    模块struct
          struct.pack(type,num)
              type:是num的类型
              num :是一个数字
              r = struct.pack 把一个数字打包成一个四字节的bytes
          struct.unpack(type,r)
              功能:解包,把r解成原数字,结果是一个元组,原数字在元组的下标位0的位置
    #解决粘包:原理是在服务器接收到字典长度后,根据字典长度去recv字典中的内容,就不会造成recv最后一次接收完后剩下的空间留给部分文件内容所造成字典内容和文件内容黏在一起
              
    #实现文件的上传功能  
    #client层
    import socket
    import json
    import struct
    import os
    
    sk=socket.socket()
    sk.connect(("10.70.2.143",8080))
    option={"1":"upload","2":"download"}
    for index,value in option.items():
        print(index,value)
    num=input("请输入您的选择")
    if num=="1":
        dic={"opt":option.get(num),"filename":None,"filesize":None}
        file_path=input("请输入所需要上传的文件的绝对路径")
        filename=os.path.basename(file_path)
        filesize=os.path.getsize(file_path)
        dic["filename"]=filename
        dic["filesize"]=filesize
        #将字典转为字符串类型
        str_dic=json.dumps(dic)
        #获取字典的长度,为了解决粘包
        len_dic=len(str_dic)
        #解决粘包:原理是在服务器接收到字典长度后,根据字典长度去recv字典中的内容,就不会造成recv最后一次接收完后剩下的空间留给部分文件内容所造成字典内容和文件内容黏在一起
        #用一个4bytes的数据表示字典的长度
        #服务器接收的时候先接收recv(4)个字节长度就可以得到字典的长度
        b_len_dic=struct.pack('i',len_dic)  #i是原字典长度的数据类型,第二个参数是需要转化的那个字典长度本身
        #将bytes类型的字典长度和字典内容进行拼接并且发送
        sk.send(b_len_dic+str_dic.encode("utf-8"))  #此时字典内容是bytes类型所以可以进行bytes的拼接
    
        #文件的上传
        with open(file_path,"rb") as f:
            #根据文件大小进行文件的上传
            while filesize:
                content=f.read(1024)
                sk.send(content)
                filesize-=len(content)
    else:
        pass
    sk.close()
    
    
    
    
    
    
    #server层
    import socket
    import json
    import struct
    
    
    sk=socket.socket()
    sk.bind(("10.70.2.143",8080))
    sk.listen()
    conn,addr=sk.accept()
    #先接收从客户端传过来的四个字节长度的字典长度
    b_len_dic=conn.recv(4)
    #将字节长度的字典长度进行解包成整型的字典长度
    len_dic=struct.unpack('i',b_len_dic)[0] #因为字典长度传过来的是一个元组的第0个下标元素
    #根据字典长度去接收字典的内容
    #下次进行文件传输的时候就不会造成粘包现象
    str_dic=conn.recv(len_dic).decode("utf-8")
    #将字符串的字典反序列化成字典
    dic=json.loads(str_dic)
    if dic["opt"]=="upload":
        #为了防止文件同名,使用字符串拼接文件名进行区分
        filename="1"+dic["filename"]
        #接收从客户端传过来的文件
        with open(filename,"ab") as f:
            #根据文件大小接收数据
            while dic["filesize"]:
                content=conn.recv(1024)
                f.write(content)
                #字典中文件大小减去已接受的文件大小
                dic["filesize"]-=len(content)
    elif dic["opt"]=="download":
        pass
    conn.close()
    sk.close()
  • 相关阅读:
    第四章 虚拟机性能监控与故障处理工具
    C++_异常5-异常规范和栈解退
    C++_异常4-将对象用作异常类型
    C++_异常3-异常机制throw try catch
    C++_异常2-返回错误码
    C++_异常1-调用abort()
    C++_类继承7-类设计回顾
    C++_类继承6-继承和动态内存分配
    C++_类继承5-抽象基类
    C++_类继承4-访问控制protected
  • 原文地址:https://www.cnblogs.com/god-for-speed/p/11719047.html
Copyright © 2011-2022 走看看