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

 

posted @ 2019-10-22 12:15  LBC不认输  阅读(1959)  评论(0编辑  收藏  举报