python ftp 文件服务器

ftp文件服务器

功能

  1. 分为服务端和客户端,要求可以有多个客户端同时操作。
  2. 客户端可以查看服务器文件库中有什么文件。
  3. 客户端可以从文件库中下载文件到本地。
  4. 客户端可以上传一个本地文件到文件库。
  5. 使用print在客户端打印命令输入提示,引导操作

图解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eTIeiQki-1639660200630)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211216160058894.png)]

1.技术点确定

  1. 并发模型: 多线程并发
  2. 数据传输:tcp传输

2.结构设计

  1. 将基本文件操作功能封装为类

3.功能模块

  1. 搭建网络通信模型
  2. 查看文件列表
  3. 下载文件
  4. 上传文件
  5. 客户端退出

4.协议确定

  1. L 请求文件列表
  2. Q 退出
  3. G 下载文件
  4. P 上传文件

5.代码演示

服务器端

"""
ftp 文件服务器,服务端
多进程/线程并发, socket
"""
import sys, os, time
from socket import *
from threading import Thread

# 全局变量
HOST = '0.0.0.0'
PORT = 26262
ADDR = (HOST, PORT)
# 文件库位置
FTP = 'FTP/'


# 创建类实现服务器文件处理功能
class FTPServer(Thread):
    """
    查看列表,下载,上传,退出处理
    """

    def __init__(self, connfd):
        self.connfd = connfd
        super().__init__()

    def do_list(self):
        # 获取文件列表
        files = os.listdir(FTP)
        if not files:
            # 文件库为空
            self.connfd.send('文件库为空'.encode())
        else:
            self.connfd.send('OK'.encode())
            time.sleep(0.5)
            # 拼接文件
            filelist = ''
            for file in files:
                if file[0] != '.' and os.path.isfile(FTP + file):
                    filelist += file + '\n'
            self.connfd.send(filelist.encode())

    def do_get(self, filename):
        try:
            f = open(FTP + filename, 'rb')
        except Exception:
            # 打开失败文件不存在
            self.connfd.send('文件不存在'.encode())
        else:
            self.connfd.send('OK'.encode())
            time.sleep(0.5)
        while True:
            data = f.read(1024)
            if not data:
                time.sleep(0.5)
                self.connfd.send(b'##')
                break
            self.connfd.send(data)
        f.close()
        print('%s传输完毕!'%filename)

    def do_put(self, filename):

        if os.path.isfile(FTP + os.path.basename(filename)):
            self.connfd.send('文件已经存在'.encode())
        else:
            self.connfd.send('OK'.encode())
            time.sleep(0.5)
            f = open(FTP + os.path.basename(filename), 'wb')
            while True:
                data = self.connfd.recv(1024)
                if data == '##'.encode():
                    print('%s接收结束'%os.path.basename(filename))
                    break
                f.write(data)
            f.close()


    # 循环接收请求,分情况调佣功能函数
    def run(self):
        while True:
            data = self.connfd.recv(1024).decode()
            if not data or data == 'Q':
                # 线程结束
                return
            elif data == 'L':
                self.do_list()
            elif data[0] == 'G':
                filename = data.split(' ')[-1]
                self.do_get(filename)
            elif data[0] == 'P':
                filename = data.split(' ')[-1]
                self.do_put(filename)


# 搭建网络服务端模型
def main():
    # 1. 创建监听套接字
    s = socket()
    # 设置套接字端口可以立即重用
    s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    s.bind(ADDR)
    s.listen(5)
    while True:
        # 循环处理客户端连接
        try:
            c, addr = s.accept()
            print('Connect from', addr)
        except KeyboardInterrupt:
            sys.exit('退出服务器')
        except Exception as e:
            print(e)
            continue

        # 创建线程对象
        client = FTPServer(c)
        client.setDaemon(True)
        # 启动线程
        client.start()


if __name__ == '__main__':
    main()

客户端

"""
ftp 文件服务,客户端
"""
import os
import sys
import time
from socket import *

# 服务器地址
ADDR = ('119.91.116.248', 26262)


# 客户端文件处理类
class FTPClient:
    """
    客户端处理 查看,上传,下载,退出
    """

    def __init__(self, sockfd):
        self.sockfd = sockfd

    # 获取文件库中文件列表
    def do_list(self):
        # 发送请求
        self.sockfd.send(b'L')
        # 等待回复
        data = self.sockfd.recv(128).decode()
        if data == 'OK':
            # 一次接收文件字符串
            data = self.sockfd.recv(4096)
            print('\n服务器有以下文件可供下载,请输入 get 文件名\n')
            print(data.decode())
        else:
            print(data)

    # 退出
    def do_quit(self):
        self.sockfd.send(b'Q')
        self.sockfd.close()
        sys.exit('谢谢使用')

    # 下载文件
    def do_get(self, filename):
        # 发送请求
        self.sockfd.send(('G ' + filename).encode())
        # 等待回复
        data = self.sockfd.recv(128).decode()
        if data == 'OK':
            f = open(filename, 'wb')
            # 循环接收写入文件
            while True:
                data = self.sockfd.recv(1024)
                # 如果收到 ## 就是发送完毕
                if data == b'##':
                    break
                f.write(data)
            f.close()
        else:
            print(data)

    # 上传文件
    def do_put(self, filename):
        if os.path.isfile(filename):
            # 发送请求
            self.sockfd.send(('P ' + os.path.basename(filename)).encode())
            # 等待回复
            data = self.sockfd.recv(128).decode()
            if data == 'OK':
                # 发送文件
                try:
                    f = open(filename, 'rb')
                except Exception:
                    print('文件不存在')
                else:
                    for data in f:
                        self.sockfd.send(data)
                    time.sleep(0.5)
                    self.sockfd.send(b'##')

                f.close()
                print('文件上传成功')
            else:
                print(data)
        else:
            print('输入的文件名有误')


# 搭建网络 连接服务器
def main():
    sockfd = socket()
    try:
        sockfd.connect(ADDR)
    except Exception as e:
        print(e)
        return
    # 实例化对象,调用文件处理方法
    ftp = FTPClient(sockfd)
    # 循环发送请求
    while True:
        print('\n=======命令选项========')
        print('**********list**********')
        print('*****   get file   *****')
        print('*****   put file   *****')
        print('*****     quit     *****')
        print('************************\n')
        cmd = input('').strip()
        if cmd == 'list':
            # 请求列表
            ftp.do_list()
        elif cmd == 'quit':
            ftp.do_quit()
            break
        elif cmd[:3] == 'get':
            filename = cmd.split(' ')[-1]
            ftp.do_get(filename)
        elif cmd[:3] == 'put':
            filename = cmd.split(' ')[-1]
            ftp.do_put(filename)
        else:
            print('请输入正确命令')


if __name__ == '__main__':
    main()
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值