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 使用两个连接:
  3. 控制连接,服务器 21 端口
  4. 数据连接,服务器随机端口
  5. TFTP 非常简单,支持的命令较少,比如:
  6. 不支持认证
  7. 不支持列出目录内容
  8. 不支持主动模式(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 库。

如果你有魔法,你可以看到一个评论框~