FTP 客户端类
一个封装 FTP 协议的非 MFC 类。
引言
CFTPClient
是一个封装 FTP 协议的类。我试图使其平台无关。为了进行通信,我使用了 David J. Kruglinski 的《Inside Visual C++》中的类 CBlockingSocket
、CSockAddr
等。这些类只是对 sockets API 的小包装。此外,我使用了 Scott Meyers 的《Effective C++》、《More Effective C++》、《Effective STL》中的智能指针实现。登录序列(带防火墙支持)的实现由 Phil Anderson 在 CodeGuru 上的一篇文章发表。用于解析不同 FTP LIST 响应的代码来自 D. J. Bernstein 的(解析代码)。我只是将 C 代码封装在一个类中。我没有在其他平台上测试过代码,但我认为只需稍作修改,它就能顺利编译并运行。
主要功能包括
- 不基于 MFC-sockets,
- 不使用其他 MFC 要素,如
CString
(使用 STL), - 支持防火墙,
- 支持续传,
- 支持文件交换协议 (FXP) - 使用 FTP 直接从一个远程服务器传输数据到另一个服务器(服务器必须支持此功能),
- 在 Windows 上使用 Visual Studio 2008 测试,
- 在 Linux (Suse 11.4) 上使用 Qt 测试,
- 可以通过定义 USE_BOOST_SMART_PTR 或 USE_STD_SMART_PTR 来轻松地将智能指针实现替换为 boost::shared_ptr 或 std::shared_ptr,
- 可以通过实现接口 "IFileListParser" 来替换解析 LIST 命令输出的解析器,
- 易于扩展。
该示例展示了使用此类是多么容易。只需几行代码,您就可以记录通信或可视化文件传输。注意:该示例不是一个功能齐全的 FTP 客户端应用程序。该示例应用程序仅适用于 Windows 平台。
背景
文件传输协议 (FTP) 的官方规范是 RFC 959。我的代码中的大部分文档都取自此 RFC。
使用代码
有很多类。但大多数只是简单的“数据类型”。其中最重要的类如下:
CFTPClient
应用程序的核心。它接受一个CLogonInfo
对象。处理与 FTP 服务器的完整通信,例如:- 获取目录列表,
- 下载/上传文件,
- 删除目录/文件,
- 遍历目录树,
- 被动模式,
- ...
CLogonInfo
用于登录信息的简单数据结构,例如主机、用户名、密码、防火墙等。CFTPClient::IFileListParser
用于定义解析类接口,该接口可以设置在CFTPClient
类中,用于解析 LIST 命令的输出。CFTPClient::ITransferNotification
此接口的实现可以在 Download 和 Upload 方法中使用,用于控制正在下载/上传的字节流。例如,这可用于仅将文件下载到内存而不是本地文件(参见类COutputStream
)。CFTPClient::CNotification
通知机制的基类。派生自CFTPClient::CNotifaction
的类可以作为观察者附加到CFTPClient
类。CFTPClient
对象会通知所有附加的观察者关于各种操作(请参阅示例应用程序)。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(); }
历史
- 2004-10-25 - 首次公开发布。
- 2005-12-04 - 版本 1.1
- 一些接口已更改(例如
CNotification
)。 - 已删除
OpenPassiveDataConnection
中的错误:在数据连接建立之前调用了SendCommand
。 - 已删除
GetSingleResponseLine
中的错误- 如果响应行不以 CRLF 结尾,则会出现无限循环。
- 必须将
std:string
->find 的返回值与npos
进行比较。
- 现在可以在 Unicode 下运行。
- 流已删除。
- 不再需要显式分离观察者。
ExecuteDatachannelCommand
现在接受一个ITransferNotification
对象。通过这种概念,无需将接收到的文件写入文件。例如,字节可以仅写入内存或其他 TCP 流。- 添加了阻塞套接字接口(
IBlockingSocket
)。因此,可以更换套接字实现,例如用于编写单元测试(通过模拟 FTP 通信的特定场景)。 - 用一个类替换了与应答代码相关的魔术数字。
- 添加了新示例。一个使用 Bloodshed Dev-C++ 创建的控制台应用程序。这是一个小型应用程序,用于演示在非 Microsoft 环境中使用这些类。
- 一些接口已更改(例如
- 2012-12-02 - 版本 2.0
- 修复了一些错误
- 引入了更多“数据类型”以实现更安全的接口
- 修改了代码,使其也可以在 Linux 下运行
- 支持文件交换协议 (FXP)
接下来要做什么
- 带 Linux GNU-C++ 的示例应用程序。
- FTP 客户端类的新功能(例如:递归复制和删除)。
- 单元测试。