Click here to Skip to main content
Click here to Skip to main content

FTP Client Class

, 8 Dec 2012
Rate this:
Please Sign up or sign in to vote.
A non-MFC class to encapsulate the FTP protocol.

Introduction

CFTPClient is a class to encapsulate the FTP protocol. I have tried to implement it as platform independent. For the purpose of communication, I have used the classes CBlockingSocket, CSockAddr, ... from David J. Kruglinski's "Inside Visual C++". These classes are only small wrappers for the sockets-API. Further, I have 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 different FTP LIST responses is taken from D. J. Bernstein's (parsing code). 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 and run smoothly.

The main features are:

  • not based on MFC-sockets,
  • not using other MFC-stuffs like CString (uses STL),
  • supports Firewalls,
  • supports resuming,
  • supports file eXchange Protocol (FXP) - uses FTP to transfer data directly from one remote server to another (servers must support this feature),
  • testet under Windows with Visual Studio 2008,
  • testet under Linux (Suse 11.4) with Qt,
  • smart pointer implementation can be easily replaced with boost::shared_ptr or std::shared_ptr by defining USE_BOOST_SMART_PTR or USE_STD_SMART_PTR,
  • parser which parses the output of the LIST command can be replaced by implementing the interface "IFileListParser",
  • can be easily extended.

The example shows how easy it is to use this class. With a few lines of code you can log the communication or visualize file transfers. Notice: The example is not a fully functional FTP-client-application. The example application is only for Windows platforms.

Background

The official specification of the File Transfer Protocol (FTP) is the RFC 959. Most of the documentation in my code are taken from this RFC.

Using the code

There are a lot of classes. But most of them are just simple "datatypes". The most important ones are the following:

  • CFTPClient
    The heart of the application. It accepts a CLogonInfo object. Handles the complete communication with the FTP-server like:
    • get directory listing,
    • download/upload files,
    • delete directories/files,
    • walk through directory-tree,
    • passive mode,
    • ...
  • CLogonInfo
    A simple data structure for logon information, such as host, username, password, firewall, ...
  • CFTPClient::IFileListParser
    Interface for defining a parser class which can be set in the CFTPClient class for parsing the output of the LIST command.

  • CFTPClient::ITransferNotification
    Implementations of this interface can be used in the Download and Upload methods for controlling the byte streams which are be downloaded/uploaded. This can be used for example to download a file only into memory instead of a local file (see class COutputStream).

  • CFTPClient::CNotification
    The base class for notification mechanism. The class which derives from CFTPClient::CNotifaction can be attached to the CFTPClient class as an observer. The CFTPClient object notifies all the attached observers about the various actions (see example application):

    void TestFTP()
    {
       nsFTP::CFTPClient ftpClient;
       nsFTP::CLogonInfo logonInfo(_T("localhost"), 21, _T("anonymous"),
                                               _T("<a href="mailto:anonymous@user.com">anonymous@user.com"));
    
       // connect to server
       ftpClient.Login(logonInfo);
    
       // get directory listing
       nsFTP::TFTPFileStatusShPtrVec list;
       ftpClient.List(_T("/"), list);
    
       // iterate listing
       for( nsFTP::TFTPFileStatusShPtrVec::iterator it=list.begin();
                                                it!=list.end(); ++it )
           TRACE(_T("\n%s"), (*it)->Name().c_str());
    
       // do file operations
       ftpClient.DownloadFile(_T("/pub/test.txt"), _T("c:\\temp\\test.txt"));
    
       ftpClient.UploadFile(_T("c:\\temp\\test.txt"), _T("/upload/test.txt"));
    
       ftpClient.Rename(_T("/upload/test.txt"), _T("/upload/NewName.txt"));
    
       ftpClient.Delete(_T("/upload/NewName.txt"));
    
       // disconnect
       ftpClient.Logout();
    }
    
    void TestFXP()
    {
       nsFTP::CFTPClient ftpClientSource;
       nsFTP::CLogonInfo logonInfoSource(_T("sourceftpserver"), 21, _T("anonymous"),
                                                           _T("<a href="mailto:anonymous@user.com">anonymous@user.com"));
    
       nsFTP::CFTPClient ftpClientTarget;
       nsFTP::CLogonInfo logonInfoTarget(_T("targetftpserver"), 21, _T("anonymous"),
                                                           _T("<a href="mailto:anonymous@user.com">anonymous@user.com"));
    
       // connect to server
       ftpClientSource.Login(logonInfoSource);
       ftpClientTarget.Login(logonInfoTarget);
    
    
       // do file operations
       nsFTP::CFTPClient::TransferFile(ftpClientSource, _T("/file.txt"),
                                       ftpClientTarget, _T("/newFile.txt"));
    
    
       // disconnect
       ftpClientTarget.Logout();
       ftpClientSource.Logout();
    }
    
    
    void TestDownloadAsciiFileIntoTextBuffer()
    {
       nsFTP::CFTPClient ftpClientSource;
       nsFTP::CLogonInfo logonInfoSource(_T("sourceftpserver"), 21, _T("anonymous"),
                                                           _T("<a href="mailto:anonymous@user.com">anonymous@user.com</a>"));
    
       // connect to server
       ftpClientSource.Login(logonInfoSource);
    
       nsFTP::COutputStream outputStream(_T("\r\n"), _T("Example"));
    
       // do file operations
       ftpClientSource.DownloadFile(_T("/file.txt"), outputStream,
                                    nsFTP::CRepresentation(nsFTP::CType::ASCII()));
    
       tstring output = outputStream.GetBuffer();
    
       // disconnect
       ftpClientSource.Logout();
    }
    
    

History

  • 2004-10-25 - First public release.
  • 2005-12-04 - Version 1.1
    • Some interfaces changed (e.g. CNotification).
    • Bug in OpenPassiveDataConnection removed: SendCommand was called before data connection was established.
    • Bugs in GetSingleResponseLine removed:
      • Infinite loop if the 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 another 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 a specific scenario of a FTP communication).
    • Replaced the magic numbers concerning the reply codes with a class.
    • New example added. A console application created with Bloodshed Dev-C++. It is only a small application which should demonstrate the use of the classes in a non Microsoft environment.
  • 2012-12-02 - Version 2.0
    • fixed some bugs
    • introduced more "data types" for more secure interfaces
    • code modified so it also runs under Linux
    • support for file eXchange Protocol (FXP)

What will be done next

  • Example application with Linux GNU-C++.
  • New features for FTP client class (for example: copy and delete recursively).
  • Unit tests.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

otom
Software Developer (Senior)
Germany Germany
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmemberMihai MOGA14-Dec-12 6:11 
GeneralMy vote of 5 Pinmemberjustdownloads13-Dec-12 0:46 
Questionis there resource leak? Pinmemberhaifeng21714-Aug-12 4:33 
AnswerRe: is there resource leak? Pinmemberwarmice525513-May-14 21:35 
Questiondownload files with filename matching Pinmembermallouna4-Jul-12 22:28 
SuggestionGreat Library small bug for File Modification Time PinmemberLefterisg30-May-12 6:03 
QuestionChange protocol Type Pinmemberjazaman14-May-12 19:31 
QuestionCan't compile the code PinmemberHooch18012-Feb-12 4:35 
AnswerRe: Can't compile the code PinmemberFrank Heimes11-Mar-12 23:09 
QuestionCalling of ::List() does not react at all PinmemberMember 440367423-Dec-11 5:00 
AnswerRe: Calling of ::List() does not react at all Pinmemberotom23-Dec-11 6:00 
GeneralRe: Calling of ::List() does not react at all [modified] PinmemberMember 440367423-Dec-11 6:54 
GeneralRe: Calling of ::List() does not react at all PinmemberMember 863475024-Apr-13 1:19 
BugSending/Receiving data using select() PinmemberKHSIEMENS21-Dec-11 21:56 
QuestionFtp Onresponse event [modified] Pinmemberpippo pioppo20-Dec-11 0:00 
QuestionLicence?? Pinmemberpippo pioppo8-Dec-11 23:45 
AnswerRe: Licence?? Pinmemberotom11-Dec-11 6:07 
QuestionGetting PinmemberSaviovt1020-Nov-11 23:12 
AnswerRe: Getting Pinmemberotom11-Dec-11 6:13 
QuestionReg: Writing a stream over FTPSession PinmemberSivaram Kannan3-Aug-11 4:10 
QuestionRegarding secure FTP PinmemberSaviovt1012-Jul-11 19:51 
AnswerRe: Regarding secure FTP Pinmemberotom12-Jul-11 21:03 
GeneralWSAStartup Problem Pinmemberwolf30572-Jan-11 14:58 
Generalerror when download file to strLocalFile which contains chinese word PinmemberSeshaal4-May-10 17:36 
GeneralAbort takes a lot of time! PinmemberSpringMVC19-Mar-10 0:43 
QuestionAny one can help me to download file on ftp server recursively by using these codes? Pinmembersongge17-Dec-09 21:28 
GeneralCompilling and running under VC++ 2002 PinmemberLeandro T C Melo14-May-09 4:28 
GeneralRe: Compilling and running under VC++ 2002 PinmemberJackSimmons1-Jun-09 13:17 
Many thanks to Leandro for his insights into initializing the use of Winsock, and for his other hints.
 
What is needed for the raw source zip is an example main. Here is one based on Leandro's advice, MSDN documentation for WSAStartup, and the example code given in the original posting.
 
When populated with my account particulars, this code lists the destination directory. (Sorry but this post has all its indentations removed.)
 

// FTP_Test.cpp : Defines the entry point for the console application.
//
 
#include
#include
#include "FTPClient.h"
 
int _tmain(int argc, _TCHAR* argv[])
{
int port_number = 21;
nsFTP::CFTPClient ftpClient;
nsFTP::CLogonInfo logonInfo(_T(""), port_number,
_T(""), _T(""));
 
// Initialize use of Winsock DLL by a process
 
WORD wVersionRequested;
WSADATA wsaData;
int err;
 
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
 
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
return 1;
}
 
/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we */
/* requested. */
 
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return 1;
}
else printf("The Winsock 2.2 dll was found okay\n");

/* The Winsock DLL is acceptable. Proceed to use it. */
/* Add network programming using Winsock here */
// In our case, do the ftp work
 
// connect to server
ftpClient.Login(logonInfo);
 
// get directory listing
nsFTP::TSpFTPFileStatusVector list;
ftpClient.List(_T("/"), list);
 
// iterate listing
for( nsFTP::TSpFTPFileStatusVector::iterator it=list.begin();
it!=list.end(); ++it )
printf("\n%s", (*it)->Name().c_str());
 
// do file operations
 
//ftpClient.DownloadFile(_T("/pub/test.txt"),
_T("c:\\temp\\test.txt"));
 
//ftpClient.UploadFile(_T("c:\\temp\\test.txt"),
_T("/upload/test.txt"));
 
//ftpClient.Delete(_T("/upload/NewName.txt"));
 
// disconnect
ftpClient.Logout();
 
/* Call WSACleanup when done using the Winsock dll */
WSACleanup();
 
// Finished
return 0;
}
GeneralBug in CFTPClient::UploadFile PinmemberGluck23-Apr-09 23:12 
General[Message Deleted] Pinmemberit.ragester2-Apr-09 21:58 
GeneralA very easy port to Linux PinmemberMember 455517230-Sep-08 6:14 
GeneralA comfortable FTP class in .NET PinmemberElmue27-Aug-08 12:18 
QuestionHas anyone got this to compile with VC6? Pinmemberpscholl21-Jul-08 5:28 
AnswerRe: Has anyone got this to compile with VC6? PinmemberDamDaDum28-Oct-08 3:26 
General... PinmemberAHTOXA18-Jun-08 2:41 
GeneralSOCKET handle(Control Link which listen to accept data link) unclosed when calling Upload PinmemberMember 458698613-Apr-08 22:10 
GeneralRe: SOCKET handle(Control Link which listen to accept data link) unclosed when calling Upload Pinmemberotom14-Apr-08 7:50 
GeneralRe: SOCKET handle(Control Link which listen to accept data link) unclosed when calling Upload Pinmemberlidongmao31-Jan-10 14:20 
Questionwhy the port is not released when I use port mode? Pinmember98863018-Dec-07 18:07 
GeneralRe: why the port is not released when I use port mode? Pinmemberotom27-Jan-08 19:22 
GeneralMFC compatability Pinmembertriplebit9-Nov-07 4:18 
GeneralReply error after upload/download files Pinmembercalvfoo1-Nov-07 0:20 
QuestionA program about UpLoadFile Pinmemberlihe8765440317-Oct-07 19:12 
AnswerRe: A program about UpLoadFile Pinmemberotom8-Oct-07 7:39 
GeneralRe: A program about UpLoadFile Pinmemberlihe8765440318-Oct-07 16:09 
GeneralRe: A program about UpLoadFile Pinmemberotom16-Oct-07 19:37 
GeneralRe: A program about UpLoadFile Pinmemberlihe87654403117-Oct-07 21:32 
GeneralRe: A program about UpLoadFile Pinmemberotom18-Oct-07 9:14 
GeneralRe: A program about UpLoadFile Pinmemberlihe87654403122-Oct-07 20:19 
Questionlinkage errors Pinmembergabriellopes19-Jun-07 14:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 9 Dec 2012
Article Copyright 2004 by otom
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid