• python学习笔记 day32 实现网盘上传下载功能


    1. 作业需求

    借助socket模块实现server端和client端的交互,拟实现网盘上传下载的功能:

    上传: client端发送请求,把本地的文件上传给server端,server端负责接收,然后server端的一个文件中写入client端上传的文件内容;

    下载: client端发送请求,想要下载server端某文件,server端接收请求后,给客户端发送该文件的内容(按字节读取文件内容,然后边读边发送给客户端)

    之前自己试着写了一个:

    1. 版本一(不完善--bymyself)

    # server.py
    import socket
    import pickle
    sk=socket.socket()
    sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    sk.bind(("127.0.0.1",8080))
    sk.listen()
    conn,addr=sk.accept()
    
    while True:
        head=conn.recv(1024)
        head=pickle.loads(head)
        file_name=head["filename"]
        file_size=head["filesize"]
        file_type=head["filetype"]
        file_path=head["filepath"]
        file_path=file_path+'\'+file_name+'.'+file_type
        with open(file_path, 'wb') as f:
            while file_size>0:
                content=conn.recv(1024)
                f.write(content)
                file_size-=1024
    conn.close()
    sk.close()
    View Code
    # client.py
    import socket
    import pickle
    sk=socket.socket()
    sk.connect(("127.0.0.1",8080))
    while True:
        head={"filename":"test","filesize":2048,"filetype":"txt",'filepath':"E:pyhtonworkspacepy3-praticePycharm_workspacepython_fullstackweek8day07"}
        file_size = head["filesize"]
        head=pickle.dumps(head)
        sk.send(head)
        with open("xixi","rb") as f:
            while file_size>0:
                content=f.read(1024)
                sk.send(content)
                file_size-=1024
    sk.close()
    View Code

    也可以实现上传功能(其实就是client端发送一个请求,想把本地的某一个文件上传给server端),server端可以接收这个文件,然后写入,但是有一点点问题,到文件的最后 会多些一点乱七八糟的东西,这个问题没有解决

    2. 版本二(Eva-J)

    # server.py
    import socket
    import pickle
    import struct
    sk=socket.socket()
    sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)  # 防止重启服务器发生错误
    sk.bind(("127.0.0.1",8080))  # server端绑定IP地址和端口号
    sk.listen()
    conn,addr=sk.accept()
    buffer=1024   # 读取文件的字节大小是1024
    head_len_bytes=conn.recv(4)  # 因为client端需要发送head报头的长度 int类型借助struct模板转为byets类型发送,占有固定的长度四个字节
    head_len=struct.unpack("i",head_len_bytes)[0]  # 把报头head的字节长度 借助struct模块转为的bytes 再使用struct的unpack转为int的整数,代表head报头的字节长度
    head_bytes=conn.recv(head_len)   # 字节类型,client端把报头head使用pickle的dumps成bytes类型,直接发送,server直接接收head的bytes类型
    head=pickle.loads(head_bytes)  # 把bytes类型的报头head使用pickle反序列化为原来的字典类型
    filesize=head["filesize"]  # 得到client端需要上传的文件的长度
    filename=head["filename"]+"."+head["filetype"]  # 得到client端需要上传的文件的文件名
    with open(filename,"wb") as f:  # 由于对于一些视频,音频等文件是无法按行读的,所以需要使用按照直接读,所以文件的打开方式都是rb 或者wb这种以二进制的方式进行的
        while filesize>=0:  # 当还有需要读取的字节数,就不断地按照特定长度的字节读取文件内容,然后写到server端的同名文件中
            if filesize>=buffer:  # 剩余的需要读取的文件字节数大于buffer时  每次就按照buffer字节来读
                content=conn.recv(buffer)
                f.write(content)
                filesize-=buffer
            else:
                content=conn.recv(filesize)
                f.write(content)
                filesize-=buffer
    conn.close()
    sk.close()
    # client.py
    import socket
    import pickle
    import struct
    import os
    sk=socket.socket()
    sk.connect(("127.0.0.1",8080))
    buffer=1024  # 设置文件读取的字节数
    head={"filename":"2018ASID格式要求","filetype":"docx","filepath":r"F:厦大课程-研二研二上学期2018ASID格式要求","filesize":None}  # 定制报头信息
    filepath=os.path.join(head["filepath"],(head["filename"]+"."+head["filetype"]))   # 拼接路径,其实就是所要上传的文件路径
    filesize=os.path.getsize(filepath)  # 得到所要上传的文件的字节数大小
    head["filesize"]=filesize
    head_bytes=pickle.dumps(head)   # head想要从client端传到server端,网络传输必须序列化(pickle的结果时bytes,也可以使用json 序列化的结果是str)
    head_bytes_len=len(head_bytes)  # head报头字节数的大小,因为网络传输都是字节数,必须要告诉对方需要接收多少字节才能准确接收到该报头信息
    head_bytes_len_bytes=struct.pack("i",head_bytes_len)    # 把bytes类型的head 对应的字节长度这个整数int使用struct的pack模块转化为字节,都是对应四个字节
    # server端只需要接收四个字节,就可以拿到head字节数的长度,然后再接收这个 字节数的长度 就可以完全拿到head信息
    sk.send(head_bytes_len_bytes)  # 发送head报头字节数长度对应的字节(4个 里面其实代表的是表头的长度信息)
    sk.send(head_bytes)  # 接下来发送head报头信息(字节类型的,server首先接收4个字节拿到head字节长度,接着接收这个字节长度 拿到head信息,bytes类型的,然后使用pickle反序列化成字典类型的head)
    
    with open(filepath,'rb') as f:  # 打开filepath对应的文件---本地文件,,server端把需要上传的本地文件 写在py文件下的同名文件中
                                    #  由于视频,音频等文件需要按照字节来读取文件,所以文件打开的方式是rb
        while filesize>=0:
            if filesize>=buffer:
                content=f.read(buffer)   # 读的内容也是二进制,bytes类型
                sk.send(content)
                filesize-=buffer
            else:
                content=f.read(filesize)
                sk.send(content)
                filesize-=buffer
    sk.close()

    运行结果:

     其实我只实现了上传功能,下载的原理完全一样的,直接把server 端和client端所做的工作互换就可以啦~

    而且还可以加上比较人性化的交互功能,交给用户选择上传还是下载,选择路径,文件名,这样就显得高大上啦~

    talk is cheap,show me the code
  • 相关阅读:
    单例设计模式
    程序员眼中的中国传统文化王阳明《传习录》10
    程序员眼中的中国传统文化王阳明《传习录》8
    程序员眼中的中国传统文化王阳明《传习录》16
    程序员眼中的中国传统文化王阳明《传习录》11
    程序员眼中的中国传统文化王阳明《传习录》15
    程序员眼中的中国传统文化王阳明《传习录》14
    程序员眼中的中国传统文化王阳明《传习录》9
    程序员眼中的中国传统文化王阳明《传习录》13
    程序员眼中的中国传统文化王阳明《传习录》12
  • 原文地址:https://www.cnblogs.com/xuanxuanlove/p/9750227.html
Copyright © 2020-2023  润新知