多线程下载技术

现在有个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:mmnamelock.avi       //文件保存在这里  

364544 //文件大小

5 //有5个线程在下载

0 //已经下载了0字节

0-72908 //线程1的下载任务

72908-145816 //线程2的下载任务

145816-218724 //线程3的下载任务

218724-291632 //线程4的下载任务

291632-364544 //线程5的下载任务


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

D:mmnamelock.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;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值