日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++编写断点续传和多线程下载模块【转】

發布時間:2023/12/20 c/c++ 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++编写断点续传和多线程下载模块【转】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在當今的網絡時代,下載軟件是使用最為頻繁的軟件之一。幾年來,下載技術也在不停地發展。最原始的下載功能僅僅是個“下載”過程,即從WEB服務器上連續地讀取文件。其最大的問題是,由于網絡的不穩定性,一旦連接斷開使得下載過程中斷,就不得不全部從頭再來一次。

  隨后,“斷點續傳”的概念就出來了,顧名思義,就是如果下載中斷,在重新建立連接后,跳過已經下載的部分,而只下載還沒有下載的部分。

   無論“多線程下載”技術是否洪以容先生的發明,洪以容使得這項技術得到前所未有的關注是不爭的事實。在“網絡螞蟻”軟件流行開后,許多下載軟件也都紛紛 效仿,是否具?quot;多線程下載"技術、甚至能支持多少個下載線程都成了人們評測下載軟件的要素。"多線程下載"的基礎是WEB服務器支持遠程的隨機 讀取,也即支持"斷點續傳"。這樣,在下載時可以把文件分成若干部分,每一部分創建一個下載線程進行下載。

  現在,不要說編寫專門的下載 軟件,在自己編寫的軟件中,加入下載功能有時也非常必要。如讓自己的軟件支持自動在線升級,或者在軟件中自動下載新的數據進行數據更新,這都是很有用、而 且很實用的功能。本文的主題即怎樣編寫一個支持"斷點續傳"和"多線程"的下載模塊。當然,下載的過程非常復雜,在一篇文章中難以全部闡明,所以,與下載 過程關系不直接的部分基本上都忽略了,如異常處理和網絡錯誤處理等,敬請各位讀者注意。我使用的開發環境是C++ Builder 5.0,使用其他開發環境或者編程語言的朋友請自行作適當修改。

  HTTP協議簡介

  下載文件是電腦與WEB服務器交互的過程,它們交互的"語言"的專業名稱是協議。傳送文件的協議有多種,最常用的是HTTP(超文本傳輸協議)和FTP(文件傳送協議),我采用的是HTTP。

HTTP協議最基本的命令只有三條:Get、Post和Head。Get從WEB服務器請求一個特定的對象,比如HTML頁面或者一個文件,WEB 服務器通過一個Socket連接發送此對象作為響應;Head命令使服務器給出此對象的基本描述,比如對象的類型、大小和更新時間。Post命令用于向 WEB服務器發送數據,通常使把信息發送給一個單獨的應用程序,經處理生成動態的結果返回給瀏覽器。下載即是通過Get命令實現。

  基本的下載過程

   編寫下載程序,可以直接使用Socket函數,但是這要求開發人員理解、熟悉TCP/IP協議。為了簡化Internet客戶端軟件的開 發,Windows提供了一套WinInet API,對常用的網絡協議進行了封裝,把開發Internet軟件的門檻大大降低了。我們需要使用的WinInet API函數如圖1所示,調用順序基本上是從上到下,其具體的函數原型請參考MSDN。

  圖1

  在使用這些函數時,必須嚴格區分它們使用的句柄。這些句柄的類型是一樣的,都是HINTERNET,但是作用不同,這一點非常讓人迷惑。按照這些句柄的產生順序和調用關系,可以分為三個級別,下一級的句柄由上一級的句柄得到。

  InternetOpen是最先調用的函數,它返回的HINTERNET句柄級別最高,我習慣定義為hSession,即會話句柄。

  InternetConnect使用hSession句柄,返回的是http連接句柄,我把它定義為hConnect。

  HttpOpenRequest使用hConnect句柄,返回的句柄是http請求句柄,定義為hRequest。

  HttpSendRequest、HttpQueryInfo、InternetSetFilePointer和InternetReadFile都使用HttpOpenRequest返回的句柄,即hRequest。

  當這幾個句柄不再使用是,應該用函數InternetCloseHandle把它關閉,以釋放其占用的資源。

首先建立一個名為THttpGetThread、創建后自動掛起的線程模塊,我希望線程在完成后自動銷毀,所以在構造函數中設置:

  FreeOnTerminate = True; // 自動刪除

  并增加以下成員變量:

char?Buffer[HTTPGET_BUFFER_MAX+4];?//?數據緩沖區
AnsiString?FURL;?//?下載對象的URL
AnsiString?FOutFileName;?//?保存的路徑和名稱
HINTERNET?FhSession;?//?會話句柄
HINTERNET?FhConnect;?//?http連接句柄
HINTERNET?FhRequest;?//?http請求句柄
bool?FSuccess;?//?下載是否成功
int?iFileHandle;?//?輸出文件的句柄

?

?、建⒘?lt;/p>

  按照功能劃分,下載過程可以分為4部分,即建立連接、讀取待下載文件的信息并分析、下載文件和釋 放占用的資源。建立連接的函數如下,其中ParseURL的作用是從下載URL地址中取得主機名稱和下載的文件的WEB路 徑,DoOnStatusText用于輸出當前的狀態:

?

?

//初始化下載環境
void?THttpGetThread::StartHttpGet(void)
{
??AnsiString?HostName,FileName;
??ParseURL(HostName,?FileName);
??
try
??{
?
//?1.建立會話
   ?FhSession?=?InternetOpen("http-get-demo",
?INTERNET_OPEN_TYPE_PRECONFIG,
?NULL,NULL,
?
0);?//?同步方式
   ?if(?FhSession==NULL)throw(Exception("Error:InterOpen"));
?DoOnStatusText(
"ok:InterOpen");
?
//?2.建立連接
   ?FhConnect=InternetConnect(FhSession,
?HostName.c_str(),
?INTERNET_DEFAULT_HTTP_PORT,
?NULL,NULL,
?INTERNET_SERVICE_HTTP,?
0,?0);
?
if(FhConnect==NULL)throw(Exception("Error:InternetConnect"));
?DoOnStatusText(
"ok:InternetConnect");
?
//?3.初始化下載請求
   ?const?char?*FAcceptTypes?=?"*/*";
?FhRequest?
=?HttpOpenRequest(FhConnect,
?
"GET",?//?從服務器獲取數據
      ?FileName.c_str(),?//?想讀取的文件的名稱
      ?"HTTP/1.1",?//?使用的協議
      ?NULL,
?
&FAcceptTypes,
?INTERNET_FLAG_RELOAD,
?
0);
?
if(?FhRequest==NULL)throw(Exception("Error:HttpOpenRequest"));
?DoOnStatusText(
"ok:HttpOpenRequest");
?
//?4.發送下載請求
   ?HttpSendRequest(FhRequest,?NULL,?0,?NULL,?0);
?DoOnStatusText(
"ok:HttpSendRequest");
??}
catch(Exception?&exception)
??{
?EndHttpGet();?
//?關閉連接,釋放資源
   ?DoOnStatusText(exception.Message);
??}
}
//?從URL中提取主機名稱和下載文件路徑
void?THttpGetThread::ParseURL(AnsiString?&HostName,AnsiString?&FileName)
{
??AnsiString?URL
=FURL;
??
int?i=URL.Pos("http://");
??
if(i>0)
??{
?URL.Delete(
1,?7);
??}
??i
=URL.Pos("/");
??HostName?
=?URL.SubString(1,?i-1);
??FileName?
=?URL.SubString(i,?URL.Length());
}

?

???? 可以看到,程序按照圖1中的順序,依次調用InternetOpen、InternetConnect、HttpOpenRequest函數得到3個相關的句柄,然后通過HttpSendRequest函數把下載的請求發送給WEB服務器。

  InternetOpen的第一個參數是無關的,最后一個參數如果設置為INTERNET_FLAG_ASYNC,則將建立異步連接,這很有實際意義,考慮到本文的復雜程度,我沒有采用。但是對于需要更高下載要求的讀者,強烈建議采用異步方式。

  HttpOpenRequest打開一個請求句柄,命令是"GET",表示下載文件,使用的協議是"HTTP/1.1"。

  另外一個需要注意的地方是HttpOpenRequest的參數FAcceptTypes,表示可以打開的文件類型,我設置為"*/*"表示可以打開所有文件類型,可以根據實際需要改變它的值。

  2、讀取待下載的文件的信息并分析

  在發送請求后,可以使用HttpQueryInfo函數獲取文件的有關信息,或者取得服務器的信息以及服務器支持的相關操作。對于下載程序,最常用的是傳遞HTTP_QUERY_CONTENT_LENGTH參數取得文件的大小,即文件包含的字節數。模塊如下所示:

//?取得待下載文件的大小
int?__fastcall?THttpGetThread::GetWEBFileSize(void)
{
??
try
??{
?DWORD?BufLen
=HTTPGET_BUFFER_MAX;
?DWORD?dwIndex
=0;
?
bool?RetQueryInfo=HttpQueryInfo(FhRequest,
?HTTP_QUERY_CONTENT_LENGTH,
?Buffer,?
&BufLen,
?
&dwIndex);
?
if(?RetQueryInfo==false)?throw(Exception("Error:HttpQueryInfo"));
?DoOnStatusText(
"ok:HttpQueryInfo");
?
int?FileSize=StrToInt(Buffer);?//?文件大小
   ?DoOnGetFileSize(FileSize);
??}
catch(Exception?&exception)
??{
?DoOnStatusText(exception.Message);
??}
??
return?FileSize;
}

?

????? 模塊中的DoOnGetFileSize是發出取得文件大小的事件。取得文件大小后,對于采用多線程的下載程序,可以按照這個值進行合適的文件分塊,確定每個文件塊的起點和大小。

  3、下載文件的模塊

  開始下載前,還應該先安排好怎樣保存下載結果。方法很多,我直接采用了C++ Builder提供的文件函數打開一個文件句柄。當然,也可以采用Windows本身的API,對于小文件,全部緩沖到內存中也可以考慮。

//?打開輸出文件,以保存下載的數據
DWORD?THttpGetThread::OpenOutFile(void)
{
??
try
??{
??
if(FileExists(FOutFileName))
?DeleteFile(FOutFileName);
??iFileHandle
=FileCreate(FOutFileName);
??
if(iFileHandle==-1)?throw(Exception("Error:FileCreate"));
??DoOnStatusText(
"ok:CreateFile");
??}
catch(Exception?&exception)
??{
?DoOnStatusText(exception.Message);
??}
??
return?0;
}
//?執行下載過程
void?THttpGetThread::DoHttpGet(void)
{
??DWORD?dwCount
=OpenOutFile();
??
try
??{
?
//?發出開始下載事件
   ?DoOnStatusText("StartGet:InternetReadFile");
?
//?讀取數據
   ?DWORD?dwRequest;?//?請求下載的字節數
   ?DWORD?dwRead;?//?實際讀出的字節數
   ?dwRequest=HTTPGET_BUFFER_MAX;
?
while(true)
?{
??Application
->ProcessMessages();
??
bool?ReadReturn?=?InternetReadFile(FhRequest,
?(LPVOID)Buffer,
?dwRequest,
?
&dwRead);
??
if(!ReadReturn)break;
??
if(dwRead==0)break;
??
//?保存數據
    ??Buffer[dwRead]='\0';
??FileWrite(iFileHandle,?Buffer,?dwRead);
??dwCount?
=?dwCount?+?dwRead;
??
//?發出下載進程事件
    ??DoOnProgress(dwCount);
?}
?Fsuccess
=true;
??}
catch(Exception?&exception)
??{
?Fsuccess
=false;
?DoOnStatusText(exception.Message);
??}
??FileClose(iFileHandle);
??DoOnStatusText(
"End:InternetReadFile");
}

?下載過程并不復雜,與讀取本地文件一樣,執行一個簡單的循環。當然,如此方便的編程還是得益于微軟對網絡協議的封裝。

  4、釋放占用的資源

  這個過程很簡單,按照產生各個句柄的相反的順序調用InternetCloseHandle函數即可。

void?THttpGetThread::EndHttpGet(void)
{
??
if(FConnected)
??{
?DoOnStatusText(
"Closing:InternetConnect");
?
try
?{
??InternetCloseHandle(FhRequest);
??InternetCloseHandle(FhConnect);
??InternetCloseHandle(FhSession);
?}
catch(){}
?FhSession
=NULL;
?FhConnect
=NULL;
?FhRequest
=NULL;
?FConnected
=false;
?DoOnStatusText(
"Closed:InternetConnect");
??}
}

???? 我覺得,在釋放句柄后,把變量設置為NULL是一種良好的編程習慣。在這個示例中,還出于如果下載失敗,重新進行下載時需要再次利用這些句柄變量的考慮。

  5、功能模塊的調用

  這些模塊的調用可以安排在線程對象的Execute方法中,如下所示:

void?__fastcall?THttpGetThread::Execute()
{
??FrepeatCount
=5;
??
for(int?i=0;i<FRepeatCount;i++)
??{
?StartHttpGet();
?GetWEBFileSize();
?DoHttpGet();
?EndHttpGet();
?
if(FSuccess)break;
??}
??
//?發出下載完成事件
 ??if(FSuccess)DoOnComplete();
??
else?DoOnError();
}

??? 這里執行了一個循環,即如果產生了錯誤自動重新進行下載,實際編程中,重復次數可以作為參數自行設置。

  實現斷點續傳功能

  在基本下載的代碼上實現斷點續傳功能并不是很復雜,主要的問題有兩點:

   1、 檢查本地的下載信息,確定已經下載的字節數。所以應該對打開輸出文件的函數作適當修改。我們可以建立一個輔助文件保存下載的信息,如已經下載的字節數等。 我處理得較為簡單,先檢查輸出文件是否存在,如果存在,再得到其大小,并以此作為已經下載的部分。由于Windows沒有直接取得文件大小的API,我編 寫了GetFileSize函數用于取得文件大小。注意,與前面相同的代碼被省略了。

DWORD?THttpGetThread::OpenOutFile(void)
{
??……
??
if(FileExists(FOutFileName))
??{
?DWORD?dwCount
=GetFileSize(FOutFileName);
?
if(dwCount>0)
?{
??iFileHandle
=FileOpen(FOutFileName,fmOpenWrite);
??FileSeek(iFileHandle,
0,2);?//?移動文件指針到末尾
    ??if(iFileHandle==-1)?throw(Exception("Error:FileCreate"));
??DoOnStatusText(
"ok:OpenFile");
??
return?dwCount;
?}
?DeleteFile(FOutFileName);
??}
??……
}

?2、 在開始下載文件(即執行InternetReadFile函數)之前,先調整WEB上的文件指針。這就要求WEB服務器支持隨機讀取文件的操作,有些服務器對此作了限制,所以應該判斷這種可能性。對DoHttpGet模塊的修改如下,同樣省略了相同的代碼:

void?THttpGetThread::DoHttpGet(void)
{
??DWORD?dwCount
=OpenOutFile();
??
if(dwCount>0)?//?調整文件指針
 ??{
?dwStart?
=?dwStart?+?dwCount;
?
if(!SetFilePointer())?//?服務器不支持操作
   ?{
??
//?清除輸出文件
    ??FileSeek(iFileHandle,0,0);?//?移動文件指針到頭部
   ?}
??}
??……
}

?多線程下載

  要實現多線程下載,最主要的問題是下載線程的創建和管理,已經下載完成后文件的各個部分的準確合并,同時,下載線程也要作必要的修改。

  1、下載線程的修改

  為了適應多線程程序,我在下載線程加入如下成員變量:

  int FIndex; // 在線程數組中的索引

  DWORD dwStart; // 下載開始的位置

  DWORD dwTotal; // 需要下載的字節數

  DWORD FGetBytes; // 下載的總字節數

  并加入如下屬性值:

__property?AnsiString?URL?=?{?read=FURL,?write=FURL?};
__property?AnsiString?OutFileName?
=?{?read=FOutFileName,?write=FOutFileName};
__property?
bool?Successed?=?{?read=FSuccess};
__property?
int?Index?=?{?read=FIndex,?write=FIndex};
__property?DWORD?StartPostion?
=?{?read=dwStart,?write=dwStart};
__property?DWORD?GetBytes?
=?{?read=dwTotal,?write=dwTotal};
__property?TOnHttpCompelete?OnComplete?
=?{?read=FOnComplete,?write=FOnComplete?};

?同時,在下載過程DoHttpGet中增加如下處理,

void?THttpGetThread::DoHttpGet(void)
{
??……
??
try
??{
?……
?
while(true)
?{
??Application
->ProcessMessages();
??
//?修正需要下載的字節數,使得dwRequest?+?dwCount?<dwTotal;
    ??if(dwTotal>0)?//?dwTotal=0表示下載到文件結束
    ??{
?
if(dwRequest+dwCount>dwTotal)
?dwRequest
=dwTotal-dwCount;
??}
??……
??
if(dwTotal>0)?//?dwTotal?<=0表示下載到文件結束
    ??{
?
if(dwCount>=dwTotal)break;
??}
?}
??}
??……
??
if(dwCount==dwTotal)FSuccess=true;
}

?2、建立多線程下載組件

  我先建立了以TComponent為基類、名為THttpGetEx的組件模塊,并增加以下成員變量:

//?內部變量

THttpGetThread?
**HttpThreads;?//?保存建立的線程

AnsiString?
*OutTmpFiles;?//?保存結果文件各個部分的臨時文件

bool?*FSuccesss;?//?保存各個線程的下載結果

//?以下是屬性變量

int?FHttpThreadCount;?//?使用的線程個數

AnsiString?FURL;

AnsiString?FOutFileName;

?各個變量的用途都如代碼注釋,其中的FSuccess的作用比較特別,下文會再加以詳細解釋。因為線程的運行具有不可逆性,而組件可能會連續地下載不同的 文件,所以下載線程只能動態創建,使用后隨即銷毀。創建線程的模塊如下,其中GetSystemTemp函數取得系統的臨時文件 夾,OnThreadComplete是線程下載完成后的事件,其代碼在其后介紹:

//?分配資源
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];
}
//?創建一個下載線程
THttpGetThread?*?THttpGetEx::CreateHttpThread(void)
{
??THttpGetThread?
*HttpThread=new?THttpGetThread(this);
??HttpThread
->URL=FURL;
??……?
//?初始化事件
 ??HttpThread->OnComplete=OnThreadComplete;?//?線程下載完成事件
 ??return?HttpThread;
}
//?創建下載線程數組
void?THttpGetEx::CreateHttpThreads(void)
{
??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::DownLoadFile(void)
{
??CreateHttpThreads();
??THttpGetThread?
*HttpThread;
??
for(int?i=0;i<FHttpThreadCount;i++)
??{
?HttpThread
=HttpThreads[i];
?HttpThread
->Resume();
??}
}

?線程下載完成后,會發出OnThreadComplete事件,在這個事件中判斷是否所有下載線程都已經完成,如果是,則合并文件的各個部分。應該注意, 這里有一個線程同步的問題,否則幾個線程同時產生這個事件時,會互相沖突,結果也會混亂。同步的方法很多,我的方法是創建線程互斥對象。

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)//?下載完成,合并文件的各個部分
 ??{
?
//?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);
??}
}

?結語

?到此,多線程下載的關鍵部分就介紹完了。但是在實際應用時,還有許多應該考慮的因素,如網絡速度、斷線等等都是必須 考慮的。當然還有一些細節上的考慮,但是限于篇幅,就難以一一寫明了。如果讀者朋友能夠參照本文編寫出自己滿意的下載程序,我也就非常欣慰了。我也非常希 望讀者能由此與我互相學習,共同進步。

?

?

?

?

?

?

?


?

?

轉載于:https://www.cnblogs.com/NeuqUstcIim/archive/2008/08/19/1271394.html

總結

以上是生活随笔為你收集整理的c++编写断点续传和多线程下载模块【转】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产精品福利一区二区 | 成人黄色免费网址 | yy1111111| 精品一区二区三区日韩 | 77久久 | 亚洲av片一区二区三区 | 亚洲一二三区在线 | 色 综合 欧美 亚洲 国产 | 麻豆免费在线视频 | 99热这里只有精品首页 | 久久午夜场 | 巨乳美女在线 | 日本女优一区 | 日日干夜夜爽 | 超碰av人人 | 黑人巨大精品人妻一区二区 | 国产又爽又黄的视频 | 黄色一级大片免费版 | 黄色一级大片 | 麻豆伊甸园 | 日本涩涩网 | 黄色资源在线 | 欧美性猛交xxxxx水多 | 得得的爱在线视频 | 国模在线视频 | 永久免费的av网站 | 欧美美女网站 | 日韩高清一二三区 | 久久国产免费视频 | 亚洲一区在线看 | 国产一二三级 | 最近免费中文字幕中文高清百度 | 亚洲午夜无码av毛片久久 | 一道本在线观看视频 | 91一区二区三区在线观看 | 天堂影音 | av网站免费在线看 | 欧美日韩免费一区 | 欧美绿帽合集videosex | 黄色小毛片 | 中文字幕在线国产 | 天天色天天色 | 日韩成人在线视频观看 | 国产精品18 | 911福利视频 | 中文字幕无码精品亚洲 | 奇米一区二区三区 | 91深夜视频 | 好吊色视频一区二区三区 | 一级成人毛片 | 五月婷婷视频在线观看 | a天堂资源在线 | 91av国产视频 | 最好看的2019年中文在线观看 | 黄色av中文字幕 | 女同性αv亚洲女同志 | 国产欧美日韩在线视频 | 丨国产丨调教丨91丨 | 国产高清一 | 色偷偷欧美 | 色丁香久久| 亚洲天堂区 | 久久精品视频在线免费观看 | 国产男男gay体育生白袜 | 亚洲视频精品一区 | 久久9999久久免费精品国产 | 狠狠躁夜夜躁人人爽天天高潮 | 成人免费一级视频 | 国产片一区二区 | 草草草在线观看 | 免费看污视频的网站 | 午夜激情免费 | 国产奶头好大揉着好爽视频 | 久一精品| 中国女人做爰视频 | 欧美人吸奶水吃奶水 | 亚洲av无码久久精品狠狠爱浪潮 | 爱露出 | 亚洲欧美日韩动漫 | 国外成人性视频免费 | 国内av在线播放 | 国产无| 边添小泬边狠狠躁视频 | 靠逼视频网站 | 欧美综合日韩 | 久久在线免费 | 国产一级做a爰片久久毛片男 | 国产妞干网 | 激情狠狠 | www.国产黄色 | 黄色无遮挡网站 | 谁有毛片网址 | 日韩精品一区二区三区高清免费 | 亚洲成人av网址 | 97人妻精品一区二区三区视频 | 北条麻妃在线一区二区 | 伊人久久麻豆 | 中文乱码人妻一区二区三区视频 | 国产又粗又猛又大爽 |