|


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 (ports to UNIX a lot easier),
- not using other MFC-stuffs like
CString (uses STL),
- supports Firewalls,
- supports resuming,
- 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::CNotifaction
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): nsFTP::CFTPClient ftpClient;
nsFTP::CLogonInfo logonInfo("localhost", 21, "anonymous",
"anonymous@user.com");
ftpClient.Login(logonInfo);
nsFTP::TSpFTPFileStatusVector list;
ftpClient.List("/", list);
for( nsFTP::TSpFTPFileStatusVector::iterator it=list.begin();
it!=list.end(); ++it )
TRACE("\n%s", (*it)->Name().c_str());
ftpClient.DownloadFile("/pub/test.txt", "c:\\temp\\test.txt");
ftpClient.UploadFile("c:\\temp\\test.txt", "/upload/test.txt");
ftpClient.RenameFile("/upload/test.txt", "/upload/NewName.txt");
ftpClient.Delete("/upload/NewName.txt");
ftpClient.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.
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.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 86 (Total in Forum: 86) (Refresh) | FirstPrevNext |
|
|
 |
|
|
Very nice. Thank you. most of the problems i had were with the windows data types (USHORT, DWORD, SOCKADDR, etc.). i created another header file "ftp.h" to hold the typedefs and a few other definitions. also had to change the calls to "select".
still need to write a program to test all the functions, but from what i have seen it seems to work quite well.
thank you. Charles Wright
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hello
If you search a comfortable and reusable FTP client,
-- which is running on .NET Framework 1.1 or higher, -- which can automatically put together splitted files on the server, -- which allows to download only a part of a file on the server, -- which allows to resume any broken download, -- which automatically starts a separate thread, -- which can be aborted any time from your main thread, -- which supports UTF8 encoded filenames, -- which has a built-in download scheduler, -- which has a built-in bandwidth control, -- which has a built-in preview function for the download of movies, -- which automatically reconnects the server after an error has occurred, -- which displays download progress in percent and in bytes and the remaining time, -- which writes a detailed logging for all operations it does, -- which is based on Wininet.dll and has one workaround for each of the 4 known Wininet.dll bugs, -- which is very well tested and bug-free, -- which is written by a very experienced programmer and has a very clean and well documented sourcecode,
then have a look at this project:
ElmueSoft Partial FTP Downloader[^]
Elmü
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Apparently quite a few people have already tried to compile this with VC6 - but has anyone managed to compile this code without errors? What modifications are necessary and where? Please share any information that you may have. Thank you.
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
bool CFTPClient::ExecuteDatachannelCommand(const CDatachannelCmd& crDatachannelCmd, const tstring& strPath, const CRepresentation& representation, bool fPasv, DWORD dwByteOffset, ITransferNotification* pObserver) const { if( m_fTransferInProgress ) return false;
if( !IsConnected() ) return false;
// check representation if( m_apCurrentRepresentation.get()==NULL ) m_apCurrentRepresentation.reset(new CRepresentation(CType::ASCII())); if( representation!=*m_apCurrentRepresentation ) { // transmit representation to server if( RepresentationType(representation)!=FTP_OK ) return false; *m_apCurrentRepresentation = representation; }
std::auto_ptr apSckDataConnection(m_apSckControlConnection->CreateInstance()); if( fPasv ) { if( !OpenPassiveDataConnection(*apSckDataConnection, crDatachannelCmd, strPath, dwByteOffset) ) return false; } else { if( !OpenActiveDataConnection(*apSckDataConnection, crDatachannelCmd, strPath, dwByteOffset) ) return false; }
const 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; }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You are right. There is a bug in the CBlockingSocket class (see forum entry "Bug on connection break."). Add the following destructor to the file "BlockingSocket.cpp". CBlockingSocket::~CBlockingSocket() { Cleanup(); } After defining this destructor you can remove the line "apSckDataConnection->Close();" from ExecuteDatachannelCommand. The solution with the destructor is better than calling it directly.
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
I write two function ,in default use port mode. void ftptest() { nsFTP::CFTPClient ftpClient; nsFTP::CLogonInfo logonInfo;
logonInfo.SetHost(m_strFtpAddress.c_str(), m_iFtpPort, m_strFtpUserName.c_str(), m_strFtpPassword.c_str());
if (!ftpClient.Login(logonInfo)) { return ; }
nsFTP::TSpFTPFileStatusVector list; ftpClient.List("/", list);
for( nsFTP::TSpFTPFileStatusVector::iterator it=list.begin(); it!=list.end(); ++it ) { if( (*it)->IsCwdPossible() ) { if( !(*it)->IsDot() ) { std::string name = (*it)->Name().c_str(); printf("\n%s", name.c_str()); } } }
ftpClient.Logout(); } void test() { while(true) { ftptest(); } }
In the loop, the port is used by test one by one and no released, why? and how I can solve this problem?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I think it's the same problem as described in an earlier thread here. Add Cleanup to the destructor of CBlockingSocket. CBlockingSocket::~CBlockingSocket() { Cleanup(); }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Can I use the library in my code and call it from another C++ code using the MFC class CInternetConnection? Is it fully supported? Thanks Triplebit
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
> >if( !fTransferOK || !GetResponse(Reply) || !Reply.Code().IsPositiveCompletionReply() ) >
the above lines always return error after transferring multiple files.
Is this a problem in the program? or something else?
br,
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hello,I met a problem when i want to develop FTPClient with your FTPClass . A lot of warning about STL.I dont Know why,and when i use UploadFile,The program will be dead.When i tail the program ,It run to BOOL CBLockingSocket::Accept() { ... pConnect->m_hSocket = accept(m_hSocket, psa, &nLengthAddr); ..... } The program will be dead .Pls Help me~Thanks
Best Regards~
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
What compiler (development environment) do you use? - Microsoft (Visual Studio 6, 2003, 2005) - GNU compiler - or an other one What warnings do you get? What STL version do you use?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I use VS6.0, -The warnings are warning C4786 -one of my warning:
C:\Program Files\Microsoft Visual Studio\VC98\MFC\INCLUDE\afxcmn.inl(268) : warning C4786: 'std::_Treetification *>,std::allocator >::_Kfn,std::less,std::allocator >::const_iterator' : identifier was truncated to '255' characters in the debug information
-and STL is the default version when i install VS6.0.
The program can LogIn FTP ( which i have the popedom to upload and down load file),but i can not upload the file.
The code: ... if (ftpClient.UploadFile( "c:\\hehe.txt", "/ProjectDoing/Test/hehe3.txt" )) { box.MessageBox( " UpLoad Success! ", " hehe ", MB_OK ); } else { box.MessageBox( " UpLoad Fail! ", " hehe ", MB_OK ); }
... I found the uploading tread will be appended~ I dont know why ~
Best Regards~
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Using VS6.0 is the problem. Microsoft has made significant changes between the compiler in VS6.0 and VS2003. VS6.0 has a lot of deficits concerning to templates. The delivered STL implementation has changed in VS2003. As a result of this, there are compability problems between VS6.0 and VS2003. The source code have to be modified to run in VS6.0, but i don't have this version anymore.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
One last hint: If your problem only exists in release mode (and not in debug mode) then try to disable the optimization in the release version. Sometimes the optimization leads to undesired effects. (You can also disable optimization with "#pragma" statements if you can localize the problem.)
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hi,
CAN ANYONE PLEEEASE LEND A HAND ?
I've tried to use FTP Client Class in a .net 2005 c++ console application. I've added all the source files to the project. It compiles ok ... but I'm getting these linkage errors:
Linking... FTPClient.obj : error LNK2019: unresolved external symbol __imp__htonl@4 referenced in function "public: __thiscall nsSocket::CSockAddr::CSockAddr(unsigned long,unsigned short)" (??0CSockAddr@nsSocket@@QAE@KG@Z) FTPClient.obj : error LNK2019: unresolved external symbol __imp__htons@4 referenced in function "public: __thiscall nsSocket::CSockAddr::CSockAddr(unsigned long,unsigned short)" (??0CSockAddr@nsSocket@@QAE@KG@Z) FTPClient.obj : error LNK2019: unresolved external symbol __imp__inet_ntoa@4 referenced in function "public: class std::basic_string,class std::allocator > __thiscall nsSocket::CSockAddr::DottedDecimal(void)" (?DottedDecimal@CSockAddr@nsSocket@@QAE?AV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@XZ) FTPClient.obj : error LNK2019: unresolved external symbol __imp__ntohs@4 referenced in function "public: unsigned short __thiscall nsSocket::CSockAddr::Port(void)const " (?Port@CSockAddr@nsSocket@@QBEGXZ)
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Yes I can.
That's mainly why I can't figure out the reason for a simple console application failing to link. It's almost a "hello world" console application. I include FTPClient.h in the main module, and at linkage, I get the error I posted earlier. I've figured out the symbols reported missing by the compiler belong to winsock2.h, which rules out errors in the source code.
I'm guessing it has something to do with build directives ...
Any light?
Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks Lushan111,
I got it. The problem was related to the fact that the FTPClient code uses window.h and winsock2.h ... Windows.h uses winsock.h, and some symbols get mixed up because of that. You might say that if you include winsock2.h before windows.h, there wouldn't be a problem.
Since this isn't always possible, add the lib (Ws2_32.lib) to the linker settings.
Out
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I'm using the class for a uploading job, but I met a problem there and I'm looking for your help.
I built a ActiveX component and 2 threads in the ActiveX. One is used for UI and the other is used for uploading. I called the functions in the following sequence:
ftpClient.Login( ... ); ftpClient.Upload( ... );
During the uploading, I disable the network connection. Then the function uploading returns a "false" to me.
Then after 3 minutes, I enable the network connection and call ftpClient.Login, ftpClient.Upload again for resuming the job. I expect all the functions calls behave like the first time, but I'm wrong.
I found an internal error there when I called the function Upload, after several seconds as the timed-out number. Internal Error: Receive timeout error :\generalv\gvclient\generalv\ftpclient_demo\ftpclient.cpp:1,102 files..
I need to wait for a very long time, and restart the process, it seems work again.
Anyone knows why? Please help me....
Thanks,
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Is it a new ftpClient instance when you call Login the second time or is it the instance which you used on the first try? If it is the same instance then try to use a new one. Will this error only occurr in conjunction with the ActiveX control? What compiler do you use? What service pack (if you use visual studio) have you installed? Have you tried this scenario with different ftp servers? Have you tried to use an other ftp client for the second call?
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
I tried using both the same instance and a new one to do so. All seems not working if they are in the same process.
During the upload call, I disable the network connection, and after several miniutes after the function returned, I call Login and Upload again, and the login succeeded but upload fail.
If I close the application and reopen it. It works again.
I think i need to call some method of the ftpclient to clear the environment, such as close all the sockets, to make it like a fresh one, but I can't found a method to do so.
Do you recommend me to add a method to do so?
I'm using VS 2005 on Windows XP SP2.
-- modified at 4:46 Friday 15th June, 2007
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Following is my code, it is really simple. Please correct me if I have something wrong.
void CFTPClient1Dlg::OnBnClickedButton1() { nsFTP::CFTPClient ftpClient(nsSocket::CreateDefaultBlockingSocketInstance(), 30); nsFTP::CLogonInfo loginInfo; loginInfo.SetHost(static_cast(_T("192.168.1.10")), static_cast(2211), static_cast(_T("user")), static_cast(_T("passwd")), static_cast(_T("")));
bool hr = false; hr = ftpClient.Login( loginInfo ); if ( hr ) { MessageBox( L"Login Succeeded" ); } else { MessageBox( L"Login Failed" ); return; }
hr = ftpClient.UploadFile( _T("d:/video7.flv"), _T("1.flv") ); if ( hr ) { MessageBox( L"Upload file succeeded" ); } else { MessageBox( L"Upload file failed" ); } }
The bug's repro step is as following: 1. Click the button, and now the file is being transfered. 2. Disable the network connection. 3. Upload file failed is shown. 4. Enable the network connection. 5. Click the button again.
Expect behavior: 1. Messagebox "Login Succeeded" shown. 2. File is transferred. 3. MessageBox "Upload file succeeded" shown.
Actual behavior: 1. Messagebox "Login Succeeded" shown. 2. Messagebox "Upload file failed" shown. 3. Netstat shows that every retry will leave a Listening port there, if you close the process, all opening port disapperred.
I have retried for 30 times, each of two have 30 seconds interval. It still does not working.
I tried to use command line ftp to connect the server and put a file, it works.
So I think there is something not cleared when the network is unpluged, am I right?
The internal error I receive is "Internal Error: Receive timeout error :\generalv\gvclient\generalv\ftpclient_demo\ftpclient.cpp:1,102 files.."
At the same time, by "net state /a" I found the listening port of my pc is become more and more.
Therefore, it is a resource leak? or I have some thing wrong in using it?
Thanks, Mingju
-- modified at 4:44 Friday 15th June, 2007
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|