CMultiFTP類原始碼 (轉)
為了讓大家更好的理解我發表的<>,我把我自己編寫的CMultiFTP類貼上來。這段程式碼我不是很滿意(以前寫的,請寫的較倉促),
但主要供大家參考,更好得理解多執行緒下載的實現。
// MultiFTP1.cpp: implementation of the CMultiFTP class.
//
//////////////////////////////////////////////////////////////////////
/*
#include "stdafx.h"
#include "MultiFTP.h"
#include "MultiFTP1.h"
#include
#ifdef _DE
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define BUFFERSIZE 5000
CCriticalSection gcs_multiftp;
struct stThreadParam
{
CString szLocalname;
CString szRemotename;
CString szHost;
CString szUsername,szPass;
int ID;
int nPort;
CMultiFTP *pFtp;
UINT uStart,uLength;
};
UINT Thread(LPVOID pVoid)
{
stThreadParam *pvar=(stThreadParam *)pVoid;
int ID=pvar->ID ,nPort=pvar->nPort;
CString szLocalname=pvar->szLocalname,szRemotename=pvar->szRemotename;
CString szHost=pvar->szHost ;
CString szUsername=pvar->szUsername ,szPassword=pvar->szPassword ;
CMultiFTP *pFtp=pvar->pFtp;
UINT uStart=pvar->uStart ,uLength=pvar->uLength;
delete pvar;
over
CString szMsg;
CFTPGetFile m_getfile(pFtp);
CFile m_file;
char *pBuffer;
if(!m_getfile.Connect(szHost,nPort,szUsername,szPassword))
{
szMsg.Format("connect to data port failrnID:%drnError:%s",ID,m_getfile.szMsg);
AfxMessageBox(szMsg);
return 0;
}
m_file.Open(szLocalname,CFile::modeWrite|CFile::modeCreate);
pBuffer=(char *)VirtualAlloc(NULL,uLength,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
ASSERT(pBuffer);
if(!m_getfile.OpenFile(szRemotename,szLocalname,uStart,uLength))
{
m_file.Close();
DeleteFile(szLocalname);
VirtualFree(pBuffer,0,MEM_RELEASE);
szMsg.Format("open file failrnID:%drnError:%s",ID,m_getfile.szMsg);
AfxMessageBox(szMsg);
return 0;
}
file contents
for(UINT uRead;uLength;uLength-=uRead)
{
uRead=m_getfile.Read(pBuffer,uLength);
m_file.Write(pBuffer,uRead);
}
m_file.Close();
VirtualFree(pBuffer,0,MEM_RELEASE);
gcs_multiftp.Lock();
pFtp->OnThreadOver(ID,0,"ok");
gcs_multiftp.Unlock();
return 0;
}
CMultiFTP::CMultiFTP()
{
skClient.Create();
nThreads=1;
blContinue=FALSE;
}
CMultiFTP::~CMultiFTP()
{
skClient.ShutDown(2);
skClient.Close();
}
int CMultiFTP::GetThreads()
{
return nThreads;
}
int CMultiFTP::SetThreads(int n)
{
if(blContinue)
nThreads=n;
return nThreads;
}
BOOL CMultiFTP::Connect(CString szHost, UINT Port, CString szUser, CString szPass)
{
ASSERT(skClient.m_hSocket);
szHostname=szHost;
nPort=Port;
szUsername=szUser;
szPassword=szPass;
szMsg=="";
if(!skClient.Connect(szHostname,nPort))
{
return FALSE;
}
GetMsg();
CString szCommand;
szCommand.Format("user %srn",szUsername);
DoCommand(szCommand);
szCommand.Format("pass %s",szPassword);
if(DoCommand(szCommand)!=FTP_LOGOK)
return FALSE;
if(szMsg[3]=='-')
GetMsg();
if(DoCommand("rest 100")==FTP_RESTOK)
{
blContinue=TRUE;
}
else
{
nThreads=1;
blContinue=FALSE;
}
DoCommand("type a");
return TRUE;
}
void CMultiFTP::GetMsg()
{
szMsg="";
char chMsg[256];
int nRecv;
nRecv=skClient.Receive(chMsg,255);
if(nRecv==SOCKET_ERROR || nRecv==0) return;
chMsg[nRecv]='';
szMsg=chMsg;
}
int CMultiFTP::GetReturnCode()
{
CString szTemp=szMsg;
szTemp.TrimLeft();
return atoi(szTemp.Left(3));
}
int CMultiFTP::DoCommand(CString szCommand)
{
szCommand+="rn";
if(skClient.Send((LPCTSTR)szCommand,szCommand.GetLength())==SOCKET_ERROR)
return SOCKET_ERROR;
GetMsg();
return GetReturnCode();
}
void CMultiFTP::Close()
{
skClient.ShutDown(2);
skClient.Close();
}
BOOL CMultiFTP::Intinue()
{
return blContinue;
}
void CMultiFTP::OnThreadOver(int ID, UINT uRecv,CString szMsg)
{
nThreadOvered++;
if(nThreadOvered==nThreads)
{
if(Merge())
AfxMessageBox("download over");
else
AfxMessageBox("download fail");
}
}
BOOL CMultiFTP::Get(CString szRemotepath, CString szLocalpath)
{
stThreadParam *pvar;
CString szCommand;
szCommand.Format("size %s",szRemotepath);
if(DoCommand(szCommand)!=FTP_SIZEOK)
return FALSE;
szMsg.Delete(0,4);
UINT uSize=atoi(szMsg),uAvgSize=uSize/nThreads,uStart=0;
nThreadOvered=0;
for(int i=1;i<=nThreads;i++)
{
pvar=new stThreadParam;
pvar->ID =i;
pvar->nPort =nPort;
pvar->pFtp =this;
pvar->szHost =szHostname;
pvar->szPassword =szPassword;
pvar->szUsername =szUsername;
pvar->szLocalname.Format("%s_%d.dat",szLocalpath,i);
pvar->szRemotename =szRemotepath;
pvar->uStart =uStart;
pvar->uLength =(i==nThreads)?uSize:uAvgSize;
uStart+=pvar->uLength ;
uSize-=uAvgSize;
AfxBeginThread(DownloadThread,pvar);
}
szLocalname=szLocalpath;
return TRUE;
}
class
CFTPGetFile::CFTPGetFile(CMultiFTP *pFtp2)
{
pFtp=pFtp2;
blFileopened=FALSE;
}
CFTPGetFile::~CFTPGetFile()
{
Close();
}
BOOL CFTPGetFile::OpenFile(CString szRemotename,CString szLocalname,UINT uStart2,UINT uLength2)
{
ASSERT(skClient.m_hSocket);
if(skData.m_hSocket)
skData.Close();
uStart=uStart2;
uLength=uLength2;
CString szCommand,szHost;
int iPort;
remote file
data traner port
if(DoCommand("pasvrn")!=FTP_PASVOK)
{
szMsg.Format("openfile:pasv command fail,code:%d",GetFtpCode());
AfxMessageBox(szMsg);
return FALSE;
}
int p1,p2,i1,i2;
int iStart=szMsg.ReverseFind('(');
for(int i=iStart,count=0;i
if(szMsg[i]==',')
{
count++;
if(count==4) p1=i+1;
if(count==5) p2=i-1;
}
}
i1=atoi(szMsg.Mid(p1,p2-p1+1));
i2=atoi(szMsg.Mid(p2+2));
iPort=(i1<<8)+i2;
szHost=szMsg.Mid(iStart+1,p1-iStart-2);
szHost.Replace(",",".");
file mode to i
DoCommand("type i");
remote file pointer
szCommand.Format("rest %d",uStart);
DoCommand(szCommand);
ASSERT(GetFtpCode()==FTP_RESTOK);
file command
szCommand.Format("retr %s",szRemotename);
DoCommand(szCommand,FALSE);
skData.Create();
if(!skData.Connect(szHost,iPort))
{
skData.Close();
szMsg.Format("openfile:Connnect to data port:%d at server:%s fail",iPort,szHost);
AfxMessageBox(szMsg);
return FALSE;
}
return TRUE;
}
int CFTPGetFile::DoCommand(CString szCommand,BOOL blGetMsg)
{
int nRecv;
szCommand+="rn";
skClient.Send((LPCTSTR)szCommand,szCommand.GetLength());
if(blGetMsg)
{
nRecv=GetMsg();
if(nRecv==0 || nRecv==SOCKET_ERROR)
return nRecv;
return GetFtpCode();
}
return 0;
}
int CFTPGetFile::GetFtpCode()
{
szMsg.TrimLeft();
return atoi(szMsg);
}
BOOL CFTPGetFile::Connect(CString szHostname, int iPort, CString szUser, CString szPass)
{
if(skClient.m_hSocket)
skClient.Close();
skClient.Create();
ASSERT(skClient.m_hSocket);
if(!skClient.Connect(szHostname,iPort))
{
szMsg.Format("GetFile:connect to server fail:%d",GetLastError());
AfxMessageBox(szMsg);
Close();
return FALSE;
}
CString szCommand;
szCommand.Format("user %srn",szUser);
DoCommand(szCommand);
szCommand.Format("pass %srn",szPass);
DoCommand(szCommand);
if(szMsg[0]=='-')
GetMsg();
if(GetFtpCode()!=FTP_LOGOK)
{
szMsg.Format("GetFile:password is not correct");
AfxMessageBox(szMsg);
return FALSE;
}
DoCommand("type arn");
return TRUE;
}
void CFTPGetFile::Close()
{
if(skClient.m_hSocket)
{
skClient.ShutDown(2);
skClient.Close();
}
if(skData.m_hSocket)
{
skData.ShutDown(2);
skData.Close();
}
}
int CFTPGetFile::GetMsg()
{
int nRecv;
szMsg="";
nRecv=skClient.Receive(chRecv,255);
if(nRecv==SOCKET_ERROR)
return nRecv;
chRecv[nRecv]='';
szMsg=chRecv;
return nRecv;
}
int CFTPGetFile::Read(char *pBuffer, int nBufferSize)
{
return skData.Receive(pBuffer,nBufferSize);
}
BOOL CMultiFTP::Merge()
{
CFileFind m_find;
CString szFilename;
DWORD dwSize;
for(int i=1;i<=nThreads;i++)
{
szFilename.Format("%s_%d.dat",szLocalname,i);
if(!m_find.FindFile(szFilename))
return FALSE;
if(i==nThreads)
{
m_find.FindNextFile();
dwSize=m_find.GetLength();
}
m_find.Close();
}
CFile m_file,m_file2;
char *pBuffer;
pBuffer=(char *)VirtualAlloc(NULL,dwSize,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
m_file.Open(szLocalname,CFile::modeCreate|CFile::modeWrite);
for(i=1;i<=nThreads;i++)
{
szFilename.Format("%s_%d.dat",szLocalname,i);
m_file2.Open(szFilename,CFile::modeRead);
m_file2.Read(pBuffer,m_file2.GetLength());
m_file.Write(pBuffer,m_file2.GetLength());
m_file2.Close();
// DeleteFile(szFilename);
}
m_file.Close();
VirtualFree(pBuffer,0,MEM_RELEASE);
return TRUE;
}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-987836/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java集合類原始碼Java原始碼
- [轉帖]利用WebClient和WebRequest類獲得網頁原始碼Webclient網頁原始碼
- 【Java原始碼】集合類-ArrayDequeJava原始碼
- Lucene原始碼解析--Field類原始碼
- VB原始碼推薦:一個操作Ini檔案的類 (轉)原始碼
- 透過原始碼學習TComponent類的機制(1) (轉)原始碼
- Laravel 請求類原始碼分析Laravel原始碼
- JDK原始碼閱讀-Object類JDK原始碼Object
- JDK原始碼閱讀-Integer類JDK原始碼
- JDK原始碼閱讀-Number類JDK原始碼
- JDK 原始碼分析(1) Object類JDK原始碼Object
- Runtime原始碼 Category(分類)原始碼Go
- Java集合類:AbstractCollection原始碼解析Java原始碼
- DRF之排序類原始碼分析排序原始碼
- DRF之分頁類原始碼分析原始碼
- 用Javascript轉換原始碼 (轉)JavaScript原始碼
- ping原始碼(轉)原始碼
- 容器類原始碼解析系列(三)—— HashMap 原始碼分析(最新版)原始碼HashMap
- Java原始碼篇之容器類——ArrayListJava原始碼
- Java類載入原始碼閱讀Java原始碼
- Faiss原始碼剖析:類結構分析AI原始碼
- Groovy核心類原始碼講解(上)原始碼
- JDK原始碼閱讀-String類JDK原始碼
- Java類集框架 —— ArrayList原始碼分析Java框架原始碼
- Python 列舉類原始碼解析Python原始碼
- 併發類Condition原始碼分析原始碼
- Hadoop原始碼分類概要整理Hadoop原始碼
- Java類集框架 —— HashMap原始碼分析Java框架HashMap原始碼
- JVM類載入器-原始碼分析JVM原始碼
- DRF之過濾類原始碼分析原始碼
- unicode轉碼工具類Unicode
- 容器類原始碼解析系列(一) ArrayList 原始碼分析——基於最新Android9.0原始碼原始碼Android
- 超詳細的 Bert 文字分類原始碼解讀 | 附原始碼文字分類原始碼
- DVD解碼原始碼大公佈 (轉)原始碼
- java工具類之編碼轉換工具類Java
- boost::any原始碼分析 (轉)原始碼
- FileMapping使用者類原始碼(原創, 歡迎批評指正) (轉)APP原始碼
- Laravel 原始碼筆記 容器類 ContainerLaravel原始碼筆記AI