美文网首页程序员运维文档简友广场
python通过pyftpdlib实现FTP服务端和客户端

python通过pyftpdlib实现FTP服务端和客户端

作者: 微笑沉默 | 来源:发表于2021-01-11 11:11 被阅读0次

    1. 使用pyftpdlib模块搭建FTP服务器

    在我上一篇文章里面,详细的介绍了在linux操作系统下面搭建vsftpd服务,那么我们如何通过python实现一个FTP服务器呢?本文会有一个详细的介绍,搭建FTP服务器需要用到python的pyftpdlib,这是一个第三方模块需要使用pip进行安装,具体安装步骤如下:

    pip3 install -i https://mirrors.aliyun.com/pypi/simple pyftpdlib
    [root@zhanghao ~]# python3
    Python 3.6.8 (default, Nov 16 2020, 16:55:22) 
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import pyftpdlib
    >>> pyftpdlib.__doc__
    '\npyftpdlib: RFC-959 asynchronous FTP server.\n\npyftpdlib implements a fully functioning asynchronous FTP server as\ndefined in RFC-959.  A hierarchy of classes outlined below implement\nthe backend functionality for the FTPd:\n\n    [pyftpdlib.ftpservers.FTPServer]\n      accepts connections and dispatches them to a handler\n\n    [pyftpdlib.handlers.FTPHandler]\n      a class representing the server-protocol-interpreter\n      (server-PI, see RFC-959). Each time a new connection occurs\n      FTPServer will create a new FTPHandler instance to handle the\n      current PI session.\n\n    [pyftpdlib.handlers.ActiveDTP]\n    [pyftpdlib.handlers.PassiveDTP]\n      base classes for active/passive-DTP backends.\n\n    [pyftpdlib.handlers.DTPHandler]\n      this class handles processing of data transfer operations (server-DTP,\n      see RFC-959).\n\n    [pyftpdlib.authorizers.DummyAuthorizer]\n      an "authorizer" is a class handling FTPd authentications and\n      permissions. It is used inside FTPHandler class to verify user\n      passwords, to get user\'s home directory and to get permissions\n      when a filesystem read/write occurs. "DummyAuthorizer" is the\n      base authorizer class providing a platform independent interface\n      for managing virtual users.\n\n    [pyftpdlib.filesystems.AbstractedFS]\n      class used to interact with the file system, providing a high level,\n      cross-platform interface compatible with both Windows and UNIX style\n      filesystems.\n\nUsage example:\n\n>>> from pyftpdlib.authorizers import DummyAuthorizer\n>>> from pyftpdlib.handlers import FTPHandler\n>>> from pyftpdlib.servers import FTPServer\n>>>\n>>> authorizer = DummyAuthorizer()\n>>> authorizer.add_user("user", "12345", "/home/giampaolo", perm="elradfmwMT")\n>>> authorizer.add_anonymous("/home/nobody")\n>>>\n>>> handler = FTPHandler\n>>> handler.authorizer = authorizer\n>>>\n>>> server = FTPServer(("127.0.0.1", 21), handler)\n>>> server.serve_forever()\n[I 13-02-19 10:55:42] >>> starting FTP server on 127.0.0.1:21 <<<\n[I 13-02-19 10:55:42] poller: <class \'pyftpdlib.ioloop.Epoll\'>\n[I 13-02-19 10:55:42] masquerade (NAT) address: None\n[I 13-02-19 10:55:42] passive ports: None\n[I 13-02-19 10:55:42] use sendfile(2): True\n[I 13-02-19 10:55:45] 127.0.0.1:34178-[] FTP session opened (connect)\n[I 13-02-19 10:55:48] 127.0.0.1:34178-[user] USER \'user\' logged in.\n[I 13-02-19 10:56:27] 127.0.0.1:34179-[user] RETR /home/giampaolo/.vimrc\n                      completed=1 bytes=1700 seconds=0.001\n[I 13-02-19 10:56:39] 127.0.0.1:34179-[user] FTP session closed (disconnect).\n'
    

    pyftpdlib实现了一个功能完整的异步FTP服务,在rfc-959中定义的。

    pyftpdlib.ftpservers.FTPServer : 接收客户端连接,然后分发给对应的程序
    pyftpdlib.handlers.FTPHandler : 一个表示服务器协议解释器的类,每次出现一个新的连接FTPServer将创建一个新的FTPHandler实例来处理当前PI会话。
    pyftpdlib.handlers.ActiveDIPpyftpdlib.handlers.PassiveDIP : 主动模式和被动模式的基础类
    pyftpdlib.handlers.DTPHandler : 这个类处理的是数据传输进程
    pyftpdlib.authorizers.DummyAuthorizer : 处理FTPd的认证和权限的处理类,用于处理用户密码,获取用户的家目录和权限,DummyAuthorizer 是基础的认证模块的类,提供平台无关接口的基础授权程序类
    用于管理虚拟用户。
    pyftpdlib.filesystems.AbstractedFS : 类用于与文件系统交互,提供了一个高级的,跨平台接口兼容Windows和UNIX风格文件系统。

    1.1 实现脚本

    1.1.1 加载模块
    from pyftpdlib.authorizers import DummyAuthorizer
    from pyftpdlib.handlers import FTPHandler
    from pyftpdlib.servers import FTPServer
    from pyftpdlib.log import LogFormatter
    
    1.1.2 添加一个FTP的handler
    def ftpServer(username, password, directory):
    
        '''
        启动一个ftp的server进程
        :param username: 需要添加用户的用户名
        :param password: 用户的密码
        :param directory: 用户的家目录,也就是ftp的数据目录
        :return:
        '''
    
        # 添加虚拟用户,验证用户需要用户名、密码、家目录、权限
        author = DummyAuthorizer()
        author.add_user(username, password, directory, perm="elradfmw")
    
        # 初始化ftp句柄
        handler = FTPHandler
        handler.authorizer = author
    
        # 添加被动端口范围
        handler.passive_ports = range(2000, 2400)
    
        # 启动server,本地执行,监听21号端口
        server = FTPServer(('0.0.0.0', 32), handler)
        server.serve_forever()
    
    username = "zhanghao"
    password = "aixocm"
    directory = "/data/zhanghao"
    ftpServer(username, password, directory)
    

    运行报错如下:对于脚本需要添加异常处理,捕获到目录不存在,需要创建目录

    [root@zhanghao python-learning]# python3 ftptest.py 
    Traceback (most recent call last):
      File "ftptest.py", line 37, in <module>
        ftpServer(username, password, directory)
      File "ftptest.py", line 21, in ftpServer
        author.add_user(username, password, directory, perm="elradfmw")
      File "/usr/local/lib/python3.6/site-packages/pyftpdlib/authorizers.py", line 107, in add_user
        raise ValueError('no such directory: %r' % homedir)
    ValueError: no such directory: '/data/zhanghao'
    

    运行报错如下:如果端口被占用,需要捕获报错,然后将输出:"21号端口被占用"

    [root@zhanghao python-learning]# python3 ftptest.py 
    Traceback (most recent call last):
      File "ftptest.py", line 37, in <module>
        ftpServer(username, password, directory)
      File "ftptest.py", line 31, in ftpServer
        server = FTPServer(('0.0.0.0', 21), handler)
      File "/usr/local/lib/python3.6/site-packages/pyftpdlib/servers.py", line 118, in __init__
        self.bind_af_unspecified(address_or_socket)
      File "/usr/local/lib/python3.6/site-packages/pyftpdlib/ioloop.py", line 1018, in bind_af_unspecified
        raise socket.error(err)
    OSError: [Errno 98] Address already in use
    

    完善脚本之后

    #!/usr/bin/env python3
    #coding:utf-8
    
    from pyftpdlib.authorizers import DummyAuthorizer
    from pyftpdlib.handlers import FTPHandler
    from pyftpdlib.servers import FTPServer
    from pyftpdlib.log import LogFormatter
    import os
    
    def ftpServer(username, password, directory):
    
        '''
        启动一个ftp的server进程
        :param username: 需要添加用户的用户名
        :param password: 用户的密码
        :param directory: 用户的家目录,也就是ftp的数据目录
        :return:
        '''
    
        # 如果目录不存在,就创建目录
        if not os.path.exists(directory):
            os.mkdir(directory)
        
        try:
            # 添加虚拟用户,验证用户需要用户名、密码、家目录、权限
            author = DummyAuthorizer()
            author.add_user(username, password, directory, perm="elradfmw")
        except OSError as e:
            if "Address already in use" in e:
                print("21号端口被占用")
    
        # 初始化ftp句柄
        handler = FTPHandler
        handler.authorizer = author
    
        # 添加被动端口范围
        handler.passive_ports = range(2000, 2400)
    
        # 启动server,本地执行,监听21号端口
        server = FTPServer(('0.0.0.0', 21), handler)
        server.serve_forever()
    
    username = "zhanghao"
    password = "aixocm"
    directory = "/data/zhanghao"
    ftpServer(username, password, directory)
    

    正常输出

    [root@zhanghao python-learning]# python3 ftptest.py 
    [I 2021-01-09 05:40:02] concurrency model: async
    [I 2021-01-09 05:40:02] masquerade (NAT) address: None
    [I 2021-01-09 05:40:02] passive ports: 2000->2399
    [I 2021-01-09 05:40:02] >>> starting FTP server on 0.0.0.0:32, pid=4772 <<<
    

    客户端连接

    [root@zhserver zhanghao]# ftp 192.168.0.101
    Connected to 192.168.0.101 (192.168.0.101).
    220 pyftpdlib 1.5.6 ready.
    Name (192.168.0.101:root): zhanghao
    331 Username ok, send password.
    Password:
    230 Login successful.
    Remote system type is UNIX.
    Using binary mode to transfer files.
    
    1.1.3 FTP服务器资源限制
     from pyftpdlib.handlers import ThrottledDTPHandler
    transport_handler = ThrottledDTPHandler
    transport_handler.read_limit = 200 * 1024
    transport_handler.write_limit = 100 * 1024
    handler.dtp_handler = transport_handler
    
    1.1.4 添加输出log

    脚本中添加log,输出到屏幕和日志文件,日志文件名称为ftp.log

    from pyftpdlib.log import LogFormatter
    import logging
    
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
        
    stream = logging.StreamHandler()
    log_file = logging.FileHandler(filename="ftp.log", encoding="utf-8")
        
    stream.setFormatter(LogFormatter())
    log_file.setFormatter(LogFormatter())
        
    logger.addHandler(stream)
    logger.addHandler(log_file)
    
    1.1.5 用户权限
    参数 含义
    e 读权限,改变文件目录
    l 读权限,可以列出所有的文件
    r 读权限,可以从服务器下载文件
    a 写权限,可以上传文件
    d 写权限,删除文件
    f 写权限,文件重命名
    m 写权限,创建文件
    w 写权限
    M 文件传输的模式

    2. ftplib客户端实现

    from ftplib import FTP
    def ftpClient(host_ip, username, password):
        '''
        ftp客户端程序
        :param host_ip:ftp server的IP地址
        :param username: 连接server端的用户名
        :param password: 用户密码
        :return:
        '''
        ftp_client = FTP(host=host_ip, user=username, passwd=password)
        ftp_client.encoding = 'gbk'
        
        # 执行客户端的操作
        ftp_client.cwd()
    

    相关文章

      网友评论

        本文标题:python通过pyftpdlib实现FTP服务端和客户端

        本文链接:https://www.haomeiwen.com/subject/mgzhaktx.html