网络编程(八)——实现文件传输功能

实现文件传输功能

在通信循环中实现文件传输功能,以下载图片1.png为例,命令为:get 1.png

1、客户端发送命令:

cmd = input(">>:").strip() # get 1.png
    if not cmd:continue
    phone.send(cmd.encode("utf-8"))

2、服务端收命令:

res = conn.recv(8096)
        if not res:break

3、服务端解析命令:

        cmds = res.decode("utf-8").split() #得到['get','1.png']
        filename = cmds[1]

4、服务端以读的方式打开文件,读取文件内容发送给客户端:

  • 第一步:制作固定长度数据头
        header_dic = {
            "filename": filename,
            "md5": "xxxdxxx",
            'file_size': os.path.getsize(r"%s\%s"%(share_dir,filename))
        }
        header_json = json.dumps(header_dic)
        header_bytes = header_json.encode('utf-8')
  • 第二步:先发送数据头的长度
        conn.send(struct.pack("i",len(header_bytes)))
  • 第三步:再发送数据头
        conn.send(header_bytes)
  • 第四步:再发送真实数据
        with open(("%s\%s"%(share_dir,filename)),"rb") as f:
            # conn.send(f.read())
            for line in f:
                conn.send(line) # 逐行读取再发送,有效节约系统内存,但是会粘包

5、 客户端以写的方式打开一个新的文件,接收服务端发来的文件的内容写入客户的新文件:

  • 第一步:先收数据头的长度
    obj = phone.recv(4) header_size = struct.unpack('i',obj)[0]
  • 第二步:再收数据头
    header_bytes = phone.recv(header_size)
  • 第三步:从数据头中解析出对真实数据的描述信息
    header_json = header_bytes.decode("utf-8") 
    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))

程序目录结构 

 

完整代码演示 

1、服务端代码

import socket
import subprocess
import struct
import json
import os

share_dir = r"E:\mydesktop\My_Code\后端\b站网络编程\05文件传输\server\share"

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(("127.0.0.1",9910))
phone.listen(5)
print("starting...")

while True:
    conn,client_addr = phone.accept()
    print(client_addr)
    while True:
        # 1、收命令
        res = conn.recv(8096)
        if not res:break

        # 2、解析命令,提取相应命令参数
        cmds = res.decode("utf-8").split() #得到['get','a.txt']
        filename = cmds[1]

        # 3、以读的方式打开文件,读取文件内容发送给客户端
        # 第一步:制作固定长度的报头。
        header_dic = {
            "filename": filename,
            "md5": "xxxdxxx",
            'file_size': os.path.getsize(r"%s\%s"%(share_dir,filename))
        }
        header_json = json.dumps(header_dic)
        header_bytes = header_json.encode('utf-8')

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

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

        # 第四步:再发送真实的数据
        with open(("%s\%s"%(share_dir,filename)),"rb") as f:
            # conn.send(f.read())
            for line in f:
                conn.send(line) # 逐行读取再发送,有效节约系统内存,但是会粘包

    conn.close()
phone.close()

2、客户端代码

import socket
import struct
import json

download_dir = r"E:\mydesktop\My_Code\后端\b站网络编程\05文件传输\client\Download"

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(("127.0.0.1",9910))

while True:
    # 1、发命令
    cmd = input(">>:").strip() # get a.txt
    if not cmd:continue
    phone.send(cmd.encode("utf-8"))

    # 2、以写的方式打开一个新的文件,接收服务端发来的文件的内容写入客户的新文件
    # 第一步:先收报头的长度
    obj = phone.recv(4)
    header_size = struct.unpack('i',obj)[0]

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

    # 第三步:从数据头中解析出对真实数据的描述信息
    header_json = header_bytes.decode("utf-8")
    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()

3、先运行服务端,再运行客户端,在客户端控制台输入命令:get 1.png

1.png将被下载到Download目录下。 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天自洽了吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值