计算机应用研究
APPLICATION RESEARCH OF COMPUTERS
2000 Vol.17 No.3 P.78-79




Linux中基于缓冲式多线程的文件传输程序
裴开俊　张帆　朱明富
摘　要：介绍文件传输中用到的HTTP与FTP协议，讲述如何利用多线程及缓冲区编写文件传输程序。
关键词：HTTP FTP 多线程 缓冲区
1　引言
　　现在，免费操作系统Linux使用范围越来越广，由于性能稳定安全，源代码公开，又可自由获取免费的应用软件，Linux操作系统得到了许多电脑爱好者的青睐。在电脑的应用中，通过FTP和HTTP站点下载软件是很常见的，但如果连接该站点的人很多，下载的速度会很慢，为加快下载速度，通常利用多线程下载的方法。目前，Windows操作系统下的快速下载软件较多，如网络蚂蚁、网络吸血鬼等，而基于Linux操作系统的却几乎没有，本文作者便开发了一个缓冲式多线程的文件传输客户端程序。
2　FTP和HTTP协议介绍
2.1　FTP协议
　　FTP(文件传输协议)类似于SMTP(简单邮件传输协议)和POP3(邮局协议)，它也使用NTV ASCII命令串和应答码，但FTP使用两个TCP连接来完成文件传输操作。这两个TCP连接分别是控制连接和数据连接。控制连接是一典型的客户/服务器设置，TCP服务器在一周知端口(一般是端口21)执行被动打开，并等待客户连接。相应地，TCP客户也在这一端口与TCP服务器联系，在程序协调下完成一个典型的TCP连接。控制连接在整个TCP处理过程中保持主动状态，客户和服务器通过控制连接交换NVT ASCII命令串及应答码。TCP建立了一个分离的数据连接来进行文件传输操作。图1显示了一个TCP操作的典型配置。

图1　FTP操作的典型配置
　　文件传输协议包括三十多条基于FTP程序用来完成文件传送操作的命令。这些命令分为三类：访问控制命令、传送参数命令及服务命令。访问控制命令传送诸如向服务器标识用户身份或者是告诉服务器用户期望访问的位置(或目录)的信息。传送参数命令允许客户定义FTP选择：文件类型、文件格式、文件结构、传送模式。FTP命令定义了用户期望执行的文件传送操作。下面仅举几个本程序主要用到的命令。
　　USER(用户名)：当用户访问一个FTP站点时必须提供制定的用户名和口令，USER命令向服务器发送用户名。
　　PASS(口令)：该命令向服务器发送用户口令。
　　CWD(改变工作目录)：在FTP服务器上对一个文件进行操作，必须进入该文件所在的目录，否则服务器会告诉你文件不存在。CWD命令可以使用户转到远程主机上的不同目录。
　　PASV(被动)：正常情况下，FTP客户告诉服务器与客户主机的哪个端口连接，然后服务器启动数据通道的TCP连接。不过，客户可以用PASV命令来让服务器的数据传输过程在一个数据口上(不是缺省的数据口)上侦听并等待连接，而不是在传送命令的接收上启动一个连接。
　　REST(重启动)：这是本程序中用到的最重要的命令，它可以让用户从文件中间某一部分开始下载。RETR(检索)：本命令用来下载程序。
2.2 HTTP协议
　　同FTP协议相比，HTTP协议要简单一些，客户同服务器HTTP端口连接后，向服务器送GET和HOST命令就可以下载文件，本程序主要用到的命令有：
　　GET：发送下载请求。
　　HOST：同GET命令联用，告诉要下载文件所在的服务器地址。
　　RANGE：下载文件中的某一段。
3　程序结构
3.1 配置文件($HOME/.ftp.config)
　　1)下载线程数(NUMOFHREAD)，下载时开的线程数，1～10，缺省5。
　　2)缓冲区大小(SIZEOFBUF)，下载时对应每个线程开的缓冲区，1～l024(K)，缺省64(K)。
　　3)缓冲区数(NUMOFBUF)，缓冲区的数量，1～l00，缺省为10。
　　4)日志文件(LOGFILE)，日志文件位置，缺省为./ftp.log。
　　5)缓冲区刷新线程等待时间(FLUSHTIME)，1～l024(ms)，缺省100(ms)。
3.2 数据结构
　　由于各线程工作独立，它们所处的状态也不相同，往一个线程传递多个参数比较麻烦，较好的解决方法是建立结构。每个缓冲区和下载线程的参数对应一个结构链表。同时，缓冲区和下载线程结构写有它们的状态，管理线程可根据状态协调工作。
　　1)缓冲区数据结构
typedef struct {
　DLBUFFER *prebuffer；　　　　　　　　　/*上一个缓冲区*/
　long bufstatus；　　　　　　　　　　　/*缓冲区状态*/
　char *p_buffer；　　　　　　　　　　　/*缓冲区指针*/
　DLBUFFER *nextbuffer；　　　　　　　　/*下一个缓冲区*/
} DLBUFFER；
　　2)下载线程对应的数据结构
typedef struct {
　STCTHREAD *nextthread；　　　　　　/*下一个线程*/
　long threadstatus；　　　　　　　　/*线程状态*/
　long totalbytes；　　　　　　　　　/*总字节数*/
　long dlbytes；　　　　　　　　　　/*已经完成的字节数*/
　char *rmthost；　　　　　　　　　　/*远程主机名*/
　char *filename；　　　　　　　　　/*文件名*/
　long startdl；　　　　　　　　　　/*开始下载的文件位置*/
　DLBUFFER *p_buffer；　　　　　　　/*对应的缓冲区指针*/
　int *p_socket；　　　　　　　　　/*线程对应的socket端口*/
　int *p_dsocket；　　　　　　　　　/* if ftp, data socket*/
　int protocol；　　　　　　　　　/*http or ftp*/
} STCTHREAD；
3.3　程序中的多线程
　　为了提高下载速度，本程序采用了缓冲式多线程连入服务器并行下载文件各段的方法。主要工作由三种线程完成：
　　1)下载线程(DLT，Down load thread)
　　建立Socket联接，根据任务由指定的文件位置将数据填充到缓冲区里。对于HTTP协议，只需读取向服务器发“Range”命令后获取的返回内容即可，对于FTP协议，由于不能直接获取文件中的某一块，要先向服务器发送“REST”命令，从文件中的某一位置开始下载，读取制定的长度后，立即将连接服务器FTP数据端口的Socket关闭，然后将线程的状态设置为空闲。在管理线程中，服务器FTP数据端口将重新连接。
　　2)缓冲区刷新线程(BFT，Buffer flush thread)
　　将填满的缓冲区里的数据刷新到硬盘上。每过一定的时间(FLUSHTIME)检查一遍缓冲区，如遇到完成任务的下载线程，则执行刷新操作。之所以开缓冲区刷新线程，而不直接在下载线程中将缓冲区的数据刷新到硬盘上，是为了避免几个下载线程同时对硬盘上的一个文件进行操作，这样会造成文件读写错误，下载线程下载完文件一块后，就去下载另外一部分，而由一个缓冲区刷新线程负责所有的客户端文件操作，就避免了以上问题的出现。
　　3)管理线程(MGT，Manage thread)
　　负责开新的下载线程，写日志，并分派任务给新线程。
　　管理线程将下载文件分成几段，然后命令各个下载线程独立同服务器相连接，每个下载线程负责下载制定的一块文件，由缓冲区刷新线程将这些数据块写到客户端的文件中去，管理线程就是协调这些线程有序地工作。管理线程不停地监视各下载线程和缓冲区的状态。下载线程的状态有空闲、连接、已连接、下载中和下载完毕等状态，缓冲区有空闲、下载中和下载完毕等状态。当一下载线程下载完毕后，管理线程看有没有空闲的缓冲区，如有，则让该线程下载一段文件放在空闲的缓冲区中，另外，如有下载完的缓冲区，则让缓冲区刷新线程将该缓冲区的内容刷新到硬盘上。对于未连接的下载线程，管理线程还要负责连接。如果管理线程发现所有文件段都下载完毕，就关闭其它线程，退出程序。
3.4 程序主流程
　　1)确定连入服务器的方式，即客户是直接连入服务器，还是通过代理连接服务器，如是后者，则须调用代理连接处理函数。
　　2)确定缓冲区数目
　　首先获得下载文件的大小。对于FTP协议，向服务器控制端口发送SIZE命令可获得文件大小，对于HTTP协议，先向服务器发GET命令，然后读取返回的表头部分，其中“Range-Type”所在行就含有文件大小。由于通过配置参数可知缓冲区长度，用文件大小除以缓冲区长度即可获得缓冲区数目。
　　3)读取配置参数，分配缓冲区空间。
　　4)打开管理线程，在管理线程中打开日志文件，将下载文件分成若干段，分配下载参数链表。
　　5)打开缓冲区刷新线程。
　　6)管理线程协调各线程工作，如发现文件下载完毕，则关闭Socket连接和各线程并退出程序。
3.5　运行环境
　　本程序有两种运行环境：Shell终端和X Window。在Shell环境下，用户要输入下载文件的协议(FTP或HTTP)，服务器地址及文件路径和名称。可直接输入URL，例如ftp://202.114.2.1/pub/unix/samba-2.0.3.tar.gz。在X Window环境下，程序进入窗口界面，操作与Microsoft Windows中的常用下载程序基本相同。
　　X Window下的界面用GTK(GIMP Toolkit)开发，GTK基本上是物件导向应用软件程式设计界面(API)，将Xlib功能包装起来。用GTK编写X Window程序比普通的Motif编程方便、效率高。
裴开俊(华中理工大学 武汉 430074)
张帆(华中理工大学 武汉 430074)
朱明富(华中理工大学 武汉 430074)
参考文献
1 Internet网络编程. 北京：机械工业出版社
2 RFC 765: FILE TRANSFER PROTOCOL(FTP)
3 RFC 2068: Hypertext Transfer Protocol-HTTP/1.1
收稿日期：1999年9月20日
