www.pudn.com > download.rar > FTPDownload.cpp


// FTPDownload.cpp: implementation of the CFTPDownload class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "download.h" 
#include "FTPDownload.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
 DWORD WINAPI FTPDownloadThread(LPVOID); 
 DWORD WINAPI FTPNotify(LPVOID);  
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
 
 /*这个类主要包含关于FTP下载的各种函数*/ 
 CFTPDownload::CFTPDownload() 
{ 
    for(int  i=0; i<10; i++){ 
		m_hThread[i] = NULL; 
		m_bTerminate[i] = FALSE; 
		m_sum[i]=0; 
		hh[i]=0; 
	  } 
     
	m_bResume = FALSE; 
 
} 
 
CFTPDownload::~CFTPDownload() 
{ 
 
} 
 
//开始任务函数,主要进行地址的分析,并调用创建线程函数开始下载任务。 
void CFTPDownload::Begin(CString Allurl, CString Saveas, int nParts,CString User,CString Pass) 
{ 
    for( int i=0; i<10; i++){ 
		  m_bTerminate[i] = FALSE; 
		  m_state.wcsize[i] = 0;//用来记录暂停时下载文件的大小 
		  m_sum[i] = 0; 
		  hh[i]=0; 
     } 
	 
	m_strSavePath = Saveas; 
    m_nParts = nParts; 
	m_strUser = User; 
	m_strPass = Pass; 
	 
	if(!(AnalyseURL(Allurl))){AfxMessageBox("URL错误,请确认地址正确"); return;}//调用分析地址函数 
	if(!(SendRequest())) {AfxMessageBox("服务器连接错误"); return;}//调用发送请求函数 
    m_strTempSavePath = m_strSavePath; 
	m_strTempSavePath += ".down"; 
	 
	//判断文件是否下载过 
	FILE* fp = NULL; 
	if((fp = fopen(m_strTempSavePath, "r")) == NULL){ 
		m_state.range[0] = -1; 
		m_bResume = FALSE; 
	} 
	else{ 
		m_bResume = TRUE; 
        fread(m_state.range, sizeof(LONG), 2*nParts, fp); 
		fread(m_state.threadsize, sizeof(LONG), nParts, fp); 
		fread(m_state.wcsize, sizeof(LONG), nParts, fp); 
		fclose(fp); 
		DeleteFile(m_strTempSavePath); 
	} 
 
    if(m_state.range[0] == -1){ 
		 
 
	//计算并分配每个线程的任务 
	for(int i = 0; i < m_nParts; i++){ 
			m_state.range[i * 2] = i * (filesize /m_nParts); 
			m_state.range[i * 2 + 1] = (i + 1) * (filesize / m_nParts) ; 
            m_state.threadsize[i] = m_state.range[i * 2 + 1] - m_state.range[i * 2];//每个线程的任务总大小 
		} 
		m_state.range[2*m_nParts-1] = filesize; 
		m_state.threadsize[m_nParts-1] = m_state.range[2*m_nParts-1] - m_state.range[2*m_nParts-2]; 
 
	} 
     
    CreateThread(); //调用创建线程的任务 
    return; 
 
} 
 
//分析地址的函数,将地址分为服务器与文件绝对路径,并获得文件名,用户名密码 
BOOL CFTPDownload::AnalyseURL(CString Allurl) 
{ 
	m_strServer = _T(""); 
	m_strObject = _T(""); 
	m_Port	  = 0; 
    Allurl.TrimLeft(); 
	Allurl.TrimRight(); 
	CString strTemp; 
	int n=Allurl.Find("://"); 
	if(n == -1)  return FALSE;  
	strTemp = Allurl.Mid(n+3); 
	 
    n=strTemp.Find('/'); 
	if(n == -1)  return FALSE; 
	m_strServer = strTemp.Left(n); 
	m_strObject = strTemp.Mid(n); 
     
	n = m_strServer.ReverseFind(':'); 
	int m = m_strServer.Find("@"); 
	if(n > m) 
	{ 
        CString temp = m_strServer.Mid(n+1); 
        m_Port = (USHORT)_ttoi((LPCTSTR)temp); 
		m_strServer = m_strServer.Left(n); 
	} 
	else 
	{ 
		m_Port = 21; 
	} 
     
	if(m != -1) 
	{ 
		strTemp.Empty(); 
		strTemp = m_strServer.Left(m); 
        m_strServer =m_strServer.Mid(m+1); 
		n = strTemp.Find(':'); 
		if(n==-1) return FALSE; 
		m_strUser = strTemp.Left(n); 
		m_strPass = strTemp.Mid(n+1); 
	} 
 
    return TRUE; 
} 
 
//向服务器发送第一次请求,登陆服务器 
BOOL CFTPDownload::SendRequest() 
{ 
   if(FSocket.m_hSocket!= NULL) FSocket.Close(); 
   FSocket.Create(); 
   FSocket.Connect(m_strServer, m_Port); 
 
   ZeroMemory(ReadBuf,1025); 
   FSocket.Receive(ReadBuf, 1025); 
   strRead.Empty(); 
   strRead+= ReadBuf; 
   if(!(AnalyseReceive(strRead))) {AfxMessageBox("连接错误,请确认地址正确"); return FALSE; } 
 
   strSend.Empty();  
   strSend ="USER "+m_strUser+"\r\n"; 
   SendInf(strSend); 
 
   strSend.Empty();  
   strSend ="PASS "+m_strPass+"\r\n"; 
   SendInf(strSend); 
 
   strSend.Empty();  
   strSend ="SIZE "+m_strObject+"\r\n"; 
   SendInf(strSend); 
 
   FSocket.Close(); 
 
   return TRUE; 
} 
 
//发送请求时接受服务器返回信息,并分析 
BOOL CFTPDownload::AnalyseReceive(CString strRead) 
{ 
	DWORD Code; 
	 
	int n = strRead.Find(" "); 
	CString temp = strRead.Left(n); 
    Code = (DWORD)_ttoi((LPCTSTR)temp); 
	if(Code<400)  return TRUE; 
	else return FALSE; 
 
} 
 
 
void  CFTPDownload::SendInf(CString strSend) 
{ 
   FSocket.Send(strSend.GetBuffer(0), strSend.GetLength()); 
   ZeroMemory(ReadBuf,1025); 
   FSocket.Receive(ReadBuf, 1025); 
   strRead.Empty(); 
   strRead+= ReadBuf; 
   if(!(AnalyseReceive(strRead))) {AfxMessageBox("连接错误,请确认地址正确"); return; } 
   int n = strSend.Find(" "); 
   strSend = strSend.Left(n); 
   if(strSend=="SIZE") SizeOf(strRead);//如果发送获取大小请求后,获取文件大小 
} 
 
//结合上面函数获得下载大小 
void CFTPDownload::SizeOf(CString strRead) 
{ 
	CString temp; 
	int n = strRead.Find(" "); 
	temp = strRead.Mid(n+1); 
	filesize = (DWORD)_ttoi((LPCTSTR)temp); 
} 
 
 
//创建线程函数 
void CFTPDownload::CreateThread() 
{ 
	DWORD dwThread; 
	m_index = 0; 
	for(int i = 0; i < m_nParts; i++) 
	{ 
		m_bTerminate[i] = FALSE; 
		m_hThread[i] = ::CreateThread(NULL, 0, FTPDownloadThread,  (LPVOID)this, 0, &dwThread); 
 
	} 
    DWORD dwNotify; 
	m_hNotify = ::CreateThread(NULL, 0, FTPNotify, (LPVOID)this, 0, &dwNotify); 
} 
 
DWORD WINAPI FTPDownloadThread(LPVOID lpParam) 
{ 
	CFTPDownload* pThis = (CFTPDownload*)lpParam; 
	int index; 
	index = pThis->m_index; 
	InterlockedIncrement(&pThis->m_index); 
    pThis->ThreadFunc(index); 
	return 0L; 
} 
 
DWORD WINAPI FTPNotify(LPVOID lpParam) 
{ 
    CFTPDownload* pThis = (CFTPDownload*)lpParam; 
    pThis->Finish(); 
	return 0L; 
} 
 
//实际下载函数,向服务器发送下载请求 
void CFTPDownload::ThreadFunc(int index) 
{ 
    if(m_state.range[2*index] ==-99) { hh[index]=1000; m_sum[index]=m_state.threadsize[index]; return;}//用来判断此线程是否已经结束 
	 
	CSocket tSocket,readsocket; 
	tSocket.Create(); 
    tSocket.Connect(m_strServer, m_Port); 
 
	CString strSend,strRead; 
	char	 ReadBuf[1025]; 
 
   ZeroMemory(ReadBuf,1025); 
   tSocket.Receive(ReadBuf, 1025); 
   strRead.Empty(); 
   strRead+= ReadBuf; 
   if(!(AnalyseReceive(strRead))) {AfxMessageBox("线程连接错误,建议减少线程重试"); m_bTerminate[0] = TRUE;return; } 
 
   strSend.Empty();  
   strSend ="USER "+m_strUser+"\r\n"; 
   tSocket.Send(strSend.GetBuffer(0), strSend.GetLength()); 
   ZeroMemory(ReadBuf,1025); 
   tSocket.Receive(ReadBuf, 1025); 
   strRead.Empty(); 
   strRead+= ReadBuf; 
   if(!(AnalyseReceive(strRead))) {AfxMessageBox("线程连接错误,建议减少线程重试"); m_bTerminate[0] = TRUE;return; } 
 
   strSend.Empty();  
   strSend ="PASS "+m_strPass+"\r\n"; 
   tSocket.Send(strSend.GetBuffer(0), strSend.GetLength()); 
   ZeroMemory(ReadBuf,1025); 
   tSocket.Receive(ReadBuf, 1025); 
   strRead.Empty(); 
   strRead+= ReadBuf; 
   if(!(AnalyseReceive(strRead))) {AfxMessageBox("线程连接错误,建议减少线程重试"); m_bTerminate[0] = TRUE;return; } 
 
   strSend.Empty();  
   strSend ="TYPE I\r\n"; 
   tSocket.Send(strSend.GetBuffer(0), strSend.GetLength()); 
   ZeroMemory(ReadBuf,1025); 
   tSocket.Receive(ReadBuf, 1025); 
   strRead.Empty(); 
   strRead+= ReadBuf; 
   if(!(AnalyseReceive(strRead))) {AfxMessageBox("线程连接错误,建议减少线程重试"); m_bTerminate[0] = TRUE;return; } 
 
   strSend.Empty();  
   strSend.Format("REST %d\r\n",m_state.range[2*index]); 
   tSocket.Send(strSend.GetBuffer(0), strSend.GetLength()); 
   ZeroMemory(ReadBuf,1025); 
   tSocket.Receive(ReadBuf, 1025); 
   strRead.Empty(); 
   strRead+= ReadBuf; 
   if(!(AnalyseReceive(strRead))) {AfxMessageBox("线程连接错误,建议减少线程重试");m_bTerminate[0] = TRUE; return; } 
 
 
   //被动传输模式,获得服务器提供的地址端口 
   strSend.Empty();  
   strSend ="PASV\r\n"; 
   tSocket.Send(strSend.GetBuffer(0), strSend.GetLength()); 
   ZeroMemory(ReadBuf,1025); 
   tSocket.Receive(ReadBuf, 1025); 
   strRead.Empty(); 
   strRead+= ReadBuf; 
    
 
   int i = strRead.Find("("); int j = strRead.Find(")"); 
   CString temp = strRead.Mid(i+1,(j-i)-1); 
    
   //将服务器传回的地址信息进行格式转换 
   i = temp.ReverseFind(','); 
   UINT  port = atol(temp.Mid(i+1)); 
   temp = temp.Left(i); 
   i = temp.ReverseFind(','); 
   port += 256*atol(temp.Mid(i+1)); 
   CString rhost = temp.Left(i); 
   while(1) 
   { 
	   if((i=rhost.Find(','))==-1) break; 
	   rhost.SetAt(i,'.'); 
   } 
 
   strSend.Empty();  
   strSend ="RETR "+m_strObject+"\r\n"; 
   tSocket.Send(strSend.GetBuffer(0), strSend.GetLength()); 
 
   readsocket.Create(); 
   readsocket.Connect(rhost,port); 
  
   CFile file; 
   CString name; 
   name.Format(".down%d", index); 
   name =m_strSavePath + name; 
   	if(!m_bResume) 
		 file.Open(name, CFile::modeCreate | CFile::modeWrite); 
	else 
		 file.Open(name, CFile::modeWrite); 
   file.SeekToEnd(); 
 
   DWORD num,sum; sum=0; 
   dwsize[index] = m_state.range[2*index+1]-m_state.range[2*index]; 
    
   //循环接受服务器发送的数据 
   while(1) 
   { 
	  if(m_bTerminate[index]) { 
      m_state.range[2 * index] = m_state.range[2 * index] + sum; 
	  m_state.wcsize[index] = m_sum[index]; 
	  return ; 
	  } 
      ZeroMemory(ReadBuf,1025); 
      if( sum >= dwsize[index]  || !(num = readsocket.Receive(ReadBuf, 1025)) || num == SOCKET_ERROR) break; 
	  else   file.Write(ReadBuf, num); 
      sum+=num;  
	        //进度条显示需要的一些变量 
			m_sum[index]=sum+m_state.wcsize[index]; 
			hh[index]=  long((1.0*m_sum[index])*1000/m_state.threadsize[index]); 
   } 
    
 
   file.Close(); 
   readsocket.Close(); 
   tSocket.Close(); 
    
   m_state.range[2*index]= -99;//用来判断此线程是否已经结束的标志 
   return; 
} 
 
//全部线程结束后调用的完成函数 
void CFTPDownload::Finish() 
{ 
	char* lpData = NULL; 
    HRESULT ret = WaitForMultipleObjects(m_nParts, m_hThread, TRUE, INFINITE); 
	if(m_bTerminate[0]){ 
		return; 
	} 
	//如果线程结束正常,就分别打开临时文件将其依次写入目标文件 
	if(ret == 0){ 
	     
		CFile file, t[10]; 
		CString name; 
		file.Open(m_strSavePath, CFile::modeCreate | CFile::modeWrite); 
		for(int i = 0; i