| 网站首页 | 文章中心 | 电子书下载 | 矢量图库 | 视频教程 | 素材下载 | 程序代码下载 | JS代码 | 论坛 | 
常用软件类:
|杀毒安全 |联络聊天 |网络软件 |多媒体类 |系统工具 |图形图像 |系统工具 |应用软件 |行业软件
开发设计类:
|动画制作 |图像处理 |3D设计 |操作系统 |站长学院 |网络相关 |WEB设计 |数据库类 |程序开发
VC++实现点对点(P2P)多线程断点续传
作者:佚名    文章来源:网络网络    点击数:    更新时间:2006-12-20
 



 二、客户端

客户端最重要,也最复杂,它负责线程的管理,进度的记录等工作。

大概流程如下:
先连接服务器,接着发送命令1(给我文件信息),其中包括文件长度,名字等,然后根据长度决定分几个线程下载,并初使化下载进程,接着发送命令2(可以给我传文件了),并记录文件进程。最后,收尾。
这其中有一个十分重要的类,就是cdownload类,定义如下: 
class cdownload  
{
public:
 void createthread();//开线程
 DWORD finish1();//完成线程
 int sendlist();//发命令1
 downinfo doinfo;//文件信息(与服务器定义一样)
 int startask(int n);开始传文件n
 long m_index;
 BOOL good[BLACK];
 int  filerange[100];
 CString fname;
 CString fnametwo;
 UINT threadfunc(long index);//下载进程

 int sendrequest(int n);//发文件信息
 cdownload(int thno1);
 virtual ~cdownload();
};
下面先介绍sendrequest(int n),在开始前,向服务器发获得文件消息命令,以便让客户端知道有哪些文件可传 
int cdownload::sendrequest(int n)
{
 //建套接字
 sockaddr_in local;
 SOCKET m_socket;

 int rc=0;
 //初使化服务器地址
 local.sin_family=AF_INET;
 local.sin_port=htons(1028);
 local.sin_addr.S_un.S_addr=inet_addr(ip);
 m_socket=socket(AF_INET,SOCK_STREAM,0);

 
 int ret;
 //联接服务器
 ret=connect(m_socket,(LPSOCKADDR)&local,sizeof(local));
 //有错的话
 if(ret<0){
  AfxMessageBox("联接错误");
 closesocket(m_socket);
 return -1;
 }
 //初使化命令
 fileinfo fileinfo1;
 fileinfo1.len=n;
 fileinfo1.seek=50;
 fileinfo1.type=1;
 //发送命令
 int aa=sendn(m_socket,(char*)&fileinfo1,100);
 if(aa<0){
  closesocket(m_socket);
  return -1;
 }
 //接收服务器传来的信息
  aa=readn(m_socket,(char*)&fileinfo1,100);
 if(aa<0){
  closesocket(m_socket);
  return -1;
 }
 //关闭
 shutdown(m_socket,2);
 closesocket(m_socket);

 return 1;
}
有了文件消息后我们就可以下载文件了。在主函数中,用法如下: 
//下载第clno个文件,并为它建一个新cdownload类
down[clno]=new cdownload(clno);
//开始下载,并初使化
type=down[clno]->startask(clno);
//建立各线程
createthread(clno);
下面介绍开始方法: 
//开始方法
int cdownload::startask(int n)
{
 //读入文件长度
 doinfo.filelen=zmfile[n].length;
 //读入名字
 fname=zmfile[n].name;
 CString tmep;
 //初使化文件名
 tmep.Format("\\temp\\%s",fname);

 //给主函数发消息
 CString aaa;
 aaa="正在读取 "+fname+" 信息,马上开始下载。。。\n";
 AfxGetMainWnd()->SendMessageToDescendants(WM_AGE1,(LPARAM)aaa.GetBuffer(0),1);
 aaa.ReleaseBuffer();
 //如果文件长度小于0就返回
 if(doinfo.filelen<=0) return -1;
 //建一个以.down结尾的文件记录文件信息
 CString m_temp;
 m_temp=fname+".down";
 
 doinfo.name=m_temp;
 FILE* fp=NULL;
 CFile myfile;
 //如果是第一次下载文件,初使化各记录文件

 if((fp=fopen(m_temp,"r"))==NULL){
 filerange[0]=0;
 //文件分块
 for(int i=0;i<BLACK;i++)
 {
  if(i>0)
   filerange[i*2]=i*(doinfo.filelen/BLACK+1);
  filerange[i*2+1]=doinfo.filelen/BLACK+1;
 }
 filerange[BLACK*2-1]=doinfo.filelen-filerange[BLACK*2-2];

 myfile.Open(m_temp,CFile::modeCreate|CFile::modeWrite | CFile::typeBinary);

 //写入文件长度
 myfile.Write(&doinfo.filelen,sizeof(int));
 myfile.Close();
 
 CString temp;
 for(int ii=0;ii<BLACK;ii++){
 //初使化各进程记录文件信息(以.downN结尾)

 temp.Format(".down%d",ii);
 m_temp=fname+temp;
 myfile.Open(m_temp,CFile::modeCreate|CFile::modeWrite | CFile::typeBinary);
 //写入各进程文件信息
 myfile.Write(&filerange[ii*2],sizeof(int));
 myfile.Write(&filerange[ii*2+1],sizeof(int));
 myfile.Close();
 }

 ((CMainFrame*)::AfxGetMainWnd())->m_work.m_ListCtrl->AddItemtwo(n,2,0,0,0,doinfo.threadno);
 }
 else{
 //如果文件已存在,说明是续传,读上次信息
 CString temp;
 
 m_temp=fname+".down0";
 if((fp=fopen(m_temp,"r"))==NULL)
  return 1;
 else fclose(fp);

 int bb;
 bb=0;
 //读各进程记录的信息
 for(int ii=0;ii<BLACK;ii++)
 {
  temp.Format(".down%d",ii);
  m_temp=fname+temp;
 
  myfile.Open(m_temp,CFile::modeRead | CFile::typeBinary);
  myfile.Read(&filerange[ii*2],sizeof(int));
  myfile.Read(&filerange[ii*2+1],sizeof(int));
  myfile.Close();

  bb = bb+filerange[ii*2+1];
  CString temp;
 }
 if(bb==0) return 1;
 doinfo.totle=doinfo.filelen-bb;
 
 ((CMainFrame*)::AfxGetMainWnd())->m_work.m_ListCtrl->AddItemtwo(n,2,doinfo.totle,1,0,doinfo.threadno);

 }

  //建立下载结束进程timethread,以管现各进程结束时间。
 DWORD dwthread;
 ::CreateThread(NULL,0,timethread,(LPVOID)this,0,&dwthread);

 return 0;
}
下面介绍建立各进程函数,很简单: 
void CMainFrame::createthread(int threadno)
{
 DWORD dwthread;
 //建立BLACK个进程
 for(int i=0;i<BLACK;i++)
 {
  m_thread[threadno][i]= ::CreateThread(NULL,0,downthread,(LPVOID)down[threadno],0,&dwthread);
 }
}
downthread进程函数 
DWORD WINAPI downthread(LPVOID lpparam)
{
 cdownload* pthis=(cdownload*)lpparam;
 //进程引索+1
 InterlockedIncrement(&pthis->m_index);
 //执行下载进程
 pthis->threadfunc(pthis->m_index-1);
 return 1;
}

上一页  [1] [2] [3] 下一页


相关文章