服务器端:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import struct
import json
import os
import logging
# 日志共功能开始
KaoqinLogger = logging.getLogger('考勤备份日志')
handler1 = logging.StreamHandler() #打印到终端
handler2 = logging.FileHandler('kaoqin.log',encoding='utf-8')
formatter1=logging.Formatter(
fmt='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
)
handler1.setFormatter(formatter1)
handler2.setFormatter(formatter1)
KaoqinLogger.addHandler(handler1)
KaoqinLogger.addHandler(handler2)
KaoqinLogger.setLevel(10)
handler1.setLevel(10)
handler2.setLevel(10)
# 日志功能结束
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # AF_INET表示基于网络通信的套接字,SOCK_STREAM表示流式协议(tcp),SOCK_DGRAM表示UDP协议
server.bind(('127.0.0.1', 8081))
server.listen(5)
while True:
conn, client_addr = server.accept()
print('client_addr', client_addr)
while True:
try:
beginning = conn.recv(1024) # 接收客户端发过来的开始信息
filepath = 'C:\\SHARE\\aaa.mp4'
# 制作报头
headers = {
'filename': filepath.split('\\')[-1],
'md5': 'md5',
'filesize': os.path.getsize(filepath)
}
headers_json = json.dumps(headers)
headers_bytes = headers_json.encode('utf-8')
# 发送报头长度
conn.send(struct.pack('i', len(headers_bytes)))
# 发送报头
conn.send(headers_bytes)
#发送真实数据
with open(filepath, 'rb') as f:
for line in f:
conn.send(line)
KaoqinLogger.debug('数据发送完毕!')
except ConnectionAbortedError:
break
conn.close()
server.close()
客户端:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket, struct, json, os, time, logging.config
# 定义日志输出格式
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录,当前文件的父级目录
logfile_name = 'kaoqin_client.log' # log文件名
# 如果不存在定义的日志目录就创建一个
# if not os.path.isdir(logfile_dir):
# os.mkdir(logfile_dir)
# log文件的全路径
logfile_path = os.path.join(logfile_dir, 'DOWNLOAD', logfile_name)
# log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
},
'filters': {},
'handlers': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'standard'
},
#打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': logfile_path, # 日志文件
'maxBytes': 1024*1024*5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': False, # 向上(更高level的logger)传递,也就是需不需要给爹传
},
},
}
logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置
logger = logging.getLogger(__name__) # 生成一个log实例
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 8081))
DOWNLOAD_DIR = 'D:\DOWNLOAD'
client.send('start'.encode('utf-8')) # 发送开始下载指令
headers_size = struct.unpack('i', client.recv(4))[0] # 接收报头长度
headers_bytes = client.recv(headers_size) # 接收报头
headers_json = headers_bytes.decode('utf-8')
headers_dic = json.loads(headers_json)
filename = headers_dic['filename']
filesize = headers_dic['filesize']
filepath_list = filename.split('.')
file_time = time.strftime("%Y-%m-%d", time.localtime())
filepath_list[0] = filepath_list[0] + file_time
filename_new = '.'.join(filepath_list)
filepath_new = os.path.join(DOWNLOAD_DIR, filename_new)
print(filename_new,filepath_new)
with open(filepath_new, 'wb') as f: # 接收真实数据
recv_size = 0
while recv_size < filesize:
line = client.recv(1024)
recv_size += len(line)
f.write(line)
print('===>下载成功<===')
logger.debug('接收完毕!') # 记录该文件的运行状态
client.close()
本文详细介绍了一个使用Python实现的服务器端与客户端文件传输过程,包括日志功能的实现,利用socket进行通信,以及文件的分块传输和接收。通过结构化的报头信息,确保了文件传输的准确性和完整性。

被折叠的 条评论
为什么被折叠?



