6.28自我總結 客戶端與伺服器之間文件傳輸斷電續傳 `通過判斷文件大小,以及文件在讀取中的指針位置的調整來解決斷電續傳問題' 1.程式目錄 2.程式思路 第一步:我們什麼都不懂,但是有幾個模塊肯定會有一個是conf中的setting來存一些常量 第二步:我們也需要一個db文件來存內容 第三步:我們 ...
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剛剛好第二個月後的寫的程式