多線程傳輸文件_第1頁
多線程傳輸文件_第2頁
多線程傳輸文件_第3頁
多線程傳輸文件_第4頁
多線程傳輸文件_第5頁
免費預(yù)覽已結(jié)束,剩余8頁可下載查看

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、C+實現(xiàn)文件傳輸之三:斷點續(xù)傳與多線程傳輸繼木馬編程DIY的上兩篇,現(xiàn)在我們開始討論斷點續(xù)傳與多線程文件傳輸?shù)膶崿F(xiàn).其實這兩項功能是下載軟件所必不可少的功能了,現(xiàn)在我們把它加到自己的木馬中來感受感受.提到多線程下載,首先向網(wǎng)絡(luò)螞蟻的作者洪以容前輩致敬,正是由于網(wǎng)絡(luò)螞蟻而使得多線程下載被關(guān)注并流行起來.在這本篇文章中我們將簡單的實現(xiàn)支持?jǐn)帱c續(xù)傳和多線程傳輸?shù)某绦?為了更清晰的說明問題,我們將斷點續(xù)傳與多線程傳輸分別用兩個程序來實現(xiàn)多線程傳輸實現(xiàn)實現(xiàn)原理將源文件按長度為分為N塊文件,然后開辟N個線程,每個線程傳輸一塊,最后合并所有線線程文件.比如一個文件500M我們按長度可以分5個線程傳輸.第一線

2、程從0-100M,第二線程從100M-200M.最后合并5個線程文件.實現(xiàn)流程1 .客戶端向服務(wù)端請求文件信息(名稱,長度)2 .客戶端跟據(jù)文件長度開辟N個線程連接服務(wù)端3 .服務(wù)端開辟新的線程與客戶端通信并傳輸文件4 .客戶端將每線程數(shù)據(jù)保存到一個文件5 .合并所有線程文件編碼實現(xiàn)大體說來就是按以上步驟進行,詳細的實現(xiàn)和一些要點,我們跟據(jù)以上流程在編碼中實現(xiàn)結(jié)構(gòu)定義在通信過程中需要傳遞的信息包括文件名稱,文件長度,文件偏移,操作指令等信息,為了方便操作我們定義如下結(jié)構(gòu)代碼:typedefstruct(charName100;文件名稱intFileLen;文件長度intCMD;操作指令ints

3、eek;/線程開始位置SOCKETsockid;FILEINFO;1.請求文件信息客戶端代碼如下代碼:FILEINFOfi;memset(char*)&fi,0,sizeof(fi);fi.CMD=1;得到文件信息if(send(client,(char*)&fi,sizeof(fi),0)=SOCKET_ERROR)cout<<"SendGetFileInfoError'n"服務(wù)端代碼如下while(true)SOCKETclient;if(client=accept(server,(sockaddr*)&clientaddr,

4、&len)FILEINFORecvFileInfo;memset(char*)&RecvFileInfo,0,sizeof(RecvFileInfo);if(recv(client,(char*)&RecvFileInfo,sizeof(RecvFileInfo),0)=SOCKET_ERROR)cout<<"TheClinetSocketisClosedn"break;elseEnterCriticalSection(&CS);/進入臨界區(qū)memcpy(char*)&TempFileInfo,(char*)&Re

5、cvFileInfo,sizeof(RecvFileInfo);switch(TempFileInfo.CMD)case 1:GetInfoProc(client);break;case 2:TempFileInfo.sockid=client;CreateThread(NULL,NULL,GetFileProc,NULL,NULL,NULL);break;)在這里服務(wù)端循環(huán)接受連接,并跟據(jù)TempFileInfo.CMD來判斷客戶端的請求類型,1為請求文件信息,2為下載文件因為在下載文件的請求中,需要開辟新的線程,并傳遞文件偏移和文件大小等信息,所以需要對線程同步.這里使用臨界區(qū)其文件信息函

6、數(shù)GetInfoProc代碼如下代碼:DWORDGetInfoProc(SOCKETclient)CFilefile;if(file.Open(FileName,CFile:modeRead|CFile:typeBinary)intFileLen=file.GetLength();if(send(client,(char*)&FileLen,sizeof(FileLen),0)=SOCKET_ERROR)cout<<"SendFileLenErrorn"elsecout<<"TheFilelenis"<<Fil

7、eLen<<"nn"return0;這里主要是向客戶端傳遞文件長度,而客戶端收到長度后則開辟線程進行連接傳輸文件2.客戶端跟據(jù)長度開辟線程其實現(xiàn)代碼如下代碼:FILEINFOFI;intFileLen=0;if(recv(client,(char*)&FileLen,sizeof(FileLen),0)=SOCKET_ERROR)/接受文件長度cout<<"RecvFileLenErrorn"elsecout<<"FileLenis"<<FileLen<<"

8、n"intCOUNT_SIZE=FileLen/5;每線程傳輸大小for(inti=0;i<5;i+)分5個線程傳輸memset(char*)&FI,0,sizeof(FI);FI.CMD=2;請求下載文件FI.seek=i*COUNT_SIZE;/線程文件偏移if(i+1=5)最后一線程長度為總長度減前4個線程長度FI.FileLen=FileLen-COUNT_SIZE*i;elseFI.FileLen=COUNT_SIZE;Thread=CreateThread(NULL,NULL,GetFileThread,&i,NULL,NULL);Sleep(500

9、);LeaveCriticalSection(&CS);/離開臨界區(qū)WaitForMultipleObjects(5,Thread,true,INFINITE);等所有線程結(jié)束這里默認(rèn)開辟5個線程傳輸,當(dāng)然可以改為想要的線程數(shù)目,仍然用臨界區(qū)來實現(xiàn)線程的同步問題3.服務(wù)端開辟線程傳輸數(shù)據(jù)在1.請求文件信息中以說明了服務(wù)端的結(jié)構(gòu),這里主要介紹線程函數(shù)的實現(xiàn),其代碼如下代碼:DWORDWINAPIGetFileProc(LPVOIDlparam)EnterCriticalSection(&CS);進入臨界區(qū)intFileLen=TempFileInfo.FileLen;intSee

10、k=TempFileInfo.seek;SOCKETclient=TempFileInfo.sockid;LeaveCriticalSection(&CS);離開臨界區(qū)CFilefile;if(file.Open(FileName,CFile:modeRead|CFile:typeBinary)file.Seek(Seek,CFile:begin);/指針移至偏移位置char*date=newcharFileLen;intnLeft=FileLen;intidx=0;file.Read(date,FileLen);while(nLeft>0)intret=send(client,

11、&dateidx,nLeft,0);if(ret=SOCKET_ERROR)cout<<"SendDateErrorn"break;)nLeft-=ret;idx+=ret;)file.Close();deletedate;else(cout<<"openthefileerrorn"closesocket(client);return0;還是比較簡單的,主要是獲取線程的文件長度和偏移,并移動文件指針到偏移處,最后讀取發(fā)送數(shù)據(jù),而客戶端接受數(shù)據(jù)并寫入文件.4 .客戶端將線程數(shù)據(jù)保存到文件GetFileThread的實現(xiàn)代碼如

12、下代碼:DWORDWINAPIGetFileThread(LPVOIDlparam)(charTempNameMAX_PATH;sprintf(TempName,"TempFile%d",*(DWORD*)lparam);每線程的文件名為"TempName"+線程數(shù)SOCKETclient;SOCKADDR_INserveraddr;intport=5555;client=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);serveraddr.sin_family=AF_INET;serveraddr.sin_port=ht

13、ons(port);serveraddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");if(connect(client,(SOCKADDR*)&serveraddr,sizeof(serveraddr)=INVALID_SOCKET)(cout<<"ConnectServerErrorn"if(send(client,(char*)&FI,sizeof(FI),0)=SOCKET_ERROR)(cout<<"SendGetFileError'n&quo

14、t;return0;CFilefile;intFileLen=FI.FileLen;文件長度intSeek=FI.seek;文件偏移LeaveCriticalSection(&CS);離開臨界區(qū)if(file.Open(TempName,CFile:modeWrite|CFile:typeBinary|CFile:modeCreate)(char*date=newcharFileLen;intnLeft=FileLen;intidx=0;while(nLeft>0)(intret=recv(client,&dateidx,nLeft,0);if(ret=SOCKET_ER

15、ROR)(cout<<"RecvDateError"break;idx+=ret;nLeft-=ret;file.Write(date,FileLen);file.Close();deletedate;else(cout<<"CreateFileErrorn"return0;在此線程函數(shù)中,將每線程傳輸?shù)臄?shù)據(jù)存為一個文件,文件名為"TempName"+線程數(shù),只所以存成單獨的文件是因為比較直觀且容易理解,但如果文件很大的話這個方法并不好,因為合并文件又會花費很多時間,另一個方法是創(chuàng)始一個文件,讓每個線程寫入文件

16、的不同偏移,這樣就可以不必單獨合并文件了,但要記得打開文件時加入CFile:shareDenyNone屬性.這樣整個過程就完成了.最后一步合并線程文件5 .合并線程文件代碼:intUniteFile()/合并線程文件(cout<<"NowisUniteFileing.n"intlen;char*date;CFilefile;CFilefile。;/*其它文件.*/if(file.Open(FileName,CFile:modeCreate|CFile:typeBinary|CFile:modeWrite)創(chuàng)建文件(file0.Open("TempFil

17、e0",CFile:modeRead|CFile:typeBinary);/合并第一線程文件len=file0.GetLength();date=newcharlen;file0.Read(date,len);file.SeekToEnd();file.Write(date,len);file1.Open("TempFile1",CFile:modeRead|CFile:typeBinary);合并第二線程文件len=file1.GetLength();date=newcharlen;file1.Read(date,len);file.SeekToEnd();fi

18、le.Write(date,len);/*合并其它線程.*/file0.Close();file1.Close();/*/deletedate;returntrue;else(returnfalse;這個簡單,就是打開一個文件讀取到緩沖區(qū),寫入文件,再打開第二個.現(xiàn)在多線程傳輸部分就介紹完了下面討論斷斷點續(xù)傳的實現(xiàn)C+實現(xiàn)文件傳輸之四:斷點傳輸收麴所謂的斷點續(xù)傳就是指:文件在傳輸過程式中被中斷后,在重新傳輸時,可以從上次的斷點處開始傳輸,這樣就可節(jié)省時間,和其它資源.實現(xiàn)關(guān)鍵在這里有兩個關(guān)鍵點,其一是檢測本地已經(jīng)下載的文件長度和斷點值,其二是在服務(wù)端調(diào)整文件指針到斷點處實現(xiàn)方法我們用一個簡單的

19、方法來實現(xiàn)斷點續(xù)傳的功能.在傳輸文件的時候創(chuàng)建一個臨時文件用來存放文件的斷點位置在每次發(fā)送接受文件時,先檢查有沒有臨時文件,如果有的話就從臨時文件中讀取斷點值,并把文件指針移動到斷點位置開始傳輸,這樣便可以做到斷點續(xù)傳了實現(xiàn)流程首次傳輸其流程如下1 .服務(wù)端向客戶端傳遞文件名稱和文件長度2 .跟據(jù)文件長度計算文件塊數(shù)(文件分塊傳輸請參照第二篇文章)3 .客戶端將傳輸?shù)膲K數(shù)寫入臨時文件(做為斷點值)4 .若文件傳輸成功則刪除臨時文件首次傳輸失敗后將按以下流程進行1 .客戶端從臨時文件讀取斷點值并發(fā)送給服務(wù)端2 .服務(wù)端與客戶端將文件指針移至斷點處3 .從斷點處傳輸文件編碼實現(xiàn)因為程序代碼并不復(fù)雜

20、,且注釋也比較詳細,這里就給出完整的實現(xiàn)其服務(wù)端實現(xiàn)代碼如下代碼:int_tmain(intargc,TCHAR*argv,TCHAR*envp).cout<<"tt服務(wù)端-斷點續(xù)傳"<<"t作者:冷風(fēng)nn"<<"請輸入被下載的文件路徑如C:File.rarnn"<<"文件路徑:"cin>>FilePath;/*這部分為網(wǎng)絡(luò)參數(shù)與設(shè)置,詳細請參照源代碼.*/while(true)if(client=accept(server,(sockaddr*)&

21、;clientaddr,&len)cout<<"haveoneconnectn"intnCurrentPos=0;/接受斷點值if(recv(client,(char*)&nCurrentPos,sizeof(nCurrentPos),0)=SOCKET_ERROR)(cout<<"TheClinetSocketisClosedn"break;else(cout<<"TheCurrentposisThe"<<nCurrentPos<<"n"

22、GetFileProc(nCurrentPos,client);closesocket(server);closesocket(client);WSACleanup();return0;return0;DWORDGetFileProc(intnCurrentPos,SOCKETclient)(cout<<"GetFileProcisokn"CFilefile;intnChunkCount=0;/文件塊數(shù)if(file.Open(FilePath,CFile二modeRead|CFile二typeBinary)(if(nCurrentPos!=0)(巾le.See

23、k(nCurrentPos*CHUNK_SIZE,CFile:begin);/文件指針移至斷點處cout<<"fileseekis"<<nCurrentPos*CHUNK_SIZE<<"n"intFileLen=file.GetLength();nChunkCount=FileLen/CHUNK_SIZE;/文件塊數(shù)if(FileLen%nChunkCount!=0)nChunkCount+;send(client,(char*)&FileLen,sizeof(FileLen),0);/發(fā)送文件長度char*d

24、ate=newcharCHUNK_SIZE;/for(inti=nCurrentPos;i<nChunkCount;i+)從斷點處分塊發(fā)送(cout<<"sendthecount"<<i<<"n"intnLeft;if(i+1=nChunkCount)/最后一塊nLeft=FileLen-CHUNK_SIZE*(nChunkCount-1);elsenLeft=CHUNK_SIZE;intidx=0;file.Read(date,CHUNK_SIZE);while(nLeft>0)intret=send(c

25、lient,&dateidx,nLeft,0);if(ret=SOCKET_ERROR)cout<<"SendTheDateErrorn"break;nLeft-=ret;idx+=ret;file.Close();deletedate;elsecout<<"openthefileerrorn"return0;客戶端實現(xiàn)代碼如下代碼:int_tmain(intargc,TCHAR*argv,TCHAR*envp)cout<<"tt客戶端-斷點續(xù)傳"<<"t作者:冷風(fēng)nn

26、"<<"請輸入保存文件的路徑如C:Save.RARnn"<<"文件路徑:"cin>>FilePath;/*網(wǎng)絡(luò)參數(shù)初示化,詳細請參照源代碼*/if(connect(client,(SOCKADDR*)&serveraddr,sizeof(serveraddr)=INVALID_SOCKET)cout<<"ConnectServerError"return0;)intFileLen=0;intnCurrentPos=0;/斷點位置UINTOpenFlags;CFilePo

27、sFile;if(PosFile.Open("PosFile.temp”,CFile:modeRead|CFile:typeBinary)/如果有臨時文件則讀取斷點PosFile.Read(char*)&nCurrentPos,sizeof(nCurrentPos);/讀取斷點位置cout<<"TheFilePosis"<<nCurrentPos<<"n"nCurrentPos=nCurrentPos+1;/從斷點的下一塊開始PosFile.Close();send(client,(char*)&am

28、p;nCurrentPos,sizeof(nCurrentPos),0);/發(fā)送斷點值OpenFlags=CFile:modeWrite|CFile:typeBinary;/文件為可寫)elsesend(client,(char*)&nCurrentPos,sizeof(nCurrentPos),0);/無斷點文件nCurrentPos為0OpenFlags=CFile:modeWrite|CFile:typeBinary|CFile:modeCreate;/創(chuàng)建文件方式)if(recv(client,(char*)&FileLen,sizeof(FileLen),0)!=0)接受文件長度intnChunkCount;CFilefile;nChunkCount=FileLen/CHUNK_SIZE;/計算文件塊數(shù)if(FileLen%nChunkCount!=0)nChunkCount+;)if(file.Open(FilePath,OpenFlags)file.Seek(nCurrentPos*CHUNK_SIZE,CFile:begin);/文件指針移至斷點處char*date=newcharCHUNK_SIZE;for

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論