⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpget.cpp

📁 此程式利用ftp與http協定提供多線程下載及斷點續傳功能
💻 CPP
字号:
// FtpGet.cpp: 实现CFtpGet类.
//
#include "stdafx.h"
#include "FtpGet.h"
#include "DealSocket.h"
#include "Myfile.h"

int CFtpGet::m_nCount;

//---------------------------------------------------------------------------
CFtpGet::CFtpGet()
{
}

//---------------------------------------------------------------------------
CFtpGet::~CFtpGet()
{
}

//---------------------------------------------------------------------------
void CFtpGet::DirList(SOCKET hCtrlSock,BOOL bPasvMode)
{
    SOCKET hDataSock;
	
	if(bPasvMode){
		CString revStr=QueueFtpCmd(hCtrlSock,"PASV");
		CString strHost=GetHost(revStr);
		int nPort=GetPort(revStr);
		hDataSock=dealsocket.GetConnect(strHost,nPort);
		QueueFtpCmd(hCtrlSock,"LIST");
	}
	else{
		SOCKET hLstnSock=InitPortConn(hCtrlSock);
		QueueFtpCmd(hCtrlSock,"LIST");
		hDataSock=accept(hLstnSock,0,0);
	}

	if(hDataSock == INVALID_SOCKET) return;
	
	dealsocket.GetResponse(hDataSock);
}

//---------------------------------------------------------------------------
BOOL CFtpGet::FtpDownLoad(
		CString strHostAddr, 
		int nPort, 
		CString strUserName ,
		CString  strPassword,
		CString strFtpFileName,
		CString strWriteFileName,
		int nSectNum, 
		BOOL bPasvMode)
{
	ASSERT(nSectNum>0);
	SOCKET hCtrlSock=
		ConnectFtp(strHostAddr,nPort,strUserName,strPassword);

	// 下载类型.
	QueueFtpCmd(hCtrlSock,"TYPE","I");

	if(hCtrlSock == INVALID_SOCKET)
		return FALSE;

	// 获取被下载文件长度.
	DWORD nFtpFileSize=GetFtpFileSize(hCtrlSock,strFtpFileName);

	// 把计数器清零.
	m_nCount=0;

	// 给每个线程的信息结构申请内存.
	sectinfo=new CFtpSect[nSectNum];

	// 计算分割段的大小.
	DWORD nSize = nFtpFileSize/nSectNum; 

	int i;
	
	// 创建线程.
	for(i=0;i<nSectNum;i++)
	{
        sectinfo[i].szHostAddr=strHostAddr;
        sectinfo[i].szUserName=strUserName;
        sectinfo[i].szPassword=strPassword;
        sectinfo[i].nPort=nPort;
		sectinfo[i].bPasvMode=bPasvMode;
	    sectinfo[i].szFtpFilename=strFtpFileName; 

		// 计算临时文件名.
		CString strTempFileName;
		strTempFileName.Format("%s_%d",strWriteFileName, i);

        sectinfo[i].szDesFilename=strTempFileName; 

		if(i<nSectNum-1){
			sectinfo[i].nStart=i*nSize;
			sectinfo[i].nEnd=(i+1)*nSize;
		}
		else{
			sectinfo[i].nStart=i*nSize;
			sectinfo[i].nEnd=nFtpFileSize;
		}

		// AfxBeginThread(ThreadDownLoad,&sectinfo[i],THREAD_PRIORITY_HIGHEST);
		AfxBeginThread(ThreadDownLoad,&sectinfo[i]);
	}

	// 等待所有线程结束.
	while(m_nCount!=nSectNum);			

	FILE *fpwrite;

 	// 打开写文件.
	if((fpwrite=fopen(strWriteFileName,"wb"))==NULL){
  		return FALSE;
	}

	for(i=0;i<nSectNum;i++)
	{
		FileCombine(&sectinfo[i],fpwrite);
	}

	fclose(fpwrite);
	delete[] sectinfo;
    
    return TRUE;
}

//---------------------------------------------------------------------------
UINT CFtpGet::ThreadDownLoad(void* pParam)
{
	CFtpSect *pInfo=(CFtpSect*)pParam;

	TRACE("Starting and ending pos: %s %d %d\n",
	        pInfo->szDesFilename, pInfo->nStart, pInfo->nEnd);

	SOCKET hCtrlSock=ConnectFtp(pInfo->szHostAddr,pInfo->nPort,
		pInfo->szUserName,pInfo->szPassword);
	if(hCtrlSock == INVALID_SOCKET) return 1;

	// 下载类型.
	QueueFtpCmd(hCtrlSock,"TYPE","I");

	// 计算临时文件大小.
	DWORD nFileSize=myfile.GetFileSizeByName(pInfo->szDesFilename);
    DWORD nSectSize=(pInfo->nEnd)-(pInfo->nStart);

	// 此段已下载完毕.
	if(nFileSize==nSectSize){
		TRACE("文件已下载完毕!\n");
		CFtpGet::m_nCount++;  // 计数.
		return 0;
	}

    FILE *fpwrite=myfile.GetFilePointer(pInfo->szDesFilename);
	if(!fpwrite) return 1;

	// 设置文件读取起始位置,请注意此命令所在位置的顺序.
	SetFilePos(hCtrlSock,pInfo->nStart+nFileSize);
	fseek(fpwrite,nFileSize,SEEK_SET);

	SOCKET hDataSock;
	
	if(pInfo->bPasvMode){
		CString revStr=QueueFtpCmd(hCtrlSock,"PASV");
		CString strHost=GetHost(revStr);
		int nPort=GetPort(revStr);
		if((hDataSock=dealsocket.GetConnect(strHost,nPort))
			== INVALID_SOCKET) return 1;
		QueueFtpCmd(hCtrlSock,"RETR",pInfo->szFtpFilename);
	}
	else{
		SOCKET hLstnSock=InitPortConn(hCtrlSock);
		QueueFtpCmd(hCtrlSock,"RETR",pInfo->szFtpFilename);
		if((hDataSock=accept(hLstnSock,0,0))==INVALID_SOCKET)
			return 1;
	}
	
	DWORD nLen; 
	DWORD nSumLen=0; 
	char szBuffer[1024];

	while(1)
	{
		if(nSumLen>=nSectSize-nFileSize) break;
		nLen=recv(hDataSock,szBuffer,sizeof(szBuffer),0);
		if (nLen == SOCKET_ERROR){
			TRACE("Read error!\n");
			fclose(fpwrite);
			return 1;
		}

  		if(nLen==0) break;
		nSumLen +=nLen;
		TRACE("%d\n",nLen);

		// 把数据写入文件.		
		fwrite(szBuffer,nLen,1,fpwrite);
	}

    // 关闭写文件.
	fclose(fpwrite);

	// 关闭套接字.
	closesocket(hDataSock);
	closesocket(hCtrlSock);

	// 计数.
	CFtpGet::m_nCount++;
	return 0;
}

//---------------------------------------------------------------------------
BOOL CFtpGet::FileCombine(CFtpSect *pInfo, FILE *fpwrite)
{	
	FILE *fpread;
	
	// 打开文件.
	if((fpread=fopen(pInfo->szDesFilename,"rb"))==NULL)
		return FALSE;

	DWORD nPos=pInfo->nStart;
	
	// 设置文件写指针起始位置.
	fseek(fpwrite,nPos,SEEK_SET);
	
	int c;
	// 把文件数据写入到子文件.		
	while((c=fgetc(fpread))!=EOF)
	{
		fputc(c,fpwrite);
		nPos++;
		if(nPos==pInfo->nEnd) break;
	}
	
	fclose(fpread);
	DeleteFile(pInfo->szDesFilename);

	return TRUE;
}

//---------------------------------------------------------------------------
CString CFtpGet::QueueFtpCmd(SOCKET hSock,CString strCmd,CString strDescr)
{
	CString str;
	str.Format("%s %s\r\n",strCmd,strDescr);
    send(hSock,str,str.GetLength(),0);
    return dealsocket.GetResponse(hSock);
}

//---------------------------------------------------------------------------
CString CFtpGet::GetHost(CString pasvStr)
{
    int index1 = pasvStr.Find("(");
    int index2 = pasvStr.Find(")");
	CString newstr=pasvStr.Mid(index1+1,index2-index1);
   
	int a1,a2,a3,a4,p1,p2;
	sscanf(newstr,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2);
     
	CString strHost;
	strHost.Format("%d.%d.%d.%d",a1,a2,a3,a4);
    return strHost;
}

//---------------------------------------------------------------------------
int CFtpGet::GetPort(CString pasvStr)
{
    int index1 = pasvStr.Find("(");
    int index2 = pasvStr.Find(")");
	CString newstr=pasvStr.Mid(index1+1,index2-index1);
   
	int a1,a2,a3,a4,p1,p2;
	sscanf(newstr,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2);
   
	return p1*256 + p2;
}

//---------------------------------------------------------------------------
SOCKET CFtpGet::ConnectFtp(CString host,int port,CString userName,CString pass)
{
	TRACE("正在建立连接\n");

    SOCKET hCtrlSock=dealsocket.GetConnect(host,port);
	if(hCtrlSock == INVALID_SOCKET){
		TRACE("连接ftp服务器失败!\n");
		return INVALID_SOCKET;
	}

    dealsocket.GetResponse(hCtrlSock);
	CString revStr=QueueFtpCmd(hCtrlSock,"USER",userName);

	if(GetCode(revStr) == 331)
	{
		TRACE("服务器要求验证密码...\n");
	    revStr=QueueFtpCmd(hCtrlSock,"PASS",pass);
		int tryTimes = 3;
		while(GetCode(revStr)!= 230 && tryTimes > 0)
		{
 	        revStr=QueueFtpCmd(hCtrlSock,"PASS",pass);
			tryTimes--;
			TRACE("第%d尝试\n",3-tryTimes);
		}
		
		if(tryTimes < 0)
		{
			TRACE(userName +"登录失败!\n");
			return INVALID_SOCKET;
		}
		else
			TRACE("登录成功!\n");
	}

	return hCtrlSock;
}

//---------------------------------------------------------------------------
DWORD CFtpGet::GetFtpFileSize(SOCKET hCtrlSock ,CString fileName)
{
    CString revStr=QueueFtpCmd(hCtrlSock,"SIZE",fileName);
	if(GetCode(revStr) != 213)
	{
		TRACE("尝试第二次获取\n");
        revStr=QueueFtpCmd(hCtrlSock,"SIZE",fileName);
		if(GetCode(revStr) != 213)
		{
			TRACE("尝试第三次获取\n");
            revStr=QueueFtpCmd(hCtrlSock,"SIZE",fileName);
			if(GetCode(revStr) != 213)	{
				TRACE("获取文件大小失败!");
				return 0;
			}
		}
	}
	
	int index =  revStr.Find("\r\n");
	revStr = revStr.Mid(0,index);
	index = revStr.Find(" ");
	revStr = revStr.Mid(index,revStr.GetLength()- index);

	DWORD fileSize  =atoi(revStr);
	return fileSize;
}

//---------------------------------------------------------------------------
BOOL CFtpGet::SetFilePos(SOCKET hCtrlSock,DWORD pos)
{
	CString strPos;
	strPos.Format("%d",pos);
 	CString  revStr=QueueFtpCmd(hCtrlSock,"REST",strPos);
	if(GetCode(revStr) != 350) 
		return FALSE;
	return TRUE;
}

//---------------------------------------------------------------------------
UINT CFtpGet::GetCode(CString revStr)
{
	if(revStr.IsEmpty()) return 0;
	CString str;
	int index ;
	index = revStr.Find(" ");
	str = revStr.Mid(0,index);
	return atoi(str);
}

//---------------------------------------------------------------------------
SOCKET CFtpGet::InitPortConn(SOCKET hCtrlSock)
{
 	SOCKADDR_IN sockCtlAddr;
	SOCKADDR_IN sockLsnAddr;

    SOCKET hLstnSock=dealsocket.Listening(0);
    int nLen = sizeof(SOCKADDR_IN);

	if (hLstnSock == SOCKET_ERROR) {
		closesocket(hLstnSock);
		return INVALID_SOCKET;
	}

	if(getsockname(hLstnSock,(LPSOCKADDR)&sockLsnAddr,(int *)&nLen)
		== SOCKET_ERROR)
	{
		return INVALID_SOCKET;
	}

	if(getsockname(hCtrlSock,(LPSOCKADDR)&sockCtlAddr,(int *)&nLen)
		== SOCKET_ERROR)
	{
		return INVALID_SOCKET;
	}
	
	CString strPort;
	strPort.Format("%d,%d,%d,%d,%d,%d", 
          sockCtlAddr.sin_addr.S_un.S_un_b.s_b1,  // 本地地址.
          sockCtlAddr.sin_addr.S_un.S_un_b.s_b2,
          sockCtlAddr.sin_addr.S_un.S_un_b.s_b3,
          sockCtlAddr.sin_addr.S_un.S_un_b.s_b4,
          sockLsnAddr.sin_port & 0xFF,            // 本地端口.
          (sockLsnAddr.sin_port & 0xFF00)>>8);

	QueueFtpCmd(hCtrlSock,"PORT",strPort);

	return hLstnSock;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -