gusucode.com > 一个视频压缩并通过网络来传送的源代码 > 一个视频压缩并通过网络来传送的源代码/断点续传和多线程VC源码/code/THttpGetEx.cpp
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "THttpGetEx.h" #pragma package(smart_init) //--------------------------------------------------------------------------- AnsiString GetSystemTemp(void) { AnsiString T; char Tmp[1024]; if(GetTempPath(1024,Tmp)>0)T=Tmp; return T; } //--------------------------------------------------------------------------- __fastcall THttpGetEx::THttpGetEx(TComponent* Owner) : TComponent(Owner) { FHttpThreadCount=3; FHttpThreadCreated=false; FWorking=false; FFromBreakpoint=false; } //--------------------------------------------------------------------------- __fastcall THttpGetEx::~THttpGetEx() { delete []HttpThreads; } //--------------------------------------------------------------------------- namespace Thttpgetex { void __fastcall PACKAGE Register() { TComponentClass classes[1] = {__classid(THttpGetEx)}; RegisterComponents("Samples", classes, 0); } } //--------------------------------------------------------------------------- // 分配资源 void THttpGetEx::AssignResource(void) { FSuccesss=new bool[FHttpThreadCount]; for(int i=0;i<FHttpThreadCount;i++) { FSuccesss[i]=false; } // 输出文件名称 OutTmpFiles = new AnsiString[FHttpThreadCount]; AnsiString ShortName=ExtractFileName(FOutFileName); AnsiString Path=GetSystemTemp(); for(int i=0;i<FHttpThreadCount;i++) { OutTmpFiles[i]=Path+ShortName+"-"+IntToStr(i)+".hpt"; } // 建立线程 HttpThreads = new THttpGetThread *[FHttpThreadCount]; } //--------------------------------------------------------------------------- // 释放资源 void THttpGetEx::ReleaseResource(void) { delete HttpThreads; delete OutTmpFiles; delete FSuccesss; HttpThreads=NULL; OutTmpFiles=NULL; FSuccesss=NULL; FHttpThreadCreated=false; } //--------------------------------------------------------------------------- // 创建一个下载线程 THttpGetThread * THttpGetEx::CreateHttpThread(void) { THttpGetThread *HttpThread=new THttpGetThread(this); HttpThread->FromBreakpoint=FFromBreakpoint; HttpThread->URL=FURL; HttpThread->OnAbort=OnThreadError; HttpThread->OnError=OnThreadError; HttpThread->OnComplete=OnThreadComplete; HttpThread->OnGetFileSize=FOnGetFileSize; HttpThread->OnProgress=FOnProgress; HttpThread->OnStatusText=FOnStatusText; return HttpThread; } //--------------------------------------------------------------------------- // 创建下载线程 void THttpGetEx::CreateHttpThreads(void) { if(FHttpThreadCreated)return; FHttpThreadCreated=true; AssignResource(); // 取得文件大小,以决定各个线程下载的起始位置 THttpGetThread *HttpThread=CreateHttpThread(); HttpThreads[FHttpThreadCount-1]=HttpThread; int FileSize=HttpThread->GetWebFileSize(); // 把文件分成FHttpThreadCount块 int AvgSize=FileSize/FHttpThreadCount; int *Starts= new int[FHttpThreadCount]; int *Bytes = new int[FHttpThreadCount]; for(int i=0;i<FHttpThreadCount;i++) { Starts[i]=i*AvgSize; Bytes[i] =AvgSize; } // 修正最后一块的大小 Bytes[FHttpThreadCount-1]=AvgSize+(FileSize-AvgSize*FHttpThreadCount); // 检查服务器是否支持断点续传 HttpThread->StartPostion=Starts[FHttpThreadCount-1]; HttpThread->GetBytes=Bytes[FHttpThreadCount-1]; bool CanMulti=HttpThread->SetFilePointer(); if(CanMulti==false) // 不支持,直接下载 { FHttpThreadCount=1; HttpThread->StartPostion=0; HttpThread->GetBytes=FileSize; HttpThread->Index=0; HttpThread->OutFileName=OutTmpFiles[0]; }else { HttpThread->OutFileName=OutTmpFiles[FHttpThreadCount-1]; HttpThread->Index=FHttpThreadCount-1; // 支持断点续传,建立多个线程 for(int i=0;i<FHttpThreadCount-1;i++) { HttpThread=CreateHttpThread(); HttpThread->StartPostion=Starts[i]; HttpThread->GetBytes=Bytes[i]; HttpThread->OutFileName=OutTmpFiles[i]; HttpThread->Index=i; HttpThreads[i]=HttpThread; } } // 删除临时变量 delete Starts; delete Bytes; } //--------------------------------------------------------------------------- // 开始下载 void __fastcall THttpGetEx::StartGet(void) { if(FURL.IsEmpty() || FOutFileName.IsEmpty())return; CreateHttpThreads(); THttpGetThread *HttpThread; for(int i=0;i<FHttpThreadCount;i++) { HttpThread=HttpThreads[i]; if(HttpThread->Suspended)HttpThread->Resume(); } } //--------------------------------------------------------------------------- // 重新开始下载 void __fastcall THttpGetEx::RestartGet(void) { if(FURL.IsEmpty() || FOutFileName.IsEmpty())return; Stop(); StartGet(); } //--------------------------------------------------------------------------- // 暂停下载 void __fastcall THttpGetEx::Pause(void) { if(FWorking==false)return; // 请自己实现 } //--------------------------------------------------------------------------- // 停止下载 void __fastcall THttpGetEx::Stop(void) { if(FWorking==false)return; // 请自己实现 ReleaseResource(); } //--------------------------------------------------------------------------- const char *MutexToThread="http-get-thread-mutex"; void __fastcall THttpGetEx::OnThreadComplete(TObject *Sender, int Index) { // 创建互斥对象 HANDLE hMutex= CreateMutex(NULL,FALSE,MutexToThread); DWORD Err=GetLastError(); if(Err==ERROR_ALREADY_EXISTS) // 已经存在,等待 { WaitForSingleObject(hMutex,INFINITE);//8000L); hMutex= CreateMutex(NULL,FALSE,MutexToThread); } // 当一个线程结束时,检查是否全部认为完成 FSuccesss[Index]=true; bool S=true; for(int i=0;i<FHttpThreadCount;i++) { S = S && FSuccesss[i]; } ReleaseMutex(hMutex); if(S)// 下载完成 { DoOnComplete(); } } //--------------------------------------------------------------------------- void __fastcall THttpGetEx::OnThreadError(TObject *Sender, int Index) { // 当一个线程结束时,检查 Stop(); DoOnError(); } //--------------------------------------------------------------------------- void THttpGetEx::DoOnComplete(void) { if(FOnComplete) { DoOnStatusText("download complete"); // 合并各个文件 DoOnStatusText("merge all parts"); // 1. 复制第一部分 CopyFile(OutTmpFiles[0].c_str(),FOutFileName.c_str(),false); // 添加其他部分 int hD=FileOpen(FOutFileName,fmOpenWrite); FileSeek(hD,0,2); // 移动文件指针到末尾 if(hD==-1) { DoOnError(); return; } const int BufSize=1024*4; char Buf[BufSize+4]; int Reads; for(int i=1;i<FHttpThreadCount;i++) { int hS=FileOpen(OutTmpFiles[i],fmOpenRead); // 复制数据 Reads=FileRead(hS,(void *)Buf,BufSize); while(Reads>0) { FileWrite(hD,(void *)Buf,Reads); Reads=FileRead(hS,(void *)Buf,BufSize); } FileClose(hS); } FileClose(hD); DoOnStatusText("all complete"); FOnComplete(this); } } //--------------------------------------------------------------------------- void THttpGetEx::DoOnError(void) { if(FOnError) FOnError(this); } //--------------------------------------------------------------------------- void THttpGetEx::DoOnStatusText(AnsiString Text) { if(FOnStatusText) FOnStatusText(this,Text,-1); } //---------------------------------------------------------------------------