要做个局域网内的资源共享软件。当然少不了下载模块了。下载模块不要求多线程(毕竟局域网内的网速还是可以的····),但至少要支持断点续传。Ftp是可以的,不过貌似有点大了,更适合有服务器的网络模式。而我的环境是点对点的文件传输,因此杀鸡焉能用牛刀。
好了。文件传输的原理就是建立socket连接,然后通过send()和recv()来传送文件信息。当然比较小的文件,可以一次传完。但对于上百兆、上G的资料,我们就要先将文件划分成块后,在进行传送。如何实现断点续传呢?很简单首先要记录断点。比如文件被划分为10个小块。但我传输了3块时,就在本地保存一个flag=3。等下次文件续传时,先检查flag值。通过seek()函数将待传文件指针和已接受的文件指针都移动到要续传的位置。如此就实现了续传功能。
我把文件发送接收的功能都封装在了FileTransport类中。
//.h
class FileTransport
{
public:
FileTransport(void);
~FileTransport(void);
public:
void Sent(CString FilePath); //FilePath是要传文件的路径
void Down(char* ip); //ip是服务器端得ip地址
private:
void GetFileProc(int nCurrentPos,SOCKET client,CString FilePath);
};
//.cpp
#include "StdAfx.h"
#include "FileTransport.h"
#define CHUNK_SIZE (64*1024)
FileTransport::FileTransport(void)
{
}
FileTransport::~FileTransport(void)
{
}
void FileTransport::GetFileProc(int nCurrentPos,SOCKET client,CString FilePath)
{
CFile file;
int nChunkCount=0; //文件块数
//CString FilePath(_T("D://file.rar"));
if(file.Open(FilePath,CFile::modeRead|CFile::typeBinary))
{
if(nCurrentPos!=0)
{
file.Seek(nCurrentPos*CHUNK_SIZE,CFile::begin); //文件指针移至断点处
//MessageBox(L"file seek is "+nCurrentPos*CHUNK_SIZE);
}
int FileLen=file.GetLength();
nChunkCount=FileLen/CHUNK_SIZE; //文件块数
if(FileLen%CHUNK_SIZE!=0)
nChunkCount++;
send(client,(char*)&FileLen,sizeof(FileLen),0); //发送文件长度
char *date=new char[CHUNK_SIZE];
for(int i=nCurrentPos;i<nChunkCount;i++) //从断点处分块发送
{
// MessageBox(L"send the count"+i);
int nLeft;
if(i+1==nChunkCount) //最后一块
nLeft=FileLen-CHUNK_SIZE*(nChunkCount-1);
else
nLeft=CHUNK_SIZE;
int idx=0;
file.Read(date,CHUNK_SIZE);
while(nLeft>0)
{
int ret=send(client,&date[idx],nLeft,0);
if(ret==SOCKET_ERROR)
{
//MessageBox(L"Send The Date Error");
break;
}
nLeft-=ret;
idx+=ret;
}
}
file.Close();
delete[] date;
}else
{
// MessageBox(L"open the file error");
}
}
void FileTransport::Sent(CString FilePath)
{
WSADATA data;
WORD w=MAKEWORD(2,0);
::WSAStartup(w,&data);
SOCKET server,client;
server=::socket(AF_INET,SOCK_STREAM,0);
sockaddr_in addr,clientaddr;
addr.sin_family=AF_INET;
addr.sin_port=htons(75);
addr.sin_addr.S_un.S_addr=INADDR_ANY;
::bind(server,(sockaddr*)&addr,sizeof(addr));
::listen(server,2);
int n=sizeof(clientaddr);
while(true)
{
client=::accept(server,(sockaddr *)&clientaddr,&n);
if(client!=NULL)
{
//MessageBox(L"have one connect");
int nCurrentPos=0;//接受断点值
if(recv(client,(char*)&nCurrentPos,sizeof(nCurrentPos),0)==SOCKET_ERROR)
{
//MessageBox(L"The Clinet Socket is Closed");
break;
}else
{
//MessageBox(L"The Currentpos is The"+nCurrentPos);
GetFileProc(nCurrentPos,client,FilePath);
}
}
}
MessageBox(NULL,_T("传输结束"),NULL,NULL);
closesocket(server);
closesocket(client);
WSACleanup();
::closesocket(server);
::closesocket(client);
::WSACleanup();
}
void FileTransport::Down(char* ip)
{
//保存文件位置
CString recv_file_name;
CFileDialog dlg(FALSE,_T("*.txt"),_T(".txt"),NULL,_T("All Files (*.*)|*.*||"));
if(dlg.DoModal() == IDOK)
{
recv_file_name = dlg.GetPathName();
}
WSADATA data; //定义WSADATA结构体对象
WORD w=MAKEWORD(2,0); //定义版本号码
::WSAStartup(w,&data); //初始化套接字库
char text[100]={0};
SOCKET client; //定义连接套接字和数据收发套接字句柄
char sztext[10]={0};
client=::socket(AF_INET,SOCK_STREAM,0); //创建TCP套接字
sockaddr_in serveraddr; //定义套接字地址结构
serveraddr.sin_family=AF_INET; //初始化地址结构
serveraddr.sin_port=htons(75);
serveraddr.sin_addr.S_un.S_addr=inet_addr(ip);
if(connect(client,(SOCKADDR*)&serveraddr,sizeof(serveraddr))==INVALID_SOCKET)
{
MessageBox(NULL,L"Connect Server Error",NULL,NULL);
}
int FileLen=0;
int nCurrentPos=0; //断点位置
UINT OpenFlags;
CFile PosFile;
if(PosFile.Open(_T("PosFile.temp"),CFile::modeRead|CFile::typeBinary))//如果有临时文件则读取断点
{
PosFile.Read((char*)&nCurrentPos,sizeof(nCurrentPos)); //读取断点位置
//MessageBox(L"The File Pos is "+nCurrentPos);
nCurrentPos=nCurrentPos+1; //从断点的下一块开始
PosFile.Close();
send(client,(char*)&nCurrentPos,sizeof(nCurrentPos),0); //发送断点值
OpenFlags=CFile::modeWrite|CFile::typeBinary; //文件为可写
}
else
{
send(client,(char*)&nCurrentPos,sizeof(nCurrentPos),0); //无断点文件nCurrentPos为0
OpenFlags=CFile::modeWrite|CFile::typeBinary|CFile::modeCreate;//创建文件方式
}
if(recv(client,(char*)&FileLen,sizeof(FileLen),0)!=0)//接受文件长度
{
int nChunkCount;
CFile file;
nChunkCount=FileLen/CHUNK_SIZE; //计算文件块数
if(FileLen%CHUNK_SIZE!=0)
{
nChunkCount++;
}
if(file.Open(recv_file_name,OpenFlags))
{
file.Seek(nCurrentPos*CHUNK_SIZE,CFile::begin); //文件指针移至断点处
char *date = new char[CHUNK_SIZE];
for(int i=nCurrentPos;i<nChunkCount;i++) //从断点处开始写入文件
{
//MessageBox(L"Recv The Chunk is "+i);
int nLeft,nCount;
if(i+1==nChunkCount) //最后一块
nCount=nLeft=FileLen-CHUNK_SIZE*(nChunkCount-1);
else
nCount=nLeft=CHUNK_SIZE;
int idx=0;
while(nLeft>0)
{
int ret=recv(client,&date[idx],nLeft,0);
if(ret==SOCKET_ERROR)
{
//MessageBox(L"Recv Date Error");
}
idx+=ret;
nLeft-=ret;
}
file.Write(date,nCount);
CFile PosFile; //将断点写入PosFile.temp文件
int seekpos=i+1;
if(PosFile.Open(_T("PosFile.temp"),CFile::modeWrite|CFile::typeBinary|CFile::modeCreate))
{
PosFile.Write((char*)&seekpos,sizeof(seekpos));
PosFile.Close();
}
}
file.Close();
delete[] date;
}
if(DeleteFile(_T("PosFile.temp"))!=0)
{
MessageBox(NULL,L"文件传输完成",NULL,NULL);
}
}
::closesocket(client); //关闭套接字句柄
::WSACleanup();
}
测试了~~~~0k