pyhton多线程:C、S端多任务文件下载器

一、案例要求:
(1)利用tcp传输方式完成客户端和服务端的数据传输。
(2)利用文件读写操作完成文件读取、传输和下载。
(3)服务端引入多线程,可满足多个客户端进行链接及文件下载。

二、需求分析:
(1)tcp通信,需要socket套接字完成数据传递
(2)下载文件原理:客户端请求下载内容,服务端判断如果文件存在,则读取文件,并将读取到的文件内容以二进制方式传递给客户端,客户端收到数据,写入到文件中。
(3)服务端同时满足多个客户端的链接和下载操作,需要创建子线程,accept方法等待链接和recv方法接收数据、send方法发送文件内容同步进行。

三、代码
3.1 服务端代码:

import threading
import socket
import os

# 定义文件下载函数
def download_file(tcp_client_socket):
    # 接收来自客户端发来的文件名的二进制数据
    file_name_data = tcp_client_socket.recv(1024)
    # 对文件名进行解码
    file_name = file_name_data.decode("gbk")
    print(ip_port, file_name, sep=":")
    # 判断如果该文件服务端存在,则发送任意一个标识字符给客户端,证明文件存在,客户端可以接收。
    if os.path.exists(file_name):
        tcp_client_socket.send("1".encode("utf-8"))   # 可发送任意非控字符,标识文件存在
        print("文件存在,已经将标识字段'1'发给客户端。开始发送...")
        # 文件存在,打开文件,以二进制方式循环读取数据,发送给客户端
        with open(file_name, "rb") as file:
            while True:
                send_data = file.read(1024)
                if send_data:
                    tcp_client_socket.send(send_data)
                # 最后一次读取到的为空,跳出循环
                else:
                    break
    # 如果文件不存在,则端开与客户端的链接,然后客户端会收到长度为0 的信息,表示文件不存在不必再接收。
    else:
        print("文件不存在,将断开与该客户端的链接。此时客户端收到字段为空...")
        tcp_client_socket.close()
    # 文件存在,读取完毕跳出循环以后执行关闭客户端链接
    tcp_client_socket.close()


if __name__ == '__main__':
    # 创建服务端tcp套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 设置socket选项,防止程序退出端口不立即释放的问题
    tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    # 绑定服务端端口
    tcp_server_socket.bind(("", 8080))
    # 变套接字主动为被动,可以建立链接
    tcp_server_socket.listen(128)
    # 循环接收客户端的连接请求, 提示:现在的下载是同步下载,一个用户下载完成以后另外一个用户才能下载
    while True:
        # 等待链接
        tcp_client_socket, ip_port = tcp_server_socket.accept()
        # 创建子线程执行文件下载任务,用于执行读取数据发送给已经链接成功的客户端
        download_file_thread = threading.Thread(target=download_file, args=(tcp_client_socket,))
        # 启动子线程执行对应任务
        download_file_thread.start()

    tcp_server_socket.close()

3.1.1 服务端执行结果展示:
在这里插入图片描述

3.2 客户端代码:

import socket

# 程序入口
if __name__ == '__main__':
    # 创建tcp套接字,AF_INET表示ipv4,SOCK_STREAM表示tcp传输类型
    tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 客户端建立到服务端的链接
    tcp_client_socket.connect(("192.168.14.39", 8080))
    # 输入需要下载的文件名,并编码为二进制文件发给服务端
    file_name = input("请输入需要下载的文件名:")
    tcp_client_socket.send(file_name.encode("utf-8"))
    # 接收服务端回复文件是否存在的消息
    recv_data = tcp_client_socket.recv(1024)
    # 如果存在,则创建文件并循环接收服务端发来的文件的二进制数据,并写入到创建的文件中
    if recv_data:
        print("文件存在,开始接收下载")
        with open("副本"+file_name, "wb") as file:
            # 循环接收数据
            while True:
                recv_data = tcp_client_socket.recv(1024)
                if recv_data:
                    file.write(recv_data)
                # 最后一次读取信息为空,跳出循环
                else:
                    print("下载完成!")
                    break
    # 如果文件不存在,则服务端会关闭与客户端的链接。客户端收到的信息长度为0,通过0判断文件不存在
    else:
        print("文件不存在")

    tcp_client_socket.close()

3.2.1 客户端执行结果展示:
在这里插入图片描述
四、注意点:
(1)判断文件是否存在,导入os模块,利用os.path.exists(路径或文件名)来判断,如果存在,就约定给客户端一个标识,告诉客户端文件是否存在。

(2)需要掌握tcp网络程序流程,客户端:创建套接字、建立连接(三次握手)、send发送数据、recv接收数据、关闭套接字(四次挥手);服务端:创建套接字,绑定服务端端口、listen设置监听、accept等待连接、send发送数据、recv接收数据、关闭与客户端的套接字、关闭主套接字。

(3)掌握文件读写操作。掌握 with open("文件名",“wb”) as file: 的用法,不用手动关闭文件。

(4)创建子线程完成多任务。

创建子线程:线程名 = threading.Thread(target= 函数名或方法名)
开启子线程:线程名.start()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值