python实现文件传输功能

基于之前解决粘包问题后,来实现文件传输我们就不用subprocess模块了,要传输文件首先需要打开文件以字节的格式传给对方,再让对方解码得到文件。但在这之前,我们还需要制定一下规则,确定一下客户端需要什么文件。他发给服务端的请求格式。比如:

cmd = input('>>:').strip()  # get a.txt
if not cmd:
    continue
phone.send(cmd.encode("gbk"))

客户端输入‘get a.txt’给服务端,服务端需要把这个消息分成两部分来解读,第一部分是get,表示客户端想要得到;第二部分是a.txt,指的是文件的名称。比如:

# 收命令
res = conn.recv(8096)  # b'get a.txt'

# 解析命令、提取相应的命令参数
cmds = res.decode('gbk').split()  # ['get','a.txt']  split变列表格式
filename = cmds[1]

这里服务端用split把‘get a.txt’分开变成列表。这样我们就知道了客户端需要什么文件,然后再自己库中找到文件发送给客户端。
最后,配合上之前的内容:
1、客户端

import socket
import struct  # 制作报头的模块
import json   # 转换数据格式(序列化)
import os

share_dir =  ''# 这里是服务器储存资源的地址

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.bind(('127.0.0.1', 8848))
phone.listen(5)
while True:
    conn, client = phone.accept()
    while True:
        try:
            # 收命令
            res = conn.recv(8096)  # b'get a.txt'

            # 解析命令、提取相应的命令参数
            cmds = res.decode('gbk').split()  # ['get','a.txt']  split变列表格式
            filename = cmds[1]

            # 已读的方式打开文件,读取文件内容发送给客户端
            # 第一步:制作固定长度的报头
            header_dic = {
                'filename': filename,
                'file_size': os.path.getsize(r'%s/%s' % (share_dir, filename))  # 这里把文件的名字和地址结合在一起得到文件长度
            }      # 字典方便储存数据
            header_json = json.dumps(header_dic)  # 把字典转换成js格式(字符串类型)

            header_bytes = header_json.encode('gbk')  

            # 第二步:先发送报头的长度
            conn.send(struct.pack('i', len(header_bytes)))  

            # 第三步:再发报头
            conn.send(header_bytes)

            # 第四步:发送真实数据
            with open('%s/%s' % (share_dir, filename), 'rb') as f:   
                for line in f:   # 这样一行一行发比直接发送f.read节省内存空间
                    conn.send(line)
        except ConnectionResetError as err:
            break
    conn.close()

phone.close()

2、客户端

import socket
import struct
import json

download_dir = ''  # 这里是客户端存放资源的地址

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.connect(('127.0.0.1', 8848))
print("------开始咨询客服---------")
while True:
    # 发命令
    cmd = input('>>:').strip()  # get a.txt
    if not cmd:
        continue
    phone.send(cmd.encode("gbk"))

    # 已写的方式打开一个新文件,接收服务器发来的文件的内容写入客户端的新文件

    # 第一步:先收取报头的长度
    obj = phone.recv(4) 
    header_size = struct.unpack('i', obj)[0]

    # 第二步:再收报头
    header_bytes = phone.recv(header_size)

    # 第三步:从报头中间解析出对真是数据的描述信息
    header_json = header_bytes.decode('gbk')
    header_dic = json.loads(header_json)
    print(header_dic)
    total_size = header_dic['file_size']
    filename = header_dic['filename']

    # 第三步:接受真实的数据
    with open('%s/%s' % (download_dir, filename), 'wb') as f: # 在自己的电脑中找一个地址打开一个同类型的文件准备接收数据
        recv_size = 0
        while recv_size < total_size:
            line = phone.recv(1024)
            f.write(line)
            recv_size += len(line)
            print('总大小:%s   已下载大小:%s' % (total_size, recv_size))   # 显示下载进度

phone.close()

这里只有一个下载功能,要想客户端上传文件数据业绩就是对调一下,没什么大问题。熟练后可以用函数或者类的方法来重写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值