一、前言
断点续传,顾名思义就是在文件传输过程中由于网络中断或其它原因造成传输中断,这时文件只传输了一部分,在下次在传输时能够接着前面的传输进度继续进行。在网络状况不稳定,特别是Internet环境下,特别有用。目前的通用下载工具,不论是HTTP下载工具,如NetAnts、FlashGet等,还是FTP下载工具,如CuteFTP等都具备断点续传功能。
二、方案选择
准省级任务调度系统的文件传输任务相当于一个FTP客户端,可以向FTP服务上载文件,也可以从FTP服务器下载文件。由于FTP协议已经是一种标准的协议,目前已经有许多成熟的FTP软件,也有许多实现FTP协议的方法。使用C++ Builder写FTP客户端应用程序的方法主要有:使用Microsoft Win32 Internet API和使用FTP组件。
2.1 Microsoft Win32 Internet API
在Internet互联网应用程序支持上,Microsoft提供了Win32 Internet API函数支持,此类型的API是由WININET.DLL动态链接函数库所提供的。
Win32 Internet API(即 WinInet)帮助实现对 gopher、FTP 和 HTTP 等常用 Internet 协议的访问。使用 WinInet 可以在较高编程级别上编写 Internet 客户端应用程序,且无须处理 WinSock、TCP/IP 和特定 Internet 协议的细节问题。WinInet 为所有这三种协议提供了一组一致的函数,并采用常用的 Win32 API 接口。该一致性使当基础协议改变(例如从 FTP 改为 HTTP)时所需做的代码改动减到最小。
采用Win32 Internet API实现FTP客户端有以下优点:
n 从 FTP服务器读取信息像从硬盘读取文件一样容易。
n 使用 Win32 Internet 函数的开发人员不需要熟悉 TCP/IP 或 Windows Sockets,对于许多常见的操作,开发人员不需要知道他们所使用的具体协议的细节。但开发人员仍可直接使用 WinSock 和 TCP/IP 协议在套接字级别编程,
在以前的准省级系统中的FTP文件传输及IC卡管理系统FtpStation就是采用这种方法实现的。但是在使用的过程中发现以下问题:
n 网络状况不稳定时,文件没有完全上传,但系统仍然报告文件上传成功。
n 网络状况不稳定时,文件传输过程中断,任务调度系统的文件传输任务被阻塞挂起,造成以后的文件无法上传,只能重新启动任务调度系统才行。
n Win32 Internet API中未提供支持断点续传的函数,如果需要实现此功能,必须在Winsock级别进行编程,程序员需要了解很多的FTP协议及编程细节。自己编写续传方法,可靠性难以保证。
2.2 FTP组件
FTP协议是一个标准的、成熟的协议,目前很多开发工具中都包含了FTP组件,它们在更高的层次上进行封装,提供丰富的方法和属性,使得程序员可以在无需了解FTP细节的情况下轻松开发出强大的FTP客户端和FTP服务器软件。在C++ Builder 6中包含了两种组件可以用来开发FTP应用程序:TNMFTP和Indy。此外,还有许多成熟的第三方组件,如ICS(Internet Component Suite)等。
1) TNMFTP控件
TNMFTP控件支持FTP协议,使用该组件要求机器上有32位的TCP/IP协议栈 WSOCK32.DLL。在Windows95及以后的操作系统都有该DLL。TNMFTP控件使用异步工作模式,采用事件触发机制,并提供了丰富的属性和方法,支持代理和断点续传,可以用它来开发一个强大的FTP客户端程序。以前的数据采集器系统(准省级前身)就是采用该组件实现文件传输的。但是,在使用的过程中,该组件也存在不足:
n 它采用的是异步工作模式,这在开发交互式FTP客户端程序时特别有用,但在准省级任务调度系统中,FTP任务实现为一个DLL,不提供用户界面,由主程序调度执行,无需用户干预。如果采用异步工作模式,需要复杂的控制来保证各步骤的顺序执行。
n 在使用过程中发现该组件存在内存泄漏的问题,网上也有许多人指出该组件存在bug,borland公司不再对该组件进行支持。这个问题对于需要长期稳定运行的系统来说是非常严重的。
n 在使用该组件时,发现传送大文件时不稳定,当文件大小超过100M时,经常会出现传输中断的情况。
2) Indy组件
Indy组件是一组开放源码的组件,使用Delphi语言编写,可用于C++ Builder和Delphi应用程序。目前indy已经推出10.0版本,已经发展得很成熟,在新版本的C++ Builder和Delphi中均包含了该组件。Indy组件采用阻塞式同步工作模式,提供了一组实用且使用简单的属性和方法,并有丰富的在线帮助和示例。但是在试用该组件的过程中发现有无法解决的问题。
n 该组件未提供支持断点续传的方法,并且当取消文件传输时,以前传输的内容并未真正传送到FTP服务器上。
n 不支持代理服务器,未提供设置代理服务器的属性或方法。
3) ICS(Internet Component Suite)
ICS也是一个开放源码的组件,使用Delphi语言写成,可用于各版本的C++ Builder和Delphi。ICS可以采用同步工作模式,也可以采用异步工作模式。每种方法均可工作在同步和异步模式。并且它提供了断点续传的方法和对代理服务器的支持。采用该组件的不方便之处在于没有在线帮助,但它提供了丰富的示例程序,必要时可以察看源码,了解各方法的如何使用。
三、方案设计
让FTP文件传输具备断点续传功能,除了客户端需要采用一定的编程技巧外,FTP服务器也必须支持断点续传。在本方案中,主要讨论客户端的实现方法,如果服务器不支持断点续传,则应该屏蔽该功能。
3.1数据结构和关键类
ICS组件中的TFtpClient类提供了RestGet和RestPut方法,分别用来续传(上载和下载)。但是在使用这两个方法前,必须先指定从哪个位置续传。也就是说,我们需要记录断点的位置,即上次上传多少字节后传输中断。因此定义以下数据结构来保存文件传输信息,如图1所示:
图1 文件传输信息类图
其中:
u ID:唯一标识,无实际意义。
u Host:FTP服务器名或IP地址。
u RemoteDir:FTP服务器的工作路径。
u RemoteFileName:FTP服务器上的文件名。
u LocalFileName:本地上的文件名,包含路径。
u FileSize:上次文件传输的字节数。
u Direction:传输方向,0-上传,1-下载。
u Flag:正常退出标志,0-中断,1-非正常中断。断点续传中关键是需要知道上次文件传输了字节,但是如果程序异常退出时,可能未能正确记录上次传输的字节数,这时需要从头开始传输。
文件传输记录保存在文件中。因此该类还提供了以下方法:
u Serialize:序列化方法,将文件传输信息序列化到文件流中。
u GetTransferInfos:从文件中加载文件传输记录到链表中,链表中的每一项为一条传输记录。
准省级任务调度系统每天会启动文件传输任务,如果每次文件传输都记录下来,这个文件就会越来越大。因此,如果文件传输完毕,记录就从链表中移除,文件中只记录需要续传的文件。
3.2流程图
图2 文件传输流程图
注:在文件传输过程中可能会由于网络原因或人为终止,这时传输过程会终止。在文件传输的过程中会触发TFtpClient组件的OnProgress事件,该事件具有参数,表明目前已传送的字节数。