Description

This article presents a fully functional implementation of a FTP server. It can handle multiple connections at the same time (multi threaded) and has most of the features you would find in other commercial/shareware FTP servers. The server handles all basic FTP commands and offers easy user account management.

This article describes the most important classes of the application:

CFTPServer

This class is in fact the FTP server, and controls all other classes needed for the server to work. Although CFTPServer is part of a dialog based application, it does not rely on a User Interface and can easily be implemented in a service or console application as well.

Deactivates the server and disconnects all connected clients by terminating the running threads.

BOOL IsActive()

Is FTP server active?

void SetMaxUsers(int nValue)

Set maximum number of users.

void SetPort(int nValue)

Set listening port for new connections.

void SetTimeout(int nValue)

Set connection timeout (in ms). When a client does not send any commands for nValue ms, the server will close the connection.

void SetWelcomeMessage(LPCTSTR lpszText)

Set the text that will be displayed when the client logs on.

void Initialize(CFTPEventSink *pEventSink)

Set the event sink. The event sink will be the window (or any class) that receives the events generated by the FTP server. See CFTPEventSink description for more info.

CFTPEventSink

To be able to 'send' events from the CFTPServer class to the main application, I used multiple inheritance and virtual functions. The CFTPEventSink is just a helper class that contains nothing else than virtual functions, when you derive your class from CFTPEventSink these virtual functions become a kind of events. The class CFTPServer has a reference to this class and calls the virtual functions when it needs to notify the application.

A statistic has changed, for example the number of downloaded or uploaded files.

Other helper classes:

CUserManager

The class CUserManager handles all user and file related stuff. It checks the connected users for their access rights and converts remote to local paths. CUserManager uses serializing for storing and loading the user settings.

CListenSocket

This socket is part of CFTPServer and accepts incoming connections. When a clients connects to the server, CListenSocket accepts the connection and creates a new thread (CConnectThread) that will take care of all further communication between the client and the server. After the thread has been created, CListenSocket will return to its waiting state.

CConnectThread

This thread will handle all communication between the client and the server using CConnectSocket.

CConnectSocket

This socket class will process all incoming FTP commands and send back the response to the client.

CDataSocket

When data needs to be send or received, a CDataSocket will be created by CConnectSocket. The CDataSocket class will transfer this data (such as directory listings and files) on a separate port.

All the other classes are just UI related and are only included to make it look a little bit fancier.

CFTPServer Usage:

To use the class in your application, you need to do the following:

Add the class to your application.

Derive your main class from CFTPEventSink.

Override the virtual functions of CFTPEventSink; these are the events that come from the server.

Contacting the Author

Credits

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

neither this FTP server, nor Baby FTP are not supports files greater than 4Gb
i've fixed it by simple using I64 modificator in format string in CControlSocket::GetDirectoryList [ strLength.Format("%I64d", find.GetLength()); ] and using of ULONGLONG as type for CDataSocket::m_nTotal* variables

Hi !,
I found this article is interesting and wanted to use the source in my project.
I have to develop a FTP server with minimum functionality (uploading and downloding the files).
Please let me know if I use the source is there any licensing problems ?
An early reply appriciated.

I have found serval bugs in your program. One of them is that the program run very well in WINDOWS98(Client)/Windows98(Server), or Window2k|XP(Client)/Windows2k|XP running mode, but there will be a bug in Windows98(client)/Windows2K|XP running mode. The client software is using your FTP client program.

I found the receive() got a big problem.

If a FTP transfer finished sucessfully, the program will use the Receive() function at least twice. First time. it receive the data of XXX characters, XXX is less or equal to PACKET_SIZE, second it must be 0 character.

But in Win98(client)/Win2K(Server) mode, sometime the program only pass the function one time. so it not past the statement:

Unfortunately I do not have the time to update this article.
But for the latest version see:
http://www.pablovandermeer.nl/ftp_server.html
or
http://www.pablovandermeer.nl/ftp_server_2_0.html
This bug and many other have been fixed.

The original sample application bypasses most of MFC debug-time verifications. The sample application's project file undefines the _DEBUG define. As a result no ASSERT() macros are executed, especially those in MFC's wincore.cpp.

This becomes apparent when you handle overridden OnFTPStatusChange() notifications and try to update your MFC object instance. The code ASSERTS in wincore.cpp because the call is made directly via a pointer to an MFC instance passed to another thread.

If you're going to use this code within another project, you'll have to implement the mechanism of invoking OnFTPStatusChange() via a message or using a HWND to get a hold of your MFC instance.

It's not totally clear what you mean. As far as I can tell everything works the way it should. ASSERTS will work just fine. Check out my other example: FTP server as a NT service on my website. It uses the same classes in a windowless environment.