一:目标:
要实现一个客户端从服务端下载文件的功能,这个在模拟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
=======================================================================================
标签:socket,python,编程,filename,header,服务端,import,下载,size From: https://www.cnblogs.com/mq0036/p/17999436