如何使 FTP 连接保持活动状态?

How do I keep a FTP connection alive?

我用 ftputil 从 FTP 服务器下载了一批文件。它引发了错误 ftputil.error.FTPIOError: [Errno 60] Operation timed out.

Documentation – ftputil

所述

keep_alive() attempts to keep the connection to the remote server active in order to prevent timeouts from happening. This method is primarily intended to keep the underlying FTP connection of an FTPHost object alive while a file is uploaded or downloaded. This will require either an extra thread while the upload or download is in progress or calling keep_alive from a callback function.

我从 callback 函数调用了 keep_alive

ftp_host.download(source, target, callback=ftp_host.keep_alive) 

但它引发了 ERROR __main__ keep_alive() takes 1 positional argument but 2 were given.

如何使 FTP 连接保持活动状态?

这不是您问题的直接答案,但它可能有助于您自己找到特定问题的答案。此外,ftputil 网站上的 ticket 更有助于调试问题。也就是说,我认为最好先在 Whosebug 上询问,因为您事先不知道问题是否简单。 :-)

由于FTP是一个状态协议,客户端和服务器不能在给定时间发送任意命令。允许的命令和可能的回复由连接所处的状态决定。另请参阅 RFC 959.

中的状态图

为了解决这个限制,ftputil 在幕后为每个远程文件对象 [1] 创建了一个新的 FTP 连接。使用这种方法,您仍然可以发送 chdir 之类的命令或在另一个仍在进行中时开始下载。但是,这意味着从服务器的角度来看,来自单个 FTPHost 对象的所有这些 FTP 连接都是独立的连接,因此这些连接中的每一个都可以在不同的时间超时,具体取决于各自连接的使用模式。

例如ftputil ticket 141,推测是FTPHost对象发起的主连接超时,而用于下载的连接仍然可用。

对于您的情况,找出哪个 基础连接超时(初始连接或远程文件连接)可能会有所帮助。您可以使用 ftputil.session.session_factory 创建启用 FTP 调试的工厂(参见 documentation)。

可惜60秒的超时时间很短,所以超时的机会比较多

特别是考虑到 FTP 连接超时的可能性,我的建议是以某种方式为 FTP 传输编写软件,以便您可以重新启动操作(最好使用新的 FTPHost 对象的健壮性)它被超时中断的地方。到目前为止,我还没有想出一种普遍解决超时问题的方法。在简单的情况下,您 可能 实际上直接使用 ftplib 会更好,尽管 ftputil 具有 ftplib 所没有的稳健性和延迟改进。使用 ftplib 不会使您免于超时,但至少您没有任何可能使调试更加困难的“隐藏”连接。


[1] 即是说,如果您在 ftputil 中关闭远程文件,则可以重用基础 FTP 连接,除非它没有超时。库在重新使用连接之前检查超时。

由于 ftputil 从服务器缓存大量信息以减少延迟,关于超时的情况更加复杂。例如,如果您调用 FTPHost.getcwd(),则当前目录是从缓存属性中检索的,而不是通过向服务器发送 PWD 命令从而重置超时。来自目录列表的统计信息通常也被缓存。