利用生成器製做一個簡單的客戶端接收文件的進度條

  1、首先看一個生成器的例子:json

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()方法能夠打印出相應的結果:服務器

  2、在客戶端利用生成器加進度條的簡單思路:socket

  大體的過程爲:咱們先定義一個當前文件傳輸時傳輸的數據佔文件總大小的比例current_percent變量,注意這個current_percent是不斷疊加的:當進行第二次傳輸時變成了第一次傳輸的百分比與第二次傳輸的百分比的和...以此類推;另外,咱們把每一次接收的「current_percent」的「當前值」賦值給另一個變量last_percent,只要current_percent大於last_percent,代表文件就沒有存完,只有當兩者相等的時候才表示文件所有傳完——也就是說,咱們的迭代條件就是current_percent >last_percentide

  生成器函數的代碼以下:函數

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  

  調用函數的代碼以下:spa

progress_generator = progress_bar(file_size)
progress_generator.__next__()

#其餘代碼

progress_generator.send(receive_size)

  3、程序的server端與client端的代碼以下:code

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

  4、演示以下:orm

相關文章
相關標籤/搜索