一个初学者的自动备份实例

本文详细介绍了一个使用Python实现的服务器端与客户端文件传输过程,包括日志功能的实现,利用socket进行通信,以及文件的分块传输和接收。通过结构化的报头信息,确保了文件传输的准确性和完整性。

服务器端

#!/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()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值