多线程传输文件_第1页
多线程传输文件_第2页
多线程传输文件_第3页
多线程传输文件_第4页
多线程传输文件_第5页
免费预览已结束,剩余8页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、C+实现文件传输之三:断点续传与多线程传输继木马编程DIY的上两篇,现在我们开始讨论断点续传与多线程文件传输的实现.其实这两项功能是下载软件所必不可少的功能了,现在我们把它加到自己的木马中来感受感受.提到多线程下载,首先向网络蚂蚁的作者洪以容前辈致敬,正是由于网络蚂蚁而使得多线程下载被关注并流行起来.在这本篇文章中我们将简单的实现支持断点续传和多线程传输的程序.为了更清晰的说明问题,我们将断点续传与多线程传输分别用两个程序来实现多线程传输实现实现原理将源文件按长度为分为N块文件,然后开辟N个线程,每个线程传输一块,最后合并所有线线程文件.比如一个文件500M我们按长度可以分5个线程传输.第一线

2、程从0-100M,第二线程从100M-200M.最后合并5个线程文件.实现流程1 .客户端向服务端请求文件信息(名称,长度)2 .客户端跟据文件长度开辟N个线程连接服务端3 .服务端开辟新的线程与客户端通信并传输文件4 .客户端将每线程数据保存到一个文件5 .合并所有线程文件编码实现大体说来就是按以上步骤进行,详细的实现和一些要点,我们跟据以上流程在编码中实现结构定义在通信过程中需要传递的信息包括文件名称,文件长度,文件偏移,操作指令等信息,为了方便操作我们定义如下结构代码: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"服务端代码如下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);/进入临界区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;)在这里服务端循环接受连接,并跟据TempFileInfo.CMD来判断客户端的请求类型,1为请求文件信息,2为下载文件因为在下载文件的请求中,需要开辟新的线程,并传递文件偏移和文件大小等信息,所以需要对线程同步.这里使用临界区其文件信息函

6、数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.客户端跟据长度开辟线程其实现代码如下代码: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);/离开临界区WaitForMultipleObjects(5,Thread,true,INFINITE);等所有线程结束这里默认开辟5个线程传输,当然可以改为想要的线程数目,仍然用临界区来实现线程的同步问题3.服务端开辟线程传输数据在1.请求文件信息中以说明了服务端的结构,这里主要介绍线程函数的实现,其代码如下代码:DWORDWINAPIGetFileProc(LPVOIDlparam)EnterCriticalSection(&CS);进入临界区intFileLen=TempFileInfo.FileLen;intSee

10、k=TempFileInfo.seek;SOCKETclient=TempFileInfo.sockid;LeaveCriticalSection(&CS);离开临界区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;还是比较简单的,主要是获取线程的文件长度和偏移,并移动文件指针到偏移处,最后读取发送数据,而客户端接受数据并写入文件.4 .客户端将线程数据保存到文件GetFileThread的实现代码如

12、下代码:DWORDWINAPIGetFileThread(LPVOIDlparam)(charTempNameMAX_PATH;sprintf(TempName,"TempFile%d",*(DWORD*)lparam);每线程的文件名为"TempName"+线程数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);离开临界区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;在此线程函数中,将每线程传输的数据存为一个文件,文件名为"TempName"+线程数,只所以存成单独的文件是因为比较直观且容易理解,但如果文件很大的话这个方法并不好,因为合并文件又会花费很多时间,另一个方法是创始一个文件,让每个线程写入文件

16、的不同偏移,这样就可以不必单独合并文件了,但要记得打开文件时加入CFile:shareDenyNone属性.这样整个过程就完成了.最后一步合并线程文件5 .合并线程文件代码:intUniteFile()/合并线程文件(cout<<"NowisUniteFileing.n"intlen;char*date;CFilefile;CFilefile。;/*其它文件.*/if(file.Open(FileName,CFile:modeCreate|CFile:typeBinary|CFile:modeWrite)创建文件(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;这个简单,就是打开一个文件读取到缓冲区,写入文件,再打开第二个.现在多线程传输部分就介绍完了下面讨论断断点续传的实现C+实现文件传输之四:断点传输收麴所谓的断点续传就是指:文件在传输过程式中被中断后,在重新传输时,可以从上次的断点处开始传输,这样就可节省时间,和其它资源.实现关键在这里有两个关键点,其一是检测本地已经下载的文件长度和断点值,其二是在服务端调整文件指针到断点处实现方法我们用一个简单的

19、方法来实现断点续传的功能.在传输文件的时候创建一个临时文件用来存放文件的断点位置在每次发送接受文件时,先检查有没有临时文件,如果有的话就从临时文件中读取断点值,并把文件指针移动到断点位置开始传输,这样便可以做到断点续传了实现流程首次传输其流程如下1 .服务端向客户端传递文件名称和文件长度2 .跟据文件长度计算文件块数(文件分块传输请参照第二篇文章)3 .客户端将传输的块数写入临时文件(做为断点值)4 .若文件传输成功则删除临时文件首次传输失败后将按以下流程进行1 .客户端从临时文件读取断点值并发送给服务端2 .服务端与客户端将文件指针移至断点处3 .从断点处传输文件编码实现因为程序代码并不复杂

20、,且注释也比较详细,这里就给出完整的实现其服务端实现代码如下代码:int_tmain(intargc,TCHAR*argv,TCHAR*envp).cout<<"tt服务端-断点续传"<<"t作者:冷风nn"<<"请输入被下载的文件路径如C:File.rarnn"<<"文件路径:"cin>>FilePath;/*这部分为网络参数与设置,详细请参照源代码.*/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;/文件块数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;/文件块数if(FileLen%nChunkCount!=0)nChunkCount+;send(client,(char*)&FileLen,sizeof(FileLen),0);/发送文件长度char*d

24、ate=newcharCHUNK_SIZE;/for(inti=nCurrentPos;i<nChunkCount;i+)从断点处分块发送(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;客户端实现代码如下代码:int_tmain(intargc,TCHAR*argv,TCHAR*envp)cout<<"tt客户端-断点续传"<<"t作者:冷风nn

26、"<<"请输入保存文件的路径如C:Save.RARnn"<<"文件路径:"cin>>FilePath;/*网络参数初示化,详细请参照源代码*/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);/发送断点值OpenFlags=CFile:modeWrite|CFile:typeBinary;/文件为可写)elsesend(client,(char*)&nCurrentPos,sizeof(nCurrentPos),0);/无断点文件nCurrentPos为0OpenFlags=CFile:modeWrite|CFile:typeBinary|CFile:modeCreate;/创建文件方式)if(recv(client,(char*)&FileLen,sizeof(FileLen),0)!=0)接受文件长度intnChunkCount;CFilefile;nChunkCount=FileLen/CHUNK_SIZE;/计算文件块数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. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论