python_网络编程之端点续传

这个例子分为服务端和客户端,都做了大量的注释,很容易读懂

服务端

##以下代码是梳理思路
# import socketserver
# import os  #使用os模块的join方法
# import json
# cod={'1001':'开始上传','1002':'开始续传'}
# class Nbserver(socketserver.BaseRequestHandler):
#     def handle(self):
#         while 1:
#             # 1 , 接受命令
#             upload_cmd_bytes=self.request.recv(2048) #最大是8k
#             # upload_cmd_str=json.loads(upload_cmd_bytes).decode("utf8")  #错误的写法
#             cmd_dic = json.loads(upload_cmd_bytes.decode("utf8"))  #是字节有解码的方法
#
#
#             # 2,获取文件信息
#             file_md5=cmd_dic['md5']
#             home=r'E:老男孩课程mysql_db'
#             file_mdf_path=os.path.join(home,'zhangzijie',file_md5)
#
#             exist=os.path.exists(file_mdf_path)
#             if not exist: #不续传
#                 #我没有这个文件,你开始给我传
#                 #设计状态码
#                 response = {'code': 1001}
#                 self.request.sendall(b'1001')
#             else:
#                 #怎么续传呢?你的告诉客户端我已经有多少了,你已经给我传了多少了,对方才能
#                 #从断开的那里进行继续传
#                 #根据文件路径获取大小
#                 exist_szie=os.stat(file_mdf_path).st_size
#                 #定义一个协议
#                 response={'code':1002,'size':exist_szie}
#                 self.request.sendall(json.dumps(response).encode("utf-8"))
#                 self.request.sendall(b'1002')
#
#
#             # print(cmd_dic)
#
#
# server=socketserver.ThreadingTCPServer(('127.0.0.1',8001),Nbserver)
# server.serve_forever()

###########################################################################################
# 下面这个例子可以运行,就是上传的目录64行的zhangzijie需要指定
# 开始编写上传部分
# import socketserver
# import os  #使用os模块的join方法
# import json
# cod={'1001':'开始上传','1002':'开始续传'}
# class Nbserver(socketserver.BaseRequestHandler):
#     def handle(self):
#         while 1:
#             # 1 , 接受命令
#             upload_cmd_bytes=self.request.recv(2048) #最大是8k
#             # upload_cmd_str=json.loads(upload_cmd_bytes).decode("utf8")  #错误的写法
#             cmd_dic = json.loads(upload_cmd_bytes.decode("utf8"))  #是字节有解码的方法《########
#                                                                                               #
#                                                                                               #
#             # 2,获取文件信息                                                                   #
#             file_md5=cmd_dic['md5']  #
#             file_name=cmd_dic['file_name']
#             home=r'E:老男孩课程day31ftp_projrct'                                                     #
#             file_md5_path=os.path.join(home,'zhangzijie',file_md5)  #
#             file_name_path = os.path.join(home, 'zhangzijie', file_name)
#             upload_file_size=cmd_dic['size']           #所有文件信息都在上面取到的字典里《########
#             exist=os.path.exists(file_md5_path)
#             if not exist: #不续传
#                 #我没有这个文件,你开始给我传
#                 #设计状态码
#                 response = {'code': 1001}
#                 self.request.sendall(json.dumps(response).encode("utf8"))
#                 f=open(file_md5_path,mode='wb')
#
#                 recv_size=0
#                 #接受上传的文件内容
#                 while recv_size<upload_file_size:
#                     data=self.request.recv(1024)
#                     f.write(data)   #写过来的东西都在内存中
#                     f.flush()       #把内存中的东西刷到硬盘中
#                     recv_size+=len(data)
#                 f.close()
#
#                 #改名字,
#                 #os模块的额rename在windows系统中的python2中会报错
#                 #os.rename(file_md5_path,file_name_path)
#                 #shutil模块在哪都不会报错,除了改文件名还可以该文件夹的名字
#                 import shutil
#                 shutil.move(file_md5_path,file_name_path)
#
#             else:
#                 #怎么续传呢?你的告诉客户端我已经有多少了,你已经给我传了多少了,对方才能
#                 #从断开的那里进行继续传
#                 #根据文件路径获取大小
#                 exist_szie=os.stat(file_md5_path).st_size
#                 #定义一个协议
#                 response={'code':1002,'size':exist_szie}
#                 self.request.sendall(json.dumps(response).encode("utf-8"))
#                 self.request.sendall(b'1002')
#
#                 f = open(file_md5_path, mode='ab')  #这里是追加
#
#                 # recv_size = 0     #这里的总大小就不在是0了,而是已经接受了的大小
#                 recv_size=exist_szie         #这里有个方法,对于后面的变量名,类似的用到了前面的名字
#                                              #可以不用重新再起名字,直接重新赋值把前面的覆盖掉就可以了
#                 # 接受上传的文件内容
#                 while recv_size < upload_file_size:
#                     data = self.request.recv(1024)
#                     f.write(data)  # 写过来的东西都在内存中
#                     f.flush()  # 把内存中的东西刷到硬盘中
#                     recv_size += len(data)
#                 f.close()
#
#
#             # print(cmd_dic)
#
#
# server=socketserver.ThreadingTCPServer(('127.0.0.1',8001),Nbserver)
# server.serve_forever()
# #####################################################################################
# 下面这个例子对方法进行归类
# 开始编写上传部分
import socketserver
import os  #使用os模块的join方法
import json
cod={'1001':'开始上传','1002':'开始续传'}

def upload(cmd_dic,conn):  #用conn代替了下面类中的self.request
    file_md5 = cmd_dic['md5']  #
    file_name = cmd_dic['file_name']
    home = r'E:老男孩课程day31ftp_projrct'  #
    file_md5_path = os.path.join(home, 'zhangzijie', file_md5)  #
    file_name_path = os.path.join(home, 'zhangzijie', file_name)
    upload_file_size = cmd_dic['size']  # 所有文件信息都在上面取到的字典里《########
    exist = os.path.exists(file_md5_path)
    if not exist:  # 不续传
        # 我没有这个文件,你开始给我传
        # 设计状态码
        response = {'code': 1001}
        conn.sendall(json.dumps(response).encode("utf8"))
        f = open(file_md5_path, mode='wb')

        recv_size = 0
        # 接受上传的文件内容
        while recv_size < upload_file_size:
            data = conn.recv(1024)
            f.write(data)  # 写过来的东西都在内存中
            f.flush()  # 把内存中的东西刷到硬盘中
            recv_size += len(data)
        f.close()

        # 改名字,
        # os模块的额rename在windows系统中的python2中会报错
        # os.rename(file_md5_path,file_name_path)
        # shutil模块在哪都不会报错,除了改文件名还可以该文件夹的名字
        import shutil
        shutil.move(file_md5_path, file_name_path)

    else:
        # 怎么续传呢?你的告诉客户端我已经有多少了,你已经给我传了多少了,对方才能
        # 从断开的那里进行继续传
        # 根据文件路径获取大小
        exist_szie = os.stat(file_md5_path).st_size
        # 定义一个协议
        response = {'code': 1002, 'size': exist_szie}
        conn.sendall(json.dumps(response).encode("utf-8"))
        conn.sendall(b'1002')

        f = open(file_md5_path, mode='ab')  # 这里是追加

        # recv_size = 0     #这里的总大小就不在是0了,而是已经接受了的大小
        recv_size = exist_szie  # 这里有个方法,对于后面的变量名,类似的用到了前面的名字
        # 可以不用重新再起名字,直接重新赋值把前面的覆盖掉就可以了
        # 接受上传的文件内容
        while recv_size < upload_file_size:
            data = conn.recv(1024)
            f.write(data)  # 写过来的东西都在内存中
            f.flush()  # 把内存中的东西刷到硬盘中
            recv_size += len(data)
        f.close()


class Nbserver(socketserver.BaseRequestHandler):
    def handle(self):
        while 1:
            # 1 , 接受命令
            upload_cmd_bytes=self.request.recv(2048) #最大是8k
            # upload_cmd_str=json.loads(upload_cmd_bytes).decode("utf8")  #错误的写法
            cmd_dic = json.loads(upload_cmd_bytes.decode("utf8"))  #是字节有解码的方法《########

            if cmd_dic['cmd']=='upload':
                upload(cmd_dic,self.request) #函数调用的时候,实参传self.request
            elif cmd_dic['cmd']=='download':
                pass       #下载的代码
            


server=socketserver.ThreadingTCPServer(('127.0.0.1',8001),Nbserver)
server.serve_forever()
ftp断点续传服务端

客户端

##以下代码是梳理思路
# import socket
# import json
# import hashlib
# import os
#
# def file_md5(file_path):
#     """
#     对文件进行md5加密
#     :param file_path:
#     :return:
#     """
#     obj=open(file_path,mode='rb')
#     m=hashlib.md5()       #实例化MD5
#     for line in obj:
#         m.update(line)    #使用md5的update方法
#     obj.close()
#     return m.hexdidest()
#
# sk=socket.socket()
# sk.connect(('127.0.0.1',8001))
# while 1:
#     cmd=input("请输入命令:")
#     """
#     1,自定义协议
#     {'cmd':'upload','file_path':'.....'}
#     """
#     #获取文件的相关信息
#     file_path="/.../"
#     file_md5_val=file_md5(file_path)
#     file_name= os.path.basename(file_path)
#     file_size=os.stat(file_path).st_size
#     cmd_dict={'cmd':'upload','file_name':file_name,'size':file_size}
#
#     suload_cmd_bytes=json.dumps(cmd_dict).encode("utf8")
#     sk.sendall(suload_cmd_bytes)  # 推荐使用sendall
#
#     #等待服务端的响应
#     response=json.loads(sk.recv(8096).decode("utf-8")) #通过序列化与反序列化,最后又转化成字典的操作
#                                                        #这种最后就非常方便
#     if response['code']==1001:
#         #从头开始传
#         pass
#     else:
#         #从断点开始续传
#         exist_zise=response['size']

###########################################################################################
# 下面的例子可以运行,就是上传的文件需要指定
# 开始编写上传部分
# import socket
# import json
# import hashlib
# import os
#
# def file_md5(file_path):
#     """
#     对文件进行md5加密
#     :param file_path:
#     :return:
#     """
#     obj=open(file_path,mode='rb')
#     m=hashlib.md5()       #实例化MD5
#     for line in obj:
#         m.update(line)    #使用md5的update方法
#     obj.close()
#     return m.hexdigest()
#
# sk=socket.socket()
# sk.connect(('127.0.0.1',8001))
# while 1:
#     cmd=input("请输入命令:")
#     """
#     1,自定义协议
#     {'cmd':'upload','file_path':file_path}
#     """
#     #获取文件的相关信息
#     file_path="hello.py"
#     file_md5_val=file_md5(file_path)
#     file_name= os.path.basename(file_path)
#     file_size=os.stat(file_path).st_size
#     cmd_dict={'cmd':'upload','file_name':file_name,'size':file_size,'md5':file_md5_val}
#
#     suload_cmd_bytes=json.dumps(cmd_dict).encode("utf8")
#     sk.sendall(suload_cmd_bytes)  # 推荐使用sendall
#
#     #等待服务端的响应
#     response=json.loads(sk.recv(8096).decode("utf8")) #通过序列化与反序列化,最后又转化成字典的操作
#                                                        #这种最后就非常方便
#     if response['code']==1001:
#         #从头开始上传,文件迭代,一行一行发
#         # with  open(file_path,mode='rb') as f:
#         #     for line in f:
#         #         sk.sendall(line)
#         #发送可以有两种方式,另外一种如下:
#         f=open(file_path,mode="rb")
#         send_size=0
#         while send_size< file_size: #不能等于,如果是等于,就会一直循环
#             data=f.read(1024)
#             sk.sendall(data)
#             send_size+=len(data)
#         f.close()
#
#
#     else:
#         #从断点开始续传
#         exist_zise=response['size']
#         f=open(file_path,'rb')
#         f.seek(exist_zise) #seek跳到某个字节
#         send_size=exist_zise  #已经发送的等于断点处的字节大小
#         while send_size< file_size:  #已发的字节小于总大小
#             data=f.read(1024)
#             sk.sendall(data)
#             send_size+=len(data)
#         f.close()


# #####################################################################################

# 下面的例子对方法进行归类
# 开始编写上传部分
import socket
import json
import hashlib
import os
import time
#先对函数进行归类



def file_md5(file_path):
    """
    对文件进行md5加密
    :param file_path:
    :return:
    """
    obj=open(file_path,mode='rb')
    m=hashlib.md5()       #实例化MD5
    for line in obj:
        m.update(line)    #使用md5的update方法
    obj.close()
    return m.hexdigest()

#进度条
def jdt(size,total_size):
    val = int(size/total_size * 100)
    time.sleep(0.1)
    print('
%s%%|%s' %(val,"#"*val,), end='')


def send_file(exist_zise,file_tocal_size):
    f = open(file_path, 'rb')
    f.seek(exist_zise)  # seek跳到某个字节
    send_size = exist_zise  # 已经发送的等于断点处的字节大小
    while send_size < file_tocal_size:  # 已发的字节小于总大小
        data = f.read(1024)
        sk.sendall(data)
        send_size += len(data)
        jdt(send_size,file_tocal_size)            #调用进度条函数
    f.close()

def upload(file_path):
    #获取文件的相关信息
    file_md5_val=file_md5(file_path)
    file_name= os.path.basename(file_path)
    file_size=os.stat(file_path).st_size
    cmd_dict={'cmd':'upload','file_name':file_name,'size':file_size,'md5':file_md5_val}

    suload_cmd_bytes=json.dumps(cmd_dict).encode("utf8")
    sk.sendall(suload_cmd_bytes)  # 推荐使用sendall

    #等待服务端的响应
    response=json.loads(sk.recv(8096).decode("utf8")) #通过序列化与反序列化,最后又转化成字典的操作
                                                       #这种最后就非常方便
    if response['code']==1001:
        #从头开始上传,文件迭代,一行一行发
        # with  open(file_path,mode='rb') as f:
        #     for line in f:
        #         sk.sendall(line)
        #发送可以有两种方式,另外一种如下:
        f=open(file_path,mode="rb")
        send_file(0,file_size)

    else:
        #从断点开始续传
        exist_zise=response['size']
        send_file(exist_zise,file_size)




sk=socket.socket()
sk.connect(('127.0.0.1',8001))
while 1:
    user_onput=input("请输入命令:")
    cmd,file_path=user_onput.split('|',maxsplit=1)
    if cmd=='upload':
        upload(file_path)
    elif cmd=='download':
        pass           #如果elif特别多可以考虑使用反射
ftp断点续传客户端
原文地址:https://www.cnblogs.com/zhuhaofeng/p/9590954.html