python网络编程(三)实现文件下载功能

一:目标:

要实现一个客户端从服务端下载文件的功能,这个在模拟ssh远程执行命令的基础上再做修改就可以了

二:分析:

1、要规定客户端获取文件的格式:下载文件用 get 文件名, 比如要下载服务端的a.txt ,就写成 get a.txt
2、因为我目前是客户端和服务端都是在一台服务器上,我模拟的时候就把服务端的供下载的文件放到一个share的目录下,客户端下载后的文件存放在downloads的目录下,目录结构如下图:
在这里插入图片描述

3、需要知道获取文件大小的方法:

import  os

#获取文件大小
filename = 'F:\myfile\python\code\python3进阶\chepter07\模拟ssh\server.py'
filesize = os.path.getsize(filename)
print(filesize)

4、客户端程序的流程:
发送要获取的文件名(get a.txt) —> 接收报头信息,包头固定长度---->解析报头信息,获取到文件名称和文件大小—>接收服务端发来的数据,在本地创建一个文件保存接收的数据
5、服务端的流程:
接收到客户的下载命令(get a.txt )—> 解析出文件名(a.txt)—>获取文件大小—> 制作固定长度的报头,必须包含文件名和文件大小—>发送报头长度和报头数据—>读取文件内容发送给客户端。

文件下载的服务端 server.py

#--coding:utf-8--

import socket
import subprocess
import struct
import json
import os
import threading
'''
socket.AF_INET:表示是基于网络的套接字家族
socket.SOCK_STREAM:表示流式模块,基于tcp协议
'''
#服务端可以下载的文件都放到指定的一个share目录下
share_dir = r'F:\myfile\python\code\python3进阶\chepter07\文件上传下载\server\share'
#创建套接字
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.bind(('127.0.0.1',8001))
#监听
server.listen()

print('staring....')
while True:  #连接循环
    conn , addr = server.accept()
    print(addr)

    while True:   #通信循环
        try:
            #1、接收命名
            res = conn.recv(2048)   # get a.txt
            if not res:break   #适用于linux操作系统,如果客户端断开了连接
            
            #2、解析出文件名称
            cmds = res.decode().split()
            filename = cmds[1]
            #3、获取到文件大小
            file_size = os.path.getsize('%s\%s' %(share_dir,filename))

            #第一步制作固定长度的包头
            header_dic = {
                'filename':filename,  #a.txt
                'md5':'********',
                'file_size': file_size
            }
            #将字典转化成字符串
            header_json = json.dumps(header_dic)
            #在将字符串转换为bytes
            header_bytes = header_json.encode("gbk")
            #第二步,先发送包头的长度
            conn.send(struct.pack('i',len(header_bytes)))
            #第三步: 发送报头
            conn.send(header_bytes)
            #第四步:读取文件内容,发送给客户端
            with open( '%s\%s' %(share_dir,filename),'rb') as fd:
                for line in fd:     #一行一行读取
                    print(len(line))
                    conn.send(line)

        except ConnectionResetError:     #适用于windows系统,如果客户端断开连接,在windows系统就会报ConnectionResetError的错误
            break

    conn.close()
server.close()

客户端代码,client.py

import socket
import struct
import json

downloads_dir = r'F:\myfile\python\code\python3进阶\chepter07\文件上传下载\client\downloads'

client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#发起连接,服务端的ip和端口
client.connect(('127.0.0.1',8001))

while True:
    cmd = input(">>: ").strip() #  要求下载文件的格式get a.txt
    if not cmd:continue      #如果发的是空就进入下一次循环
    #1、发送命令
    client.send(cmd.encode("gbk"))

    #2、拿下载文件报头信息
    #第一步:接收报头的长度
    obj = client.recv(4)
    header_size = struct.unpack('i',obj)[0]

    #第二步:再收报头
    header_bytes = client.recv(header_size)
    #第三步:从包头中解析出真实数据的描述信息
    header_json = header_bytes.decode("gbk")
    header_dic = json.loads(header_json)
    """
     header_dic = {
                'filename':filename,  #a.txt
                'md5':'********',
                'file_size': file_size
            }
    """
    print(header_dic)
    #一次不能把内容接收完,那就循环接收,只要知道这个内容的总共大小
    file_size = header_dic['file_size']
    filename = header_dic['filename']
    #接收服务端发来的数据,并保存到本地文件中

    with open('%s/%s' %(downloads_dir,filename),'wb') as fd:
        recv_size = 0     #接收的数据大小
        while recv_size < file_size:
            data = client.recv(1024)
            fd.write(data)
            recv_size = recv_size + len(data)
            print('总大小:%s    已下载大小:%s' %(file_size,recv_size))

client.close()

开始我的downsloads目录是空的
在这里插入图片描述
运行结果:
在这里插入图片描述
在这里插入图片描述
当总大小等于已下载大小的时候就表示下载完了。
在去看downloads目录,已经有1.jpg的图片了, 这样一个简单的下载功能就实现了。
在这里插入图片描述

 

2024-01-31 15:51:05【出处】:https://blog.csdn.net/javascript_good/article/details/131453458

=======================================================================================

posted on 2024-01-31 15:52  jack_Meng  阅读(45)  评论(0编辑  收藏  举报

导航