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刚刚好第二个月后的写的程序

python -服务器与客户端断电续传程序详细介绍的更多相关文章

  1. android81 多线程下载和断电续传

    package com.itheima.multithreaddownload; import java.io.BufferedReader; import java.io.File; import ...

  2. Android中FTP服务器、客户端搭建以及SwiFTP、ftp4j介绍

    本文主要内容: 1.FTP服务端部署---- 基于Android中SwiFTP开源软件介绍: 2.FTP客户端部署 --- 基于ftp4j开源jar包的客户端开发 : 3.使用步骤 --- 如何测试我 ...

  3. 【python之路35】FTP文件断电续传作业

    开发一个支持多用户在线FTP程序: 要求: 1.用户MD5加密认证 2.允许同时多用户登陆(socketserver) 3.执行命令 4.上传文件 文件传输过程中显示进度条 支持文件的断点续传

  4. IceGrid 用于Python服务器和客户端通信——参数传递

    本篇介绍如何用IceGrid建立python多机通信,传递比较复杂的参数 Ice代码:Demo.ice #ifndef TOS_ICE_COMMON #define TOS_ICE_COMMON mo ...

  5. windows下GitHub的安装、配置以及项目的上传过程详细介绍

    概要 本文主要介绍了在Win10系统中安装Github终端.如何配置安装好的Git终端以及如何利用Git终端将自己的项目上传到远程服务器中 操作必备 win10系统电脑一台.良好的互联网连接.GitH ...

  6. HTML5文件上传器,纯脚本无插件的客户端文件上传器---Uploader 文件上传器类

    概述 客户端完全基于JavaScript的 浏览器文件上传器,不需要任何浏览器插件,但需要和jQuery框架协同工作,支持超大文件上传,其算法是将一个超大文件切片成N个数据块依次提交给服务 端处理,由 ...

  7. window系统下SVN服务器和客户端的搭建和使用

    SVN服务器下载地址: http://subversion.apache.org/packages.html 这里我选用VisualSVN server 服务端和 TortoiseSVN客户端搭配使用 ...

  8. 【转】Linux环境搭建FTP服务器与Python实现FTP客户端的交互介绍

    Linux环境搭建FTP服务器与Python实现FTP客户端的交互介绍 FTP 是File Transfer Protocol(文件传输协议)的英文简称,它基于传输层协议TCP建立,用于Interne ...

  9. python web编程-CGI帮助web服务器处理客户端编程

    这几篇博客均来自python核心编程 如果你有任何疑问,欢迎联系我或者仔细查看这本书的地20章 另外推荐下这本书,希望对学习python的同学有所帮助 概念预热 eb客户端通过url请求web服务器里 ...

随机推荐

  1. BuildWinRTL.dproj 用这个重新编译就行

    BuildWinRTL.dproj 用这个重新编译就行 我每次安装新版本,都删掉了这两个函数 {$IFDEF DEBUG}exports  dbkFCallWrapperAddr,{$IF defin ...

  2. [Erlang-0015][Lager] Erlang日志框架Lager简析

    项目地址:https://github.com/basho/lager (欢迎任何形式的转载,但请务必注明出处:http://www.cnblogs.com/liangjingyang)

  3. C++中代理类和句柄类

    指针是 C 与其他语言区别的重要特征之一,在 C++ 中,指针也被广泛运用,我们通过指针实现多态.然而,众所周知,指针的使用必须小心,否则很容易造成内存泄漏 Memory Leak.当我们有几个指针指 ...

  4. 为什么使用剪切板时都用GlobalAlloc分配内存(历史遗留问题,其实没关系了)

    我在使用剪切板时,发现通用的都是使用GlobalAlloc来分配内存,我就想不是说在Win32中GlobalAlloc和LocalAlloc是一样的那为什么不用LocalAlloc呢,原谅我的好奇心吧 ...

  5. FMX+Win32,窗口无法保持原样,应该是个bug

    从FMX发布开始,一直有这问题,大家看看是不是一个bug,应该如何修复? 新建一个FMX Application,运行后,点击窗口标题栏右上角的“最大化”按钮,此时窗口是最大化的.在windows最底 ...

  6. java多线程之wait和notify

    多线程中的通信是非常重要的概念,线程直接实现通信就可以并发完成很多复杂工作. java在Object类中就设计了wait()和notify()两个方法,以解决这个问题. 1.释义: wait()方法将 ...

  7. composer使用gitlab搭建私有库

    { "repositories": [ { "type": "vcs", // 使用gitlab固定 "url": &q ...

  8. kubernetes实战篇之helm安装

    系列目录 Helm是kubernetes的应用包管理工具,是CNCF孵化器下的一个项目,主要用来管理 Charts.类似于 Ubuntu 中的 APT 或 CentOS 中的 YUM.它提供了一种简单 ...

  9. 设计模式-解释器模式(Interpreter)

    解释器模式是行为型模式的一种.给定一个语言(如由abcdef六个字符组成的字符串集合),定义它的文法的一种表示(S::=abA*ef,A::=cd)并定义一个解释器,解释器使用该表示来解释语言中的句子 ...

  10. POJ 2449:Remmarguts' Date(A* + SPFA)

    题目链接 题意 给出n个点m条有向边,源点s,汇点t,k.问s到t的第k短路的路径长度是多少,不存在输出-1. 思路 A*算法是启发式搜索,通过一个估价函数 f(p) = g(p) + h(p) ,其 ...