在协议级别暂停和恢复。(您可以用任何语言实现)






4.64/5 (18投票s)
2002年10月10日
5分钟阅读

200761

5563
有没有想过一些流行的下载工具是如何能够中断下载、断开网络连接,然后在以后重新连接并从之前中断的地方继续文件传输的。
引言
有没有想过一些流行的下载工具和 FTP 客户端是如何能够中断下载、断开网络连接,然后在以后重新连接并从之前中断的地方继续文件传输的。我之前写的一个 FTP 客户端就想实现这个功能(看看这个),但我却一无所知。Microsoft 没有直接的 API 支持。我找到了一些第三方支持,但要花钱。所以,我到处搜寻,并写了自己的实现。我的方法可能不代表标准,但它适用于几乎所有的 FTP 服务器。
我过去一直在阅读这个网站上的内容,我认为是时候回馈了。因此,我决定将这些内容整理在一起,写下我的第一篇文章。如果我没做好,请随时问我问题 :)。我还准备了一个可用的 C++ 示例来演示我的想法。只要您能以某种方式向服务器发送和接收 FTP 命令,您就可以用任何您喜欢的语言来实现。如果您重新使用代码,我很乐意接受您的使用或修改,但如果您不署名,我也不强求。
目录
一些热身理论
如今,大多数 FTP 服务器都支持 RESTART (REST) 命令。 (请参阅此 W3C 链接,了解更多关于其他 FTP 命令的信息)。REST 命令的目的是告诉 FTP 服务器设置一个文件传输需要重新开始的标记点。
以编程方式开始下载、暂停然后再次恢复
举个例子,假设您正在下载一个文件:MyHugeFooFile.zip。
- 通常,您会向 FTP 服务器发送一个 RETRIEVE (RETR) 命令来下载文件 MyHugeFooFile.zip。将从服务器接收到的数据存储到一个临时文件,例如 Temp_MyHugeFooFile.zip。因此,任何时候下载中断,临时文件的大小就是到目前为止已成功传输的 MyHugeFooFile.zip 的实际有效数据量。
- 假设突然 ISP 连接断开,或者 FTP 服务器宕机,或者您的 FTP 客户端崩溃,或者您手动停止了下载。
- 下次您想重新开始下载时,读取临时文件的大小 (即到目前为止已下载的有效数据量),并将文件指针移到临时文件的末尾,这样后续下载就会从末尾开始追加数据。
- 现在,向 FTP 服务器发送一个 REST 命令,并将临时文件的大小作为参数。 (一个典型的语法是 REST 250,如果临时文件的大小是 250)。FTP 服务器将发送一个类似“从字节 250 开始恢复…”的响应。
- 现在您可以再次发送 RETRIEVE (RETR) 命令来下载文件 MyHugeFooFile.zip,FTP 服务器将从字节偏移量 251 开始发送数据。
- 现在,您需要负责将来自服务器的数据追加到不完整的文件 Temp_MyHugeFooFile.zip 中,这样您就准备好了。
- 传输完成后,在 WINDOWS 上将临时文件重命名为实际文件名。使用 C++,这通常看起来像
RenameFile(Temp_MyHugeFooFile.zip, MyHugeFooFile.zip);
完成。
以编程方式开始上传、暂停然后再次恢复
对于上传场景,概念上您做的事情类似,但有几点不同:
- 首先发送一个 STORE 命令。
- 连接中断。
- 通过发送 SIZE 命令或使用您喜欢的任何方法来读取 FTP 服务器上不完整临时文件的大小,总有很多种方法。
- 将本地文件定位到从服务器接收到的大小处,这样您将从下一个位置开始读取和发送数据。
- 发送一个 REST 命令。这样 FTP 服务器将设置一个标记点,以便从 REST 命令中传递的位置开始追加数据。
- 再次发送 STORE。
- 完成后,在 FTP 服务器上重命名文件。一个典型的 winInet 函数将是
FtpRenameFile(hConnect, Temp_MyHugeFooFile.zip, MyHugeFooFile.zip)
,或者使用您喜欢的方法,例如直接发送 RENAME FROM (RNFR) & RENAME TO (RNTO),这些方法显然比 WinInet 快。 - 完成。
以编程方式确定特定的 FTP 服务器是否支持暂停和恢复。
三个简单的步骤
- 连接到 FTP 服务器后,尝试发送一个带有 0 (零) 作为参数的 REST 命令。
- 如果命令失败或服务器返回类似“命令不支持”的信息,则表示该服务器不支持暂停和恢复。
- 如果 FTP 服务器返回一个类似“从字节 0 开始恢复”的响应,则表示服务器支持暂停和恢复。
现在,如果您刚开始编写代码,您可能会问,如何向 FTP 服务器发送这些命令。答案有很多种。原始套接字是一种,WinInet 是另一种。在我的示例代码中,我使用了 WinInet 的 API FtpCommand 来直接向 FTP 服务器发送命令。
关于 C+ 示例
我用 VC++ 编写了这个示例,演示了如何使用 WinInet 来实现暂停和恢复。为了代码审查的目的,请不要在意我的编码风格,将其视为一个我不到一个小时就写出来的示例。代码几乎是不可重用的,只有这个想法是可重用的,所以我没有对其使用设置任何限制。首先构建并运行示例,不要忘记将其链接到随示例一起提供的 wininet.lib。
此示例演示了下载暂停和恢复下载的场景。当您运行示例时,单击下载按钮开始下载,并注意显示进度的进度条。中途停止,然后重新开始。请注意,下载将从上次停止的位置重新开始。单击开始,并根据需要多次单击,直到下载完成。请注意,下载是硬编码从 ftp://ftp.gnu.org/ 开始,文件始终是根目录下的 find-ls.txt.gz。
示例本身是自我解释的,但如果您有任何疑问,请随时提问,我会尽我所知回答。