`
isiqi
  • 浏览: 16490724 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

ftp协议实现多线程断点续传

阅读更多
ftp下载的好处我在这里就不多说了,许多工程会把ftp下载作为一个重要的功能来实现。微软提供的WinInet类可以利用下面这些函数:
InternetOpen;
InternetConnect;
GetCurrentDirectory;
SetCurrentDirectory;
FtpGetFile;

  很容易实现ftp的下载,网上关于这方面的文章也很多。但是要实现ftp的多线程下载,利用这些函数就显得有些牵强了。用socket根据ftp协议来开发将会变的十分灵活。下面我就逐步的讲解整个开发的过程:开发环境 BCB(组件模式),VC 环境下请自行稍作改动。看了这篇文章后对于BCB开发人员来说,不仅可以对 FlashGet 等软件的开发原理有一定的了解,特别是在开发组件方面也有很大的指导作用,请耐心的将它看完。很简单!!

首先介绍一下部分ftp协议:


图一 FTP服务示意图

  用户FTP和服务器FTP之间要传送文件,需要有两个连接:命令通道和数据连接,从名字上就可以看出命令通道是传送命令的,数据通道是用于传送文件。服务器与服务器之间的数据传送在此就不多作解释。
  主要用到的命令为:USER,PASS,TYPE,SIZE,REST,CWD,PWD,RETR,PASV,PORT,QUIT;

  • USER:参数是标记用户的Telnet串。用户标记是访问服务器必须的,此命令通常是控制连接后第一个发出的命令,有些主机还会要求口令和帐户。服务器可以在任何时间接收新的USER命令以改变访问控制和(或)帐户信息。这可以重新开始登录过程,所以传输参数不变,在进行中的文件传输在过去的访问控制参数下完成。
  • PASS:参数是标记用户口令的Telnet串。此命令紧跟USER命令,在某些站点它是完成访问控制不可缺少的一步。因此口令是个重要的东西,因此不能显示出来,服务器方没有办法隐藏口令,所以这一任务得由用户FTP进程完成。
  • TYPE:参数指定表示类型。有些类型需要第二个参数,第一个参数由单个Telnet字符定义,第二个参数是十进制整数指定字节大小,参数间以<SP>分隔。下面是格式:


    图二 TYPE参数示意图

    默认表示类型是ASCII非打印字符,如果参数未改变,以后只改变了第一个参数,则使用默认值。
  • SIZE:参数从FTP服务器上返回指定文件的大小。
  • REST:参数域代表服务器要重新开始的那一点,此命令并不传送文件,而是略过指定点后的数据,此命令后应该跟其它要求文件传输的FTP命令。
  • CWD:此命令使用户可以在不同的目录或数据集下工作而不用改变它的登录或帐户信息。传输参数也不变。参数一般是目录名或与系统相关的文件集合。
  • PWD:改变当前的工作目录。
  • RETR:开始传送指定的文件。(从REST参数指定的偏移量开始传送)
  • PASV:此命令要求服务器DTP在指定的数据端口侦听,进入被动接收请求的状态,参数是主机和端口地址。
  • PORT:参数是要使用的数据连接端口,通常情况下对此不需要命令响应。如果使用此命令时,要发送32位的IP地址和16位的TCP端口号。上面的信息以8位为一组,逗号间隔十进制传输。
  • QUIT:退出登录。

各个参数的具体用法举例如下:

USER sandy \r\n     //用户名为sandy登录
PASS sandy \r\n //密码为sandy
TYPE I \r\n
SIZE sandy.txt \r\n //如果sandy.txt文件存在,则返回该文件的大小
REST 100 \r\n //重新指定文件传送的偏移
CWD infor/ \r\n //获取当前的工作目录
PWD temp/ \r\n //改变当前的工作目录
RETR \r\n //开始传送文件
PASV \r\n //进入被动模式
PORT h1,h2,h3,h4,p1,p2 \r\n //进入主动模式,h1,h2,h3,h4为ip地址的4个部分。p1,p2是16进制的端口号。
下面介绍一下各个函数的使用顺序和一些应注意的地方:

  使用这些命令的前提条件是客户端和服务器端建立了连接。比如ftp服务器地址:192.168.1.81 ,端口:21。那么利用Winsock的API函数建立socket连接,然后使用USER,PASS登陆FTP服务器.需要下载文件,要确保文件必须在当前工作目录下,可以使用命令CWD和PWD。查看和更改当前的工作目录。使用SIZE命令获取文件的大小。我们想要多线程下载那么就要求服务器支持该功能。一般我们都会在开头先使用REST命令判断该ftp站点是否支持多线程下载。PORT和PASV两个命令是用来建立数据连接的。他们的主要区别是:PORT需要你指定一个ip地址和端口与服务器建立连接。PASV命令服务器会返回h1,h2,h3,h4,p1,p2样式 的数据供客户端连接。等数据连接建立后,就可以了使用REST,RETR进行多线程和断点续传文件下载了。
  上面讲解了一点ftp下载的基本知识,下面主要介绍的是断点续传的文件保存技巧。
若要讲断点续传的文件保存方式至少可以说出10种,但是各种方法都有利有弊,下面主要介绍一种我在工作中常常使用的一种文件保存方式:比如要下载一个364544字节的文件,文件名为:namelock.avi。因为要断点续传,所以 在下载的过程中必须得保存文件的大小,已经下载的文件的大小和各个线程的任务。有两种方法:一、可以产生两个文件:内容文件和配置文件。二、只需一个文件:把配置文件的数据加载到内容文件的末尾。这两个都不失为好方法。我使用的是前一种,因为我水平有限,(对于临界资源的访问总是不能做到互坼,老出问题。)。这里 的后缀名希望大家要把它放在心上,后缀名是个象征性的东西。就拿我们funinhand(广州富年电子科技有限公司)公司来说,拥有自己的MPEG编码、解码技术,比如原来5m的一首mp3歌曲,通过编码可以 转换成500K左右的.fun文件(funinhand的前三个字)。再利用我们自己的解码播放器边下载边解码边播放, 音质和mp3不相上下。真正实现了手机上的流媒体技术。受到国内外高科技大公司的信赖。(不好意思,这里有点像做广告了。)讲这些的另外一个企图是这样的:内容文件所使用的后缀名是我女朋友的英文名(namelock)的前三个字母.nam 。配置文件使用的是我自己的英文名(sandy)的前三个字母.san 。所以说写程序也可以很浪漫,因为这,女朋友又给了我的月生活零用钱增加了几元,哈哈(大家也可以效仿)。言归正传,这两个文件严格意义上来讲是临时文件,当文件下载完毕的时候,namelock.avi.nam内容文件应该改名为:namelock.avi。namelock.avi.san配置文件也应该及时的删除。
  FTP多线程下载技术部分:前面我介绍了文件的保存技巧,主要也是为了多线程服务。现在有个namelock.avi文件需要下载。文件的大小为:364544字节。要用8个下载线程。 第一步:将namelock.avi文件分成8个子模块。这里要注意的地方是我所说的分成8个字模块,并不是把文件的内容分别存放到8个不同的缓冲区里。而是生成8个不同的文件偏移量。很多时候程序员为了偷懒往往容易一次性讲文件读入内存,这样带来的后果是不堪设想的。一个比较理想的方法是这样的。
bool DealFile(string fileName)   //随便写个函数说明
{
FILE *file;
DWORD fileSize ,pos;
int readLen ; //MAX_BUFFER_LEN 在头文件里定义,这里能够保证数据不丢失,也不至于内存逸出
char *buffer = new char[MAX_BUFFER_LEN]; file = fopen(fileName.c_str(),"r+b");
  if(file == NULL) return false;
fseek(file,0,2);
fileSize = ftell(file); //取得文件的大小
fseek(file,0,0);
do{
readLen = fread(buffer,sizeof(char),MAX_BUFFER_LEN,file);
if(readLen > 0)
{
pos += readLen;
//对读取的文件做处理
}
}while(pos < fileSize); //循环读取文件
 delete[] buffer;
fclose(file); //释放资源
return true;
}

  8个线程下载文件时,都要对内容文件和配置文件进行读写。这样如果没有处理好,很有可能会造成访问文件失败,我定义了一个全局变量FileLocked,如果FileLocked=true说明文件正在被某个线程访问。所以使用Sleep(10)睡眠等待。当某个线程进入读写文件时必须设置FileLocked = true;访问文件完毕必须将FileLocked = false;这样就能很好的控制各个线程对文件的访问了。(对临界资源的访问有API提供了很多很好的解决方法,请查阅)。
  8个下载线程同时下载文件时,完成部分下载是随机的。那么怎么样把随机的文件数据按照偏移量正确的写入文件呢?我是这样实现的,当要下载文件namelock.avi时,首先查找文件namelock.avi.san配置文件是否存在。如果存在,说明上次已经下载过部分该文件,就可以断点续传了。如果没有找到该文件,那么生成和该文件的大小一样大的文件,文件里所有的数据都为0,(可以使用函数memset(buffer,10000,''0''))和一个配置文件。然后利用fseek函数将数据正确的覆盖原先的0;接下来要介绍一写配置文件的格式了。很简单,配置文件的内容主要包括:文件在本地保存的绝对路径、文件的大小、线程的个数、已经下载的文件大小,各个线程的任务(在原始文件起始位置和结束位置,中间使用''-''分开);如:

D:\mm\namelock.avi       //文件保存在这里  
364544                    //文件大小
5                         //有5个线程在下载
0                         //已经下载了0字节
0-72908                   //线程1的下载任务
72908-145816              //线程2的下载任务
145816-218724             //线程3的下载任务
218724-291632             //线程4的下载任务
291632-364544             //线程5的下载任务

以上是开始下载时的各个线程的任务分配。

D:\mm\namelock.avi
364544
5
113868
72908-72908
113868-145816
145816-218724
218724-291632
291632-364544
以上是某一时刻各个线程的任务分配情况。
  各个线程任务分配是这样实现的。在开始下载时,文件平均分成若干块进行下载。如第一个线程一开始的任务是从文件的0位置开始下载一直到72908位置处。线程1每次下载一块数据后就要调整任务,如第一次下载了20800字节的数据,那么线程1的任务将改为:20800-72908。如此下去,直到任务为72908-72908时表示线程1完成了当前的下载任务。此时,线程1就分析各个线程的任务,找出任务最为繁忙的一个线程:如线程3:14816-218724。那么线程1就自动去调整任务,拿50%的任务来再次下载。周而复始直到各个线程都完成任务。不过这里有一点需要注意:为了避免重复下载部分数据,在调整任务的时候,起始的文件便移量必须加上接受缓冲器的字节数,因为如前面所举的列子来看。线程1和线程3在平衡负载的时候,线程正在下载数据,如果所剩的数据比接受缓冲器的大小还小,线程1和线程3的部分下载数据将会重复。
  在调整任务和分析任务的时候,会发现一个问题。就是读取文件数据太过频繁。于是我用了一个数据结构。在下载文件的过程中始终打开配置文件,这样速度提高了很多。在文件下载完毕后关闭文件。数据结构如下:
typedef struct FromToImpl{
    DWORD from;               //任务起始位置
    DWORD to;                 //任务结束位置
}m_fromTo;
typedef struct InfroImpl{
    String fileLoad;           //文件保存位置
    DWORD fileSize;            //文件大小
    int threadCnt;             //下载线程数
    DWORD alreadyDownloadCnt;    //已经下载的文件大小
    FromToImpl *fromToImpl;     //各个线程的任务描述
}m_inforImpl;
分享到:
评论

相关推荐

    商业编程-源码-ftp协议实现多线程断点续传.zip

    实现FTP多线程断点续传通常涉及创建FTP客户端类,处理控制连接和数据连接,管理线程,以及实现断点续传逻辑。开发者可能需要使用如Python的`ftplib`库,Java的`java.net.Socket`和`java.net.FTPSClient`,或C#的`...

    VC中ftp协议实现多线程断点续传

    在VC++环境中实现FTP协议的多线程断点续传是一项技术挑战,涉及到网络编程、FTP协议的理解以及多线程的运用。以下是一份详细的知识点解析: 1. FTP协议基础: FTP(File Transfer Protocol)是一种用于在网络上...

    ftp协议实现多线程断点续传的代码 c++ builder

    本项目利用C++ Builder开发环境,实现了FTP协议下的多线程断点续传功能,这在大文件传输时尤其有用,可以提高传输效率并能应对网络中断的情况。 在C++ Builder中,我们可以使用 Indy 或 WinInet 库来实现FTP协议的...

    ftp协议实现多线程断点续传功能 源代码

    FTP(File Transfer Protocol)协议是Internet上用于在主机之间传输文件的标准协议,它允许用户从远程主机...通过学习和理解这些源代码,开发者可以深入理解FTP协议、多线程编程以及如何结合两者来实现断点续传功能。

    VC中ftp协议实现多线程断点续传.rar_C++builder _FTP 多线程_ftp_vc ftp_断点续传

    实现FTP多线程断点续传的关键步骤包括: 1. **连接服务器**:使用C++Builder中的TIdFTP组件建立到FTP服务器的连接,设置用户名、密码以及工作目录。 2. **检查已下载的文件**:在开始下载前,检查本地是否存在部分...

    vc下ftp协议实现多线程断点续传源代码

    1.采用了多线程技术,速度明显高于同类软件. 2.支持多文件同时传送. 3.支持段点继传,也就是说文件可分N次传送. 4.分服务端和客户端,服务器支持多客户. 5.在传送过程中可实实对话,有聊天功能. 6.为了提高效率,本软件做...

    java ftp 多线程 断点续传等知识

    在Java中,我们可以使用`java.net`包中的`Socket`类来实现基本的FTP功能,但更常见的是使用Apache Commons Net库,它提供了更丰富的FTP功能,包括多线程和断点续传。 FTP服务器是运行FTP服务的计算机,它存储着可供...

    FTP、HTTP 多线程断点续传下载文件.rar

    标题中的“FTP、HTTP 多线程断点续传下载文件.rar”暗示了这是一个关于网络协议(FTP和HTTP)在实现多线程下载时如何支持断点续传功能的资源包。这个压缩文件可能包含了一个或者多个示例程序、文档或教程,用于解释...

    java实现FTP多线程断点续传

    ### Java实现FTP多线程断点续传:深入解析与技术要点 在现代软件开发中,数据传输是一项基本且关键的任务,特别是在处理大文件时,断点续传功能显得尤为重要。断点续传允许在网络连接中断后恢复传输,避免了重新...

    ftp.rar_c# ftp多线程_ftp_ftp 断点续传 多线程_ftp 断点续传 实现_ftp 线程

    在压缩包内的“www.pudn.com.txt”文件可能包含了一些关于FTP协议和实现细节的参考资料,而“ftp协议实现多线程断点续传”可能是一个源代码示例,建议参考这些材料进一步了解和实现上述功能。 总之,C#中的FTP多...

    自己收集的多个Java FTP断点续传的例子源码

    java实现FTP多线程断点续传,上传下载! - java学习与交流 - j2ee学习网 - j2ee学习网 (2012年5月21日) 用 Java 实现断点续传 (HTTP) (2012年5月21日) Java写的支持断点续传的FTP--crybaby的博客 (2012年5月21日) ...

    VC FTP、HTTP 多线程断点续传下载文件.rar

    VC FTP、HTTP 多线程断点续传下载文件,在断点下载时,可获取远程站点信息,如:是否支持断点续传、要下载的文件大小和创建时间等。可设置下载的线程数、下载任务的线程函数、多线程断点续传下载一个文件、关于BOOL ...

    VC++ FTP、HTTP 多线程断点续传下载文件源码.rar

    该压缩包文件“VC++ FTP、HTTP 多线程断点续传下载文件源码.rar”包含了一套基于VC++实现的源代码,用于通过FTP和HTTP协议进行多线程断点续传下载文件。这一技术在现代软件开发中非常重要,尤其是在处理大文件或网络...

    HTTP及FTP多线程下载和断点续传

    本文将深入探讨这两个协议在实现多线程下载和断点续传方面的技术细节。 首先,HTTP(超文本传输协议)是用于从Web服务器传输数据的标准协议。在多线程下载中,HTTP允许客户端同时发起多个请求来获取同一文件的不同...

    FTP、HTTP 多线程断点续传下载文

    在本文中,我们将深入探讨如何利用VC++编程语言实现FTP和HTTP的多线程断点续传下载功能。 FTP协议是互联网上最早被定义的协议之一,主要用于在客户端与服务器之间进行文件的上传和下载。它提供了两种工作模式:主动...

    java FTP多线程 批量 断点续传

    Java FTP多线程批量断点续传是一种在Java编程中实现高效、稳定文件传输的方法,尤其适用于大文件的上传和下载。在这个过程中,我们利用FTP(File Transfer Protocol)协议,结合多线程技术和断点续传功能,可以显著...

Global site tag (gtag.js) - Google Analytics