利用生成器制作一个简单的客户端接收文件的进度条

  一、首先看一个生成器的例子:

def run():
    count = 0
    while 1:
        n = yield count
        print(n,'---',count)
        count += 1

g = run()
#一开始调用__next__方法不会唤醒,只有用send方法才能打印
g.__next__()
##send的用法
g.send('whw')
g.send('whw1')
g.send('whw2')
g.send('whw3')
g.send('whw4')

  这里,我们在第一次使用__next__()方法是是不会唤醒生成器的,后面加上send()方法可以打印出相应的结果:

  二、在客户端利用生成器加进度条的简单思路:

  大致的过程为:我们先定义一个当前文件传输时传输的数据占文件总大小的比例current_percent变量,注意这个current_percent是不断叠加的:当进行第二次传输时变成了第一次传输的百分比与第二次传输的百分比的和...以此类推;另外,我们把每一次接收的“current_percent”的“当前值”赋值给另外一个变量last_percent,只要current_percent大于last_percent,表明文件就没有存完,只有当二者相等的时候才表示文件全部传完——也就是说,我们的迭代条件就是current_percent >last_percent

  生成器函数的代码如下:

def progress_bar(total_size, current_percent=0, last_percent=0):
    '''进度条功能'''
    while 1:
        received_size = yield current_percent
        current_percent = int(received_size / total_size * 100)
        if current_percent > last_percent:
            print("*" * int(current_percent / 2) + "{percent}%".format(percent=current_percent), end='\r',
                  flush=True)
            # 把本次循环的percent赋值给last
            last_percent = current_percent  

  调用函数的代码如下:

progress_generator = progress_bar(file_size)
progress_generator.__next__()

#其他代码

progress_generator.send(receive_size)

  三、程序的server端与client端的代码如下:

import os
import socket
import json

# C:\Users\dell\Desktop\test
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

STATUS_CODE = {
        200: "开始发送文件!",
        201: "文件不存在!",
    }

def send_response(conn,status_code,*args,**kwargs):
    #制作消息
    data = kwargs
    data['status_code'] = status_code
    data['status_msg'] = STATUS_CODE[status_code]
    data['fill'] = ''
    #扩展data字典,将file_size键加进去
    data.update(kwargs)
    #二进制的消息
    bytes_data = json.dumps(data).encode('utf-8')
    #制作定长报头
    if len(bytes_data) < 1024:
        # zfill——返回指定长度字符串,原字符串右对齐,前面填充0
        data['fill'] = data['fill'].zfill(1024-len(bytes_data))
        bytes_data = json.dumps(data).encode('utf-8')
    conn.send(bytes_data)

def get(conn,addr,filename):
    while 1:
        if not filename:#空指令,断开链接
            print('connection is lost!')
            del conn,addr
            break
        file_path = os.path.join(BASE_DIR,'server',filename)
        #如果文件存在
        if os.path.isfile(file_path):
            #得出文件的大小
            file_size = os.stat(file_path).st_size
            send_response(conn,200,file_size=file_size)
            #开始发送文件
            f = open(file_path,'rb')
            for line in f:
                conn.send(line)
            else:
                print('文件传输成功!')
            f.close()
        else:
            send_response(conn,201)



def run():
    whw_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    whw_server.bind(('127.0.0.1',9999))
    whw_server.listen(5)
    print('Listening......')
    conn,addr = whw_server.accept()
    while 1:
        try:
            res = conn.recv(8096)
            cmds = res.decode('utf-8').split()
            print('收到命令:',res.decode('utf-8'))
            if cmds[0] == 'get':
                get(conn,addr,cmds[1])
        except ConnectionResetError:
            break
    conn.close()


if __name__ == '__main__':
    run()
server.py
import os
import socket
import json

# C:\Users\dell\Desktop\test
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


def progress_bar(total_size, current_percent=0, last_percent=0):
    '''进度条功能'''
    while 1:
        received_size = yield current_percent
        current_percent = int(received_size / total_size * 100)
        if current_percent > last_percent:
            print("*" * int(current_percent / 2) + "{percent}%".format(percent=current_percent), end='\r',
                  flush=True)
            # 把本次循环的percent赋值给last
            last_percent = current_percent

def send_message(whw_sock,filename,**kwargs):
    '''给客户端发送报头'''
    msg_data = {
        'file_name':filename,
        'fill':''#做定长
    }
    msg_data.update(kwargs)
    bytes_msg = json.dumps(msg_data).encode('utf-8')
    if len(msg_data) < 1024:#定长的报头
        msg_data['fill'] = msg_data['fill'].zfill(1024-len(bytes_msg))
        bytes_msg = json.dumps(msg_data).encode('utf-8')
    whw_sock.send(bytes_msg)


def get_response(whw_sock):
    """获取服务器端返回的信息"""
    data = whw_sock.recv(1024)
    return json.loads(data.decode('utf-8'))


def get(whw_sock,cmds):
    filename = cmds[1]
    response = get_response(whw_sock)
    # file_size与server端send_response(conn,200,file_size=file_size)对对应
    file_size = response.get('file_size')
    receive_size = 0
    # 进度条功能
    progress_generator = progress_bar(file_size)
    progress_generator.__next__()
    #注意wb方式打开
    f = open('%s.download' % filename, 'wb')
    # 循环接收
    while receive_size < file_size:
        if file_size - receive_size < 8192:  # last recv
            data = whw_sock.recv(file_size - receive_size)
        else:
            data = whw_sock.recv(8192)
        receive_size += len(data)
        f.write(data)
        # 打印进度条
        progress_generator.send(receive_size)
    else:
        print('\n')
        print('---file [%s] recv done,received size [%s]---' % (filename, file_size))
        f.close()
        os.replace('%s.download' % filename, filename)

def run():
    whw_sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    whw_sock.connect(('127.0.0.1',9999))
    while 1 :
        inp = input('>>>:').strip()
        if not inp:
            continue
        whw_sock.send(inp.encode('utf-8'))
        cmds = inp.split()
        if cmds[0] == 'get':
            get(whw_sock,cmds)


if __name__ == '__main__':
    run()
client.py

  四、演示如下:

 

posted on 2018-05-23 09:09  江湖乄夜雨  阅读(742)  评论(0编辑  收藏  举报