您现在的位置是:首页 > 文章详情

python -服务器与客户端断电续传程序详细介绍

日期:2021-06-01点击:272

6.28自我总结

客户端与服务器之间文件传输断电续传

`通过判断文件大小,以及文件在读取中的指针位置的调整来解决断电续传问题'

1.程序目录

E:/断电续传 |___bil | |___common.py #公共方法 |___conf | |___logger_setting.py #存日志的格式 | |___setting.py #一些常量 |___db | |___client #程序端存文件的文件夹 | |___logger #存日志的文件夹 | |___sever #服务端存文件的文件夹 |___requirements.txt #方便别人导入库 |___test.py #程序写的时候有些东西需要单独拿出来试试 |___客户端.py |___服务端.py 

2.程序思路

  • 第一步:我们什么都不懂,但是有几个模块肯定会有一个是conf中的setting来存一些常量

  • 第二步:我们也需要一个db文件来存内容

  • 第三步:我们要也有个bil存一些可能会出现的公共方法,可以精简代码

  • 第四部:生成requirements.txt文件,方便其他人用模板时候可以一键安装需要的模板

    ​ requirements的自动生成方式cmd中输入pip freeze > requirements.txt

    ​ 然后清空下内容,如果有用到第三方库什么的可以写进去方便别人安装

  • 第五步:根据功能然后进行添加,有些常量丢setting里面,公共方法丢common里面去

3.程序内容

1.conf

1.setting.py

import os #项目文件夹路径 PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #文件存放夹路径 DB_PATH = os.path.join(PATH,'db') #客户端存放路径 CLIENT_PATH = os.path.join(PATH,'db','client') #服务端存放路径 SEVER_PATH = os.path.join(PATH,'db','sever') #日志存放路径 LOGGER_PATH = os.path.join(PATH,'db','logger') #服务端PROT IP = '127.0.0.1' #服务端端口 PROT = 8000 

2.logger_setting.py

import os import logging.config #函数上面部分要根据你程序进行修改 # 定义三种日志输出格式 开始 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ '[%(levelname)s][%(message)s]' # 其中name为getLogger()指定的名字;lineno为调用日志输出函数的语句所在的代码行 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # 定义日志输出格式 结束 # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, }, 'filters': {}, # filter可以不定义 'handlers': { # 打印到终端的日志 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'simple' }, # 打印到文件的日志,收集info及以上的日志 'default': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', 'filename': 1, # 日志文件 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M (*****) 'backupCount': 5, 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, }, 'loggers': { # logging.getLogger(__name__)拿到的logger配置。如果''设置为固定值logger1,则下次导入必须设置成logging.getLogger('logger1') '': { # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'handlers': ['default', 'console'], 'level': 'DEBUG', 'propagate': False, # 向上(更高level的logger)传递 }, }, } 

2.bil

common.py

from conf.setting import * import struct from conf.logger_setting import * import logging.config import datetime #获取文件路径下的子文件的目录列表 def get_flie_lis(path): '''获取文件路径下的子文件的目录列表''' if os.path.exists(path):return os.listdir(path) return False #获取客文件的大小 def get_flie_size(filename,filefrom): '''获取客文件的大小''' path = os.path.join(DB_PATH,filefrom,filename) if os.path.exists(path): return os.path.getsize(path) return 0 #内容大小进行压缩,int格式内容进行压缩成4个字符 def zip_data(data:int): '''内容大小进行压缩,int格式内容进行压缩成4个字符''' return struct.pack('i',data) #解压缩 def uncompress(zipflie): '''解压缩压缩文件''' return struct.unpack('i',zipflie)[0] #根据文件路径读取文件大小以及文件的内容变成个生成器 def get_file_size_data(path): '''根据文件路径读取文件大小以及文件的内容变成个生成器''' #生成文件大小 file_name = path.split('\\')[-1] file_size = get_flie_size(file_name,'client') size = os.path.getsize(path) with open(path,'rb') as fr: fr.seek(file_size,0) while True: data = fr.read(10240) if data == bytes():return True yield size,data #日志 def load_my_logging_cfg(name): '''生成随着时间生成文件夹日志''' #生成日志保存路径 time = str(datetime.datetime.now()) time = time.split(' ')[0] path = os.path.join(LOGGER_PATH,time) if not os.path.exists(path):os.mkdir(path) file_path = os.path.join(path, f'{name}.log') #修改定义格式中的地址 logger_fromat = LOGGING_DIC logger_fromat['handlers']['default']['filename'] =file_path logging.config.dictConfig(logger_fromat) # 导入上面定义的logging配置 logger = logging.getLogger(name) # 生成一个log实例 logger.info(f'{name} works!') # 记录该文件的运行状态可以自己修改 

3.db

可以先新建好这三个文件夹,也可以用os.path.exists(path)判断路径来生成

4.服务端.py

from socket import * from conf.setting import IP,PROT,SEVER_PATH from bil.common import * from conf.setting import * load_my_logging_cfg('sever') #生成服务器 sever = socket() sever.bind((IP,PROT)) sever.listen(5) print('start....') #消息的传输 while True: #建立连接 conn,addr = sever.accept() while True: try: #进行文件的传输 #接受1 request = conn.recv(1024) #获得客户端目录下的所有文件名称,并且转换成list flie_list = get_flie_lis(SEVER_PATH) #列表内容进行压缩 flie_list_str_len = zip_data(len(str(flie_list))) #发送列表字符串格式大小 conn.send(flie_list_str_len) # 发送列表的字符串 conn.send(str(flie_list).encode('utf8')) #接收文件名 file_name = conn.recv(1024).decode('utf8') #拼接文件路径 file_path = os.path.join(SEVER_PATH,file_name) #判断文件是不是客户端已经下载完成了 file_name = file_path.split('\\')[-1] #为了防止客户端因为没有文件而报错,且没有文件把他大小设置成0 try: file_size = get_flie_size(file_name, 'client') except Exception: file_size = 0 sever_file_size = get_flie_size(file_name, 'sever') print(file_size,sever_file_size,file_size == sever_file_size) # 生成文件内容与文件大小的生成器 if file_size != sever_file_size: count = 0 for size,file_data in get_file_size_data(file_path): #就第一次发送文件大小 if count == 0: conn.send(zip_data(size)) print(str(zip_data(size)).encode('utf8')) print(file_data) conn.send(file_data) count += 1 else: print(1) #文件已经传输好了客户端有这个文件了 conn.send(zip_data(0)) except: break conn.close() 

5.客户端.py

from socket import * from bil.common import * from conf.setting import * load_my_logging_cfg('client') #生成客户端 client = socket() #与服务端建立连接 client.connect(('127.0.0.1',8000)) #消息的传输 while True: #自动发送请求获取 client.send(b'1') #接受文件目录大小 list_st_size = client.recv(4) #根据文件目录大小获取列表的字符串内容 data = client.recv(uncompress(list_st_size)) #将文件目录进行打印 file_list = eval(data.decode('utf8')) print('请选择你要打印文件') for file_index,file_name in enumerate(file_list): print(f'文件编号{file_index}文件名{file_name}') while True: chiose = input('请选择你要下载文件的编号:') try: chiose_file_name = file_list[int(chiose)] break except Exception: print('序号不存在') continue #发送选择的文件名 chiose_file_name = file_list[int(chiose)] print(chiose_file_name) client.send(str(chiose_file_name).encode('utf8')) #接收文件大小 file_size = uncompress(client.recv(4)) print(file_size) if file_size != 0: #初始下载文件大小 client_file_size = get_flie_size(chiose_file_name,'clien') #下载文件 path = os.path.join(CLIENT_PATH,chiose_file_name) print(client_file_size) print(file_size) while client_file_size <file_size: data = client.recv(10240) client_file_size += 10240 with open(path,'ab') as fa: fa.write(data) #打印进度条 if client_file_size < file_size: schedule = int((client_file_size/file_size)*100) #为了好看加了颜色进去 print("\r",f'[\033[1;31;40m%-{schedule}s%-3s\033[0m%-{100-schedule}s' % ('', f'{schedule}%', ''),end=']') print("\r",f'[\033[1;31;40m%-100s%-3s\033[0m%-0s' % ('', '100%', ''),end='') print('') else: print('') print('文件已经下载好了') chiose_end = input('输入Q退出下载,输入其他继续下载') if chiose_end =='Q' :break 

有不足的地方请指出来,谢谢,这是我在写程序中的总结,这是我学习python刚刚好第二个月后的写的程序

原文链接:https://blog.51cto.com/pythonywy/2838908
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章