TOC

Python 应用: 简易 FTP 服务器

FTP 需要 pyftpdlib 包的支持。

https://pypi.org/project/pyftpdlib/
https://github.com/giampaolo/pyftpdlib/

根据文档,使用统一套代码支持 Python 2.6 - 3.5。我在更高的 Python 版本上运行也挺正常的。

根据文档上的性能测试数据,它的传输速度和 Linux 上常用的两款 FTP 服务器 vsftpd 和 proftpd 相同,但是有更好的并发性能(远超)。

python3 -m pip install pyftpdlib --user

# 默认工作在 0.0.0.0:2121 端口, 只读, 匿名登录
python3 -m pyftpdlib -d ~/Documents/Mine/
python3 -m pyftpdlib -d ~/Documents/Mine/ -p 21
python3 -m pyftpdlib -d ~/Documents/Mine/ -w
python3 -m pyftpdlib -d ~/Documents/Mine/ -u sharefile -P markjour.com

# -h, --help
# -i ADDRESS, --interface=ADDRESS
# -p PORT, --port=PORT
# -w, --write
#     grants write access for logged in user (default read-only)
# -d FOLDER, --directory=FOLDER
# -n ADDRESS, --nat-address=ADDRESS
#     the NAT address to use for passive connections
# -r FROM-TO, --range=FROM-TO
#     the range of TCP ports to use for passive connections (e.g. -r 8000-9000)
# -D, --debug
# -v, --version
# -V, --verbose
# -u USERNAME, --username=USERNAME
# -P PASSWORD, --password=PASSWORD

TFTP Server

Trivial File Transfer Protocol
协议极其简单,只支持文件传输,常用于 PXE 网络引导。
两个知名协议:BOOTP 和 DHCP 的网络引导部分都包含 TFTP 协议相关内容。

  • RFC 783, The TFTP Protocol (Revision 1), 1981
  • RFC 1350, The TFTP Protocol (Revision 2), 1992

其他只需要提供简单文件传输的场景也可以使用 TFTP。

TFTP 和 FTP 之间没有继承关系,他们之间的主要差别:

  1. TFTP 是 UDP 协议,FTP 是 TCP 协议。
  2. TFTP 服务只需要建立一个连接(服务器 69 端口),而 FTP 使用两个连接:
    1. 控制连接,服务器 21 端口
    2. 数据连接,服务器随机端口
  3. TFTP 非常简单,支持的命令较少,比如:
    1. 不支持认证
    2. 不支持列出目录内容
    3. 不支持主动模式(FTP 上用的很少的功能)

遗憾的是,tftpy 和 fbtftp 两个包都不支持直接运行。

# python3 -m pip install tftpy --user
python3 -m pip install fbtftp --user

参照官方文档,可以这样运行:

import os

from fbtftp.base_handler import BaseHandler, ResponseData
from fbtftp.base_server import BaseServer


class FileResponseData(ResponseData):
    def __init__(self, path):
        self._size = os.stat(path).st_size
        self._reader = open(path, 'rb')

    def read(self, n):
        return self._reader.read(n)

    def size(self):
        return self._size

    def close(self):
        self._reader.close()


def print_session_stats(stats):
    print(stats)


def print_server_stats(stats):
    counters = stats.get_and_reset_all_counters()
    print('Server stats - every {} seconds'.format(stats.interval))
    print(counters)


class StaticHandler(BaseHandler):
    def __init__(self, server_addr, peer, path, options, root, stats_callback):
        self._root = root
        super().__init__(server_addr, peer, path, options, stats_callback)

    def get_response_data(self):
        return FileResponseData(os.path.join(self._root, self._path))


class StaticServer(BaseServer):
    def __init__(self, address, port, retries, timeout, root,
                 handler_stats_callback, server_stats_callback=None):
        self._root = root
        self._handler_stats_callback = handler_stats_callback
        super().__init__(address, port, retries, timeout, server_stats_callback)

    def get_handler(self, server_addr, peer, path, options):
        return StaticHandler(server_addr, peer, path, options, self._root,
                             self._handler_stats_callback)


def main():
    server = StaticServer(address='::', port=69, retries=3, timeout=5,
                          root='/var/tftproot',
                          handler_stats_callback=print_session_stats,
                          server_stats_callback=print_server_stats)
    try:
        server.run()
    except KeyboardInterrupt:
        server.close()


if __name__ == '__main__':
    main()

SFTP

有两种含义:

  • Simple File Transfer Protocol, RFC913, 实际没有使用过
  • SSH File Transfer Protocol, 或者 Secure File Transfer Protocol
    工作在 SSH 之上,比 SCP 提供更高多的文件管理操作。

绝大部分时候,提到 SFTP 都是指第二种。

虽然 SFTP 不复杂,但是需要实现 SSH 协议,能找到一些 Python 项目提供支持,但是由于一般的 SSH 服务器都提供 SFTP 功能,所以应该没有什么场景会使用到这些 Python 库。