断点续传的实现

要做个局域网内的资源共享软件。当然少不了下载模块了。下载模块不要求多线程(毕竟局域网内的网速还是可以的····),但至少要支持断点续传。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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值