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

📄 ftpclient.cpp

📁 实现了wince 客户端上传下载查看文件及目录的功能接口d
💻 CPP
📖 第 1 页 / 共 5 页
字号:
////////////////////////////////////////////////////////////////////////////////
//
// The official specification of the File Transfer Protocol (FTP) is the RFC 959.
// Most of the documentation are taken from this RFC.
// This is an implementation of an simple ftp client. I have tried to implement
// platform independent. For the communication i used the classes CBlockingSocket,
// CSockAddr, ... from David J. Kruglinski (Inside Visual C++). These classes are
// only small wrappers for the sockets-API.
// Further I used a smart pointer-implementation from Scott Meyers (Effective C++, 
// More Effective C++, Effective STL).
// The implementation of the logon-sequence (with firewall support) was published 
// in an article on Codeguru by Phil Anderson. 
// The code for the parsing of the different FTP LIST responses is taken from 
// D. J. Bernstein (http://cr.yp.to/ftpparse.html). I only wrapped the c-code in
// a class.
// I haven't tested the code on other platforms, but i think with little 
// modifications it would compile.
// 
// Copyright (c) 2004 Thomas Oswald
//
// Permission to copy, use, sell and distribute this software is granted
// provided this copyright notice appears in all copies.
// Permission to modify the code and to distribute modified code is granted
// provided this copyright notice appears in all copies, and a notice
// that the code was modified is included with the copyright notice.
//
// This software is provided "as is" without express or implied warranty,
// and with no claim as to its suitability for any purpose.
//
// History:
// v1.1 released 2005-12-04
//      - Bug in OpenPassiveDataConnection removed: SendCommand was called before data connection was established.
//      - Bugs in GetSingleResponseLine removed:
//         * Infinite loop if response line doesn't end with CRLF.
//         * Return value of std:string->find must be checked against npos.
//      - Now runs in unicode.
//      - Streams removed.
//      - Explicit detaching of observers are not necessary anymore.
//      - ExecuteDatachannelCommand now accepts an ITransferNotification object. 
//        Through this concept there is no need to write the received files to a file.
//        For example the bytes can be written only in memory or an other tcp stream.
//      - Added an interface for the blocking socket (IBlockingSocket).
//        Therefore it is possible to exchange the socket implementation, e.g. for 
//        writing unit tests (by simulating an specific scenario of an ftp communication).
//      - Replaced the magic numbers concerning the reply codes by a class.
// v1.0 released 2004-10-25
////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "FTPclient.h"
#include <limits>
#include <algorithm>
#include "FTPListParse.h"
#include "FTPFileState.h"

#undef max

#ifdef __AFX_H__ // MFC only
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif

using namespace nsHelper;

namespace nsFTP
{
   class CMakeString
   {
   public:
      CMakeString& operator<<(DWORD dwNum)
      {
         DWORD dwTemp = dwNum;
         int iCnt=1; // name lookup of 'iCnt' changed for new ISO 'for' scoping
         for( ; (dwTemp/=10) != 0; iCnt++ )
            ;

         m_str.resize(m_str.size() + iCnt);
         tsprintf(&(*m_str.begin()), _T("%s%u"), m_str.c_str(), dwNum);

         return *this;
      }

      CMakeString& operator<<(const tstring& strAdd)
      {
         m_str += strAdd;
         return *this;
      }
      
      operator tstring() const { return m_str; }
   
   private:
      tstring m_str;
   };

   tstring& ReplaceStr(tstring& strTarget, const tstring& strToReplace, const tstring& strReplacement)
   {
      size_t pos = strTarget.find(strToReplace);
      while( pos != tstring::npos )
      {
         strTarget.replace(pos, strToReplace.length(), strReplacement);
         pos = strTarget.find(strToReplace, pos+1);
      }
      return strTarget;
   }

   class CFile : public ITransferNotification
   {
      FILE* m_pFile;
   public:
      enum T_enOrigin { orBegin=SEEK_SET, orEnd=SEEK_END, orCurrent=SEEK_CUR };

      CFile() : m_pFile(NULL) {}
      ~CFile()
      {
         Close();
      }

      bool Open(const tstring& strFileName, const tstring& strMode)
      {
         m_pFile = fopen(CCnv::ConvertToString(strFileName).c_str(), 
                         CCnv::ConvertToString(strMode).c_str());
         return m_pFile!=NULL;
      }

      bool Close()
      {
         FILE* pFile = m_pFile;
         m_pFile = NULL;
         return pFile && fclose(pFile)==0;
      }

      bool Seek(long lOffset, T_enOrigin enOrigin)
      {
         return m_pFile && fseek(m_pFile, lOffset, enOrigin)==0;
      }

      long Tell()
      {
         if( !m_pFile )
            return -1L;
         return ftell(m_pFile);
      }

      size_t Write(const void* pBuffer, size_t itemSize, size_t itemCount)
      {
         if( !m_pFile )
            return 0;
         return fwrite(pBuffer, itemSize, itemCount, m_pFile);
      }

      size_t Read(void* pBuffer, size_t itemSize, size_t itemCount)
      {
         if( !m_pFile )
            return 0;
         return fread(pBuffer, itemSize, itemCount, m_pFile);
      }

      virtual void OnBytesReceived(const TByteVector& vBuffer, long lReceivedBytes)
      {
         Write(&(*vBuffer.begin()), sizeof(TByteVector::value_type), lReceivedBytes);
      }

      virtual void OnPreBytesSend(TByteVector& vBuffer, size_t& bytesToSend)
      {
         bytesToSend = Read(&(*vBuffer.begin()), sizeof(TByteVector::value_type), vBuffer.size());
      }
   };

   class COutputStream : public ITransferNotification
   {
      const tstring mc_strEolCharacterSequence;
      tstring m_vBuffer;
      tstring::iterator m_itCurrentPos;
   public:
      COutputStream(const tstring& strEolCharacterSequence) :
         mc_strEolCharacterSequence(strEolCharacterSequence),
         m_itCurrentPos(m_vBuffer.end()) {}

      void SetStartPosition()
      {
         m_itCurrentPos = m_vBuffer.begin();
      }
      
      bool GetNextLine(tstring& strLine)// const
      {
         tstring::iterator it = std::search(m_itCurrentPos, m_vBuffer.end(), mc_strEolCharacterSequence.begin(), mc_strEolCharacterSequence.end());
         if( it == m_vBuffer.end() )
            return false;

         strLine.assign(m_itCurrentPos, it);

         m_itCurrentPos = it + mc_strEolCharacterSequence.size();

         return true;
      }

      virtual void OnBytesReceived(const TByteVector& vBuffer, long lReceivedBytes)
      {
         std::copy(vBuffer.begin(), vBuffer.begin()+lReceivedBytes, std::back_inserter(m_vBuffer));
      }
   };

};

using namespace nsFTP;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

/// constructor
/// @param[in] pSocket Instance of socket class which will be used for 
///                    communication with the ftp server.
///                    CFTPClient class takes ownership of this instance.
///                    It will be deleted on destruction of this object.
///                    If this pointer is NULL, the CBlockingSocket implementation
///                    will be used. 
///                    This gives the ability to set an other socket class.
///                    For example a socket class can be implemented which simulates
///                    a ftp server (for unit testing).
/// @param[in] uiTimeout Timeout used for socket operation.
/// @param[in] uiBufferSize Size of the buffer used for sending and receiving
///                         data via sockets. The size have an influence on 
///                         the performance. Through empiric test i come to the
///                         conclusion that 2048 is a good size.
/// @param[in] uiResponseWait Sleep time between receive calls to socket when getting 
///                           the response. Sometimes the socket hangs if no wait time
///                           is set. Normally not wait time is necessary.
CFTPClient::CFTPClient(IBlockingSocket* pSocket/*=NULL*/, unsigned int uiTimeout/*=10*/, 
                       unsigned int uiBufferSize/*=2048*/, unsigned int uiResponseWait/*=0*/) :
   mc_uiTimeout(uiTimeout),
   mc_uiResponseWait(uiResponseWait),
   mc_strEolCharacterSequence(_T("\r\n")),
   m_vBuffer(uiBufferSize),
   m_apSckControlConnection(pSocket),
   m_fTransferInProgress(false),
   m_fAbortTransfer(false),
   m_fResumeIfPossible(true)
{
   ASSERT( pSocket );
}

CFTPClient::~CFTPClient()
{
   if( IsTransferringData() )
      Abort();

   if( IsConnected() )
      Logout();
}

CFTPClient* CFTPClient::pinstance = 0;// 初始化指针
CFTPClient* CFTPClient::Instance () 
{
	if (pinstance == 0) // 是第一次调用吗?
	{ 
	   //pinstance = new CFTPClient(nsSocket::CreateDefaultBlockingSocketInstance(), 30); // 创建唯一实例
		pinstance = new CFTPClient(); // 创建唯一实例
	}
	return pinstance; // 唯一实例的地址
}

/// Attach an observer to the client. You can attach as many observers as you want.
/// The client send notifications (more precisely the virtual functions are called)
/// to the observers.
void CFTPClient::AttachObserver(CFTPClient::CNotification* pObserver)
{
   ASSERT( pObserver );
   if( pObserver )
      m_setObserver.Attach(pObserver);
}

/// Detach an observer from the client.
void CFTPClient::DetachObserver(CFTPClient::CNotification* pObserver)
{
   ASSERT( pObserver );
   if( pObserver )
      m_setObserver.Detach(pObserver);
}

/// Returns a set of all observers currently attached to the client.
CFTPClient::TObserverSet& CFTPClient::GetObservers()
{
   return m_setObserver;
}

/// Enables or disables resuming for file transfer operations.
/// @param[in] fEnable True enables resuming, false disables it.
void CFTPClient::SetResumeMode(bool fEnable/*=true*/)
{
   m_fResumeIfPossible=fEnable;
}

/// Opens the control channel to the FTP server.
/// @param[in] strServerHost IP-address or name of the server
/// @param[in] iServerPort Port for channel. Usually this is port 21.
bool CFTPClient::OpenControlChannel(const tstring& strServerHost, USHORT ushServerPort/*=DEFAULT_FTP_PORT*/)
{
   CloseControlChannel();

   try
   {
      m_apSckControlConnection->Create(SOCK_STREAM);
      CSockAddr adr = m_apSckControlConnection->GetHostByName(CCnv::ConvertToString(strServerHost).c_str(), ushServerPort);
      m_apSckControlConnection->Connect(adr);
   }
   catch(CBlockingSocketException& blockingException)
   {
      ReportError(blockingException.GetErrorMessage(), CCnv::ConvertToTString(__FILE__), __LINE__);
      m_apSckControlConnection->Cleanup();
      return false;
   }

   return true;
}

/// Returns the connection state of the client.
bool CFTPClient::IsConnected() const
{
   return m_apSckControlConnection->operator SOCKET()!=0;
}

/// Returns true if a download/upload is running, otherwise false.
bool CFTPClient::IsTransferringData() const
{
   return m_fTransferInProgress;
}

/// Closes the control channel to the FTP server.
void CFTPClient::CloseControlChannel() 
{
   try
   {
      m_apSckControlConnection->Close();
      m_apCurrentRepresentation.reset(NULL);
   }
   catch(CBlockingSocketException& blockingException)
   {
      blockingException.GetErrorMessage();
      m_apSckControlConnection->Cleanup();
   }

⌨️ 快捷键说明

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