学习笔记(14):Python网络编程&并发编程-文件传输功能实现

立即学习:https://edu.csdn.net/course/play/24458/296245?utm_source=blogtoedu

1.课程目的:

       实现客户端输入下载文件的命令,然后将命令发送给服务端,服务端再执行下载文件的命令,最后将执行下载文件命令后的结果返回给客户端,客户端进行接收,这样就完成了一个简单的文件下载功能。文件的上传与下载类似,只是两个相反的过程

2.知识点与关键点:

1)os模块:可使用os.path.getsize(filename)来获取指定文件的大小;

2)在服务端接收的命令,使用split命令将接收的命令的字符串分割,判断第一个是‘get’还是‘put’,即判断时下载文件还是上传文件

3.完整代码

'''

服务端

'''

import socket
import subprocess
import json
import struct
import os
server_dir = r'C:\Users\jinlin\Desktop\python_further_study\socket编程\文件的传输(上传)\简单版本\serve'


phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8080))
phone.listen(5)
while True:
    #接收客户端发送过来连接服务器请求
    res = phone.accept()
    conn,client_addr = res

    while True:
        try:
            #1接收客户端发送过来的命令
            resv = conn.recv(1024)
            #2将接收到的结果进行分割,获得命令以及文件名
            cmds = resv.decode('utf-8').split()#['get','a.txt']
            print('*'*50)
            #3处理命令,执行命令并且获得命令得到的结果
            cmd = cmds[0]
            filename = cmds[1]
            total_size = os.path.getsize(r'%s/%s'%(server_dir,filename))#获得文件的字节数大小

            #1)制作包含文件名和文件大小的文件头,用字典实现
            headers_dict = {
                "filename":filename,
                "filedata":"2020/03/09",
                "total_size":total_size
            }

            #2)将字典先序列化成惊悚字符串,再转为bytes类型文件头
            headers_json = json.dumps(headers_dict)

            #3)获取bytes类型的长度
            headers_bytes = headers_json.encode('utf-8')
            headers_size = len(headers_bytes)

            #4)将bytes类型文件头长度定制为固定长度的报头
            header = struct.pack('i',headers_size)

            #5)向客户端发送报头
            conn.send(header)

            #6)向客户端发送包含文件信息的字典
            conn.send(headers_bytes)

            #7)通过二进制只读的方式打开文件,按行读取文件并且发送给客户端
            with open(filename,'rb') as fp:
                for line in fp:
                    conn.send(line)

        except ConnectionResetError:
            break
    conn.close()

phone.close()

'''

客户端

'''

#导入模块
import socket
import struct
import json
client_dir = r'C:\Users\jinlin\Desktop\python_further_study\socket编程\文件的传输(上传)\简单版本\client'

#1、设置phone套接字
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#2、连接服务器(打电话),本地地址:127.0.0.1
phone.connect(('127.0.0.1',8080))

#3、向服务器发送请求send(),发送的数据不能直接发送字符串,因为要传送到物理层底层,因此需要转换成二进制的bytes类型进行发送,只需:发送的数据.encode('utf-8')即可
while True:
    cmd = input("请输入:")#向服务端发送下载文件的命令,get a.txt
    #修复客户端发送空字符串而服务器卡在接收信息处的bug,continue表示跳出本次循环,重新开始下一次的循环
    if not cmd:continue
    phone.send(cmd.encode('utf-8'))

    #4、接收服务器返回来的数据recv()

    #1)先接收由服务器返回来的报头,报头是固定长度的,因此取前面4字节的数据即为报头
    header = phone.recv(4)#返回的是一个对象

    #2)解析报头,得到bytes类型的文件头长度
    obj_truple = struct.unpack('i',header)#返回的是一个元组
    headers_bytes_size = obj_truple[0]#取元组第一个元素即为总字节数

    #3)接收bytes类型的文件头数据
    headers_bytes = phone.recv(headers_bytes_size)

    #4)将bytes类型的文件头数据反序列化成字典
    headers_json = headers_bytes.decode('utf-8')
    headers_dict = json.loads(headers_json)
    print(headers_dict)

    #5)从字典中取出字命令执行结果字节总长度
    total_size = headers_dict['total_size']
    filename = headers_dict['filename']

    #6)接收返回的数据
    with open(r'%s/%s'%(client_dir,filename), 'wb') as fp:
        recv_size = 0
        while recv_size < total_size:
                recv_line = phone.recv(1024)#接收小于1024bytes的数据
                fp.write(recv_line)
                recv_size += len(recv_line)
                print('文件总字节长为%s,已经下载了%s'%(total_size,recv_size))

#5、关闭套接字phone
phone.close()

4.运行的结果:

...

客户端结果

...

请输入:get mn.png
{'filename': 'mn.png', 'filedata': '2020/03/09', 'total_size': 702935}
文件总字节长为702935,已经下载了6
文件总字节长为702935,已经下载了8
文件总字节长为702935,已经下载了237
文件总字节长为702935,已经下载了455
文件总字节长为702935,已经下载了686
文件总字节长为702935,已经下载了851
文件总字节长为702935,已经下载了946
文件总字节长为702935,已经下载了1113
文件总字节长为702935,已经下载了1339
文件总字节长为702935,已经下载了1387
文件总字节长为702935,已经下载了1847
文件总字节长为702935,已经下载了2009

.......

文件总字节长为702935,已经下载了702656
文件总字节长为702935,已经下载了702935

5.待改进

代码的可读性较差,可以通过函数以及面向对象来对其进行优化,增加其代码的可读性

发布了39 篇原创文章 · 获赞 11 · 访问量 420

猜你喜欢

转载自blog.csdn.net/qq_45769063/article/details/104764967
今日推荐