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

在如今的网络应用中,文件的传送是重要的功能之一,也是共享的基础。一些重要的协议像HTTP,FTP等都支持文件的传送。尤其是FTP,它的全称就是“文件传送协议”,当 初的工程师设计这一协议就是为了解决网络间的文件传送问题,而且以其稳定,高速,简单而一直保持着很大的生命力。作为一个程序员,使用这些现有的协议传送文件相当简单,不过,它们只适用于服务器模式中。这样,当我们想在点与点之间传送文件就不适用了或相当麻烦,有一种大刀小用的意味。笔者一直想寻求一种简单有效,且具备多线程断点续传的方法来实现点与点之间的文件传送问题,经过大量的翻阅资料与测试,终于实现了,现把它共享出来,与大家分享。
我写了一个以此为基础的实用程序(网络传圣,包含源代码),可用了基于TCP/IP的电脑上,供大家学习。
upload/2004_06/04062118541204.gif
(本文源代码运行效果图) 

实现方法(VC++,基于TCP/IP协议)如下:
仍釆用服务器与客户模式,需分别对其设计与编程。
服务器端较简单,主要就是加入待传文件,监听客户,和传送文件。而那些断点续传的功能,以及文件的管理都放在客户端上。

 一、服务器端

首先介绍服务器端:
最开始我们要定义一个简单的协议,也就是定义一个服务器端与客户端听得懂的语言。而为了把问题简化,我就让服务器只要听懂两句话,一就是客户说“我要读文件信息”,二就是“我准备好了,可以传文件了”。
由于要实现多线程,必须把功能独立出来,且包装成线程,首先建一个监听线程,主要负责接入客户,并启动另一个客户线程。我用VC++实现如下:

DWORD WINAPI listenthread(LPVOID lpparam)


    //由主函数传来的套接字
  SOCKET  pthis=(SOCKET)lpparam;
    //开始监听
 int rc=listen(pthis,30);
    //如果错就显示信息
    if(rc<0){
   CString aaa;
   aaa="listen错误\n";
      AfxGetMainWnd()->SendMessageToDescendants(WM_AGE1,(LPARAM)aaa.GetBuffer(0),1);
   aaa.ReleaseBuffer();
   return 0;
 }
    //进入循环,并接收到来的套接字
 while(1){
    //新建一个套接字,用于客户端
 SOCKET s1;
 s1=accept(pthis,NULL,NULL);
 
   //给主函数发有人联入消息
    CString aa;
    aa="一人联入!\n";
    AfxGetMainWnd()->SendMessageToDescendants(WM_AGE1,(LPARAM)aa.GetBuffer(0),1);
 aa.ReleaseBuffer();
 DWORD dwthread;
    //建立用户线程
 ::CreateThread(NULL,0,clientthread,(LPVOID)s1,0,&dwthread); 
 }
 return 0;
}

接着我们来看用户线程:
先看文件消息类定义:

struct fileinfo
{
 int fileno;//文件号
 int type;//客户端想说什么(前面那两句话,用1,2表示)
 long len;//文件长度
 int seek;//文件开始位置,用于多线程

 char name[100];//文件名
};

用户线程函数: 
DWORD WINAPI clientthread(LPVOID lpparam)
{
 //文件消息
 fileinfo* fiinfo;
 //接收缓存
 char* m_buf;
 m_buf=new char[100];
 //监听函数传来的用户套接字
 SOCKET  pthis=(SOCKET)lpparam;
 //读传来的信息
 int aa=readn(pthis,m_buf,100);
 //如果有错就返回
 if(aa<0){
  closesocket (pthis);
  return -1;
 }
 //把传来的信息转为定义的文件信息
 fiinfo=(fileinfo*)m_buf;
 CString aaa;
 //检验客户想说什么
 switch(fiinfo->type)
 {
 //我要读文件信息
 case 0:
 //读文件
 aa=sendn(pthis,(char*)zmfile,1080);
 //有错
 if(aa<0){ 
  closesocket (pthis);
  return -1;
 }
 //发消息给主函数
 aaa="收到LIST命令\n";
     AfxGetMainWnd()->SendMessageToDescendants(WM_AGE1,(LPARAM)aaa.GetBuffer(0),1);
 break;
 //我准备好了,可以传文件了

 case 2:
 //发文件消息给主函数
 aaa.Format("%s  文件被请求!%s\n",zmfile[fiinfo->fileno].name,nameph[fiinfo->fileno]);
 AfxGetMainWnd()->SendMessageToDescendants(WM_AGE1,(LPARAM)aaa.GetBuffer(0),1);
 //读文件,并传送
 readfile(pthis,fiinfo->seek,fiinfo->len,fiinfo->fileno);
 //听不懂你说什么

 default:
 aaa="接收协议错误!\n";
     AfxGetMainWnd()->SendMessageToDescendants(WM_AGE1,(LPARAM)aaa.GetBuffer(0),1);
 break;
}

 return 0;
}
读文件函数 
void readfile(SOCKET  so,int seek,int len,int fino)
{
 //文件名
 CString myname;
 myname.Format("%s",nameph[fino]);
 CFile myFile;
 //打开文件
 myFile.Open(myname, CFile::modeRead | CFile::typeBinary|CFile::shareDenyNone); 
 //传到指定位置 
 myFile.Seek(seek,CFile::begin);
 char m_buf[SIZE];
 int len2;
 int len1;
 len1=len;
 //开始接收,直到发完整个文件
 while(len1>0){
  len2=len>SIZE?SIZE:len;
  myFile.Read(m_buf, len2);
  int aa=sendn(so,m_buf,len2);
 if(aa<0){ 
  closesocket (so);
  break;
 }
 len1=len1-aa;
 len=len-aa;
 }
 myFile.Close();
}

服务器端最要的功能各技术就是这些,下面介绍客户端。

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


相关文章