ftpclient.cpp
来自「自己改写的在WINCE上开发用的EVC++的FTP操作示例工程,希望能给相关人士」· C++ 代码 · 共 1,641 行 · 第 1/4 页
CPP
1,641 行
while( outputStream.GetNextLine(strLine) )
{
std::auto_ptr<CFTPFileStatus> pFtpFileStatus(new CFTPFileStatus());
if( ftpListParser.Parse(*pFtpFileStatus, strLine) )
{
pFtpFileStatus->Path() = strPath;
vFileList.push_back(pFtpFileStatus.release());
}
}
return true;
}
/// Gets the directory listing of the ftp-server. Sends the NLST command to
/// the ftp-server.
/// @param[in] strPath Starting path for the list command.
/// @param[out] vFileList Returns a simple list of the files and folders of the specified directory.
/// vFileList contains CFTPFileStatus-Objects. Normally these Objects provide
/// a lot of information about the file/folder. But the NLST-command provide
/// only a simple list of the directory content (no specific information).
/// @param[in] fPasv see documentation of CFTPClient::Passive
bool CFTPClient::NameList(CStringA strPath, TSpFTPFileStatusVector& vFileList, bool fPasv)
{
COutputStream outputStream(mc_strEolCharacterSequence);
if( !ExecuteDatachannelCommand(CDatachannelCmd::NLST(), strPath, CRepresentation(CType::ASCII()), fPasv, 0, &outputStream) )
return false;
vFileList.clear();
CStringA strLine;
CFTPListParse ftpListParser;
outputStream.SetStartPosition();
while( outputStream.GetNextLine(strLine) )
{
std::auto_ptr<CFTPFileStatus> pFtpFileStatus(new CFTPFileStatus());
pFtpFileStatus->Path() = strPath;
pFtpFileStatus->Name() = strLine;
vFileList.push_back(pFtpFileStatus.release());
}
return true;
}
/// Gets a file from the ftp-server.
/// Uses C functions for file access (very fast).
/// @param[in] strRemoteFile Filename of the sourcefile on the ftp-server.
/// @param[in] strLocalFile Filename of the targetfile on the local computer.
/// @param[in] repType Representation Type (see documentation of CRepresentation)
/// @param[in] fPasv see documentation of CFTPClient::Passive
bool CFTPClient::DownloadFile(CStringA strRemoteFile, CStringA strLocalFile, CRepresentation& repType, bool fPasv)
{
CFileT file;
if( !file.Open(strLocalFile, m_fResumeIfPossible ? "ab" : "wb") )
{
ReportError(CCnv::ConvertToString(CErrorT::GetErrorDescription()).c_str(), __FILE__, __LINE__);
return false;
}
file.Seek(0, CFileT::orEnd);
bool fRet= false;
long lRemoteFileSize = 0;
FileSize(strRemoteFile, lRemoteFileSize);
if(m_pNotification)
m_pNotification->OnPreReceiveFile(strRemoteFile, strLocalFile, lRemoteFileSize);
fRet = ExecuteDatachannelCommand(CDatachannelCmd::RETR(), strRemoteFile, repType, fPasv, file.Tell(), &file);
if(m_pNotification)
m_pNotification->OnPostReceiveFile(strRemoteFile, strLocalFile, lRemoteFileSize);
return fRet;
}
/// Puts a file on the ftp-server.
/// Uses C functions for file access (very fast).
/// @param[in] strLocalFile Filename of the the local sourcefile which to put on the ftp-server.
/// @param[in] strRemoteFile Filename of the targetfile on the ftp-server.
/// @param[in] fStoreUnique if true, the ftp command STOU is used for saving
/// else the ftp command STOR is used.
/// @param[in] repType Representation Type (see documentation of CRepresentation)
/// @param[in] fPasv see documentation of CFTPClient::Passive
bool CFTPClient::UploadFile(CStringA& strLocalFile, CStringA& strRemoteFile, bool fStoreUnique, CRepresentation& repType, bool fPasv)
{
CFileT file;
if( !file.Open(strLocalFile, "rb") )
{
ReportError(CCnv::ConvertToString(CErrorT::GetErrorDescription()).c_str(), __FILE__, __LINE__);
return false;
}
long lRemoteFileSize = 0;
if( m_fResumeIfPossible )
FileSize(strRemoteFile, lRemoteFileSize);
CDatachannelCmd cmd(CDatachannelCmd::STOR());
if( lRemoteFileSize > 0 )
cmd = CDatachannelCmd::APPE();
else if( fStoreUnique )
cmd = CDatachannelCmd::STOU();
file.Seek(0, CFileT::orEnd);
long lLocalFileSize = file.Tell();
file.Seek(lRemoteFileSize, CFileT::orBegin);
bool fRet=false;
if(m_pNotification)
m_pNotification->OnPreSendFile(strLocalFile, strRemoteFile, lLocalFileSize);
fRet = ExecuteDatachannelCommand(cmd, strRemoteFile, repType, fPasv, 0, &file);
if(m_pNotification)
m_pNotification->OnPostSendFile(strLocalFile, strRemoteFile, lLocalFileSize);
return fRet;
}
/// Executes a commando that result in a communication over the data port.
/// @param[in] crDatachannelCmd Command to be executeted.
/// @param[in] strPath Parameter for the command usually a path.
/// @param[in] representation see documentation of CFTPClient::CRepresentation
/// @param[in] fPasv see documentation of CFTPClient::Passive
/// @param[in] dwByteOffset Server marker at which file transfer is to be restarted.
/// @param[in] pObserver Object for observing the execution of the command.
bool CFTPClient::ExecuteDatachannelCommand(CDatachannelCmd crDatachannelCmd, CStringA& strPath, CRepresentation& representation,
bool fPasv, DWORD dwByteOffset, ITransferNotification* pObserver)
{
if( m_fTransferInProgress )
return false;
if( !IsConnected() )
return false;
// check representation
if( m_apCurrentRepresentation.get() == NULL )
{
CRepresentation *pRep = m_apCurrentRepresentation.release();
delete pRep;
std::auto_ptr<CRepresentation> rep(new CRepresentation(CType::ASCII()));
m_apCurrentRepresentation = rep;
}
if( representation != *m_apCurrentRepresentation )
{
// transmit representation to server
if( RepresentationType(representation)!=FTP_OK )
return false;
*m_apCurrentRepresentation = representation;
}
std::auto_ptr<IBlockingSocket> apSckDataConnection(m_apSckControlConnection->CreateInstance());
if( fPasv )
{
if( !OpenPassiveDataConnection(*apSckDataConnection, crDatachannelCmd, strPath, dwByteOffset) )
return false;
}
else
{
if( !OpenActiveDataConnection(*apSckDataConnection, crDatachannelCmd, strPath, dwByteOffset) )
return false;
}
bool fTransferOK = TransferData(crDatachannelCmd, pObserver, *apSckDataConnection);
apSckDataConnection->Close();
// get response from ftp server
CReply Reply;
if( !fTransferOK || !GetResponse(Reply) || !Reply.Code().IsPositiveCompletionReply() )
return false;
return true;
}
/// Executes a commando that result in a communication over the data port.
/// @param[in] crDatachannelCmd Command to be executeted.
/// @param[in] pObserver Object for observing the execution of the command.
/// @param[in] sckDataConnection Socket which is used for sending/receiving data.
bool CFTPClient::TransferData(CDatachannelCmd& crDatachannelCmd, ITransferNotification* pObserver, IBlockingSocket& sckDataConnection)
{
switch( crDatachannelCmd.AsEnum() )
{
case CDatachannelCmd::cmdSTOR:
case CDatachannelCmd::cmdSTOU:
case CDatachannelCmd::cmdAPPE:
{
if( !SendData(pObserver, sckDataConnection) )
return false;
}
break;
case CDatachannelCmd::cmdRETR:
case CDatachannelCmd::cmdLIST:
case CDatachannelCmd::cmdNLST:
if( !ReceiveData(pObserver, sckDataConnection) )
return false;
break;
default:
ASSERT( false );
return false;
}
return true;
}
/// Opens an active data connection.
/// @param[out] sckDataConnection
/// @param[in] crDatachannelCmd Command to be executeted.
/// @param[in] strPath Parameter for the command usually a path.
/// @param[in] dwByteOffset Server marker at which file transfer is to be restarted.
bool CFTPClient::OpenActiveDataConnection(IBlockingSocket& sckDataConnection, CDatachannelCmd& crDatachannelCmd, CStringA& strPath, DWORD dwByteOffset)
{
std::auto_ptr<IBlockingSocket> apSckServer(m_apSckControlConnection->CreateInstance());
USHORT ushLocalSock = 0;
try
{
// INADDR_ANY = ip address of localhost
// second parameter "0" means that the WINSOCKAPI ask for a port
CSockAddr csaAddressTemp(INADDR_ANY, 0);
apSckServer->Create(SOCK_STREAM);
apSckServer->Bind(csaAddressTemp);
apSckServer->GetSockAddr(csaAddressTemp);
ushLocalSock=csaAddressTemp.Port();
apSckServer->Listen();
}
catch(CBlockingSocketException& blockingException)
{
ReportError(blockingException.GetErrorMessage(), __FILE__, __LINE__);
apSckServer->Cleanup();
return false;
}
// get own ip address
CSockAddr csaLocalAddress;
m_apSckControlConnection->GetSockAddr(csaLocalAddress);
// transmit the socket (ip address + port) to the server
// the ftp server establishes then the data connection
if( DataPort(csaLocalAddress.DottedDecimal(), ushLocalSock)!=FTP_OK )
return false;
// if resuming is activated then set offset
if( m_fResumeIfPossible &&
(crDatachannelCmd==CDatachannelCmd::cmdSTOR || crDatachannelCmd==CDatachannelCmd::cmdRETR || crDatachannelCmd==CDatachannelCmd::cmdAPPE ) &&
(dwByteOffset!=0 && Restart(dwByteOffset)!=FTP_OK) )
return false;
// send FTP command RETR/STOR/NLST/LIST to the server
CReply Reply;
if( !SendCommand(GetCmdString(crDatachannelCmd, strPath), Reply) ||
!Reply.Code().IsPositivePreliminaryReply() )
return false;
// accept the data connection
CSockAddr sockAddrTemp;
if( !apSckServer->Accept(sckDataConnection, sockAddrTemp) )
return false;
return true;
}
/// Opens a passive data connection.
/// @param[out] sckDataConnection
/// @param[in] crDatachannelCmd Command to be executeted.
/// @param[in] strPath Parameter for the command usually a path.
/// @param[in] dwByteOffset Server marker at which file transfer is to be restarted.
bool CFTPClient::OpenPassiveDataConnection(IBlockingSocket& sckDataConnection, CDatachannelCmd& crDatachannelCmd, CStringA& strPath, DWORD dwByteOffset)
{
ULONG ulRemoteHostIP = 0;
USHORT ushServerSock = 0;
// set passive mode
// the ftp server opens a port and tell us the socket (ip address + port)
// this socket is used for opening the data connection
if( Passive(ulRemoteHostIP, ushServerSock)!=FTP_OK )
return false;
// establish connection
CSockAddr sockAddrTemp;
try
{
sckDataConnection.Create(SOCK_STREAM);
CSockAddr csaAddress(ulRemoteHostIP, ushServerSock);
sckDataConnection.Connect(csaAddress);
}
catch(CBlockingSocketException& blockingException)
{
ReportError(blockingException.GetErrorMessage(), __FILE__, __LINE__);
sckDataConnection.Cleanup();
return false;
}
// if resuming is activated then set offset
if( m_fResumeIfPossible &&
(crDatachannelCmd==CDatachannelCmd::cmdSTOR || crDatachannelCmd==CDatachannelCmd::cmdRETR || crDatachannelCmd==CDatachannelCmd::cmdAPPE ) &&
(dwByteOffset!=0 && Restart(dwByteOffset)!=FTP_OK) )
return false;
// send FTP command RETR/STOR/NLST/LIST to the server
CReply Reply;
if( !SendCommand(GetCmdString(crDatachannelCmd, strPath), Reply) ||
!Reply.Code().IsPositivePreliminaryReply() )
return false;
return true;
}
/// Sends data over a socket to the server.
/// @param[in] pObserver Object for observing the execution of the command.
/// @param[in] sckDataConnection Socket which is used for the send action.
bool CFTPClient::SendData(ITransferNotification* pObserver, IBlockingSocket& sckDataConnection)
{
try
{
m_fTransferInProgress=true;
int iNumWrite;
size_t bytesRead;
pObserver->OnPreBytesSend(m_vBuffer, bytesRead);
while( !m_fAbortTransfer && bytesRead!=0 )
{
iNumWrite = sckDataConnection.Write(m_vBuffer.GetData(), static_cast<int>(bytesRead), mc_uiTimeout);
ASSERT( iNumWrite == static_cast<int>(bytesRead) );
pObserver->OnPreBytesSend(m_vBuffer, bytesRead);
if(m_pNotification)
m_pNotification->OnBytesSent(m_vBuffer, iNumWrite);
}
m_fTransferInProgress=false;
if( m_fAbortTransfer )
{
Abort();
return false;
}
}
catch(CBlockingSocketException& blockingException)
{
m_fTransferInProgress=false;
ReportError(blockingException.GetErrorMessage(), __FILE__, __LINE__);
sckDataConnection.Cleanup();
return false;
}
return true;
}
/// Receives data over a socket from the server.
/// @param[in] pObserver Object for observing the execution of the command.
/// @param[in] sckDataConnection Socket which is used for receiving the data.
bool CFTPClient::ReceiveData(ITransferNotification* pObserver, IBlockingSocket& sckDataConnection)
{
try
{
m_fTransferInProgress = true;
if(m_pNotification)
m_pNotification->OnBeginReceivingData();
int iNumRead=sckDataConnection.Receive(m_vBuffer.GetData(), m_vBuffer.Length(), mc_uiTimeout);
long lTotalBytes = iNumRead;
while( !m_fAbortTransfer && iNumRead!=0 )
{
if(m_pNotification)
m_pNotification->OnBytesReceived(m_vBuffer, iNumRead);
pObserver->OnBytesReceived(m_vBuffer, iNumRead);
iNumRead=sckDataConnection.Receive(m_vBuffer.GetData(), m_vBuffer.Length(), mc_uiTimeout);
lTotalBytes += iNumRead;
}
if(m_pNotification)
m_pNotification->OnEndReceivingData(lTotalBytes);
m_fTransferInProgress=false;
if( m_fAbortTransfer )
{
Abort();
return false;
}
}
catch(CBlockingSocketException& blockingException)
{
m_fTransferInProgress=false;
ReportError(blockingException.GetErrorMessage(), __FILE__, __LINE__);
sckDataConnection.Cleanup();
return false;
}
return true;
}
/// Returns the command string for a specific command.
/// @param[in] crDatachannelCmd Command for which the string should be returned.
/// @param[in] strPath Parameter which have to be added to the command.
CStringA CFTPClient::GetCmdString(CDatachannelCmd& crDatachannelCmd, CStringA& strPath)
{
switch( crDatachannelCmd.AsEnum() )
{
case CDatachannelCmd::cmdLIST: return strPath.IsEmpty() ? "LIST" : "LIST " + strPath;
case CDatachannelCmd::cmdNLST: return strPath.IsEmpty() ? "NLST" : "NLST " + strPath;
case CDatachannelCmd::cmdSTOR: return "STOR " + strPath;
case CDatachannelCmd::cmdSTOU: return "STOU " + strPath;
case CDatachannelCmd::cmdRETR: return "RETR " + strPath;
case CDatachannelCmd::cmdAPPE: return "APPE " + strPath;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?