4.3.3 获取FTP服务器文件信息
当用户编程(www.cppentry.com)时,需要获取FTP服务器文件的列表,以便查看文件的相关信息。本节将向用户讲述怎样获取FTP服务器文件的相关信息。
1.获取文件列表
一般情况下,FTP文件列表信息是通过客户端和服务器端之间的数据通道获取。编程(www.cppentry.com)中,用户可以向服务器发送LIST命令,服务器接收到该命令以后会向客户端返回FTP目录下的文件列表信息。需要用户注意,在PORT模式下传输数据,客户端需要向服务器提交本地IP地址和用于返回数据的端口号。
- CSocket m_Client; //客户端套接字变量
- CString m_host; //IP地址字符串变量
- UINT nport,port=111; //端口号
- m_Client.GetSockName(m_host,nport); //调用函数获得本地的IP地址
- m_host.Format(m_host+",%d",port); //格式化字符串
用户使用PORT命令可以向服务器发送端口号码。格式如:"PORT"+string。其中string表示已经格式化的IP和端口字符串。代码如下:
- m_archive->WriteString("PORT "+ m_host+"\r\n");
- //调用CArchive类的WriteString()函数发送
- m_archive->Flush();
客户端发送端口之后,必须在该端口上进行监听,以便接受服务器的连接请求。用户需要注意,在服务器和客户端连接关闭以前,服务器均按照此次的IP和端口与客户端进行数据交换。监听代码如下:
- m_Client.Create(111,SOCK_STREAM,NULL);
//创建在111端口上监听的套接字- m_Client.Listen(); //进行监听
现在,用户可以向服务器发送LIST命令获取相关文件的信息。发送LIST命令的代码如下:
- Try
- { //尝试发送命令LIST到服务器,以获取文件列表
- m_archive->WriteString("LIST "+"\r\n");
- //调用CArchive类的WriteString()函数发送LIST命令
- m_archive->Flush();
- }
- Catch(CException e)
- { MessageBox("发送关闭命令失败!"); } //抛出错误并处理错误
当用户向服务器发送LIST命令后,服务器会向客户端提供的IP地址和端口号发出连接请求。所以,当客户端在指定端口上监听到连接请求后,应该对该连接进行处理。
一般情况下,用户将套接字设置为非阻塞模式,避免出现等待状态。当监听套接字检测到有连接请求到来时才响应,否则套接字一直处于监听状态。用户可以使用AP函数Accept()来响应服务器的连接请求。代码如下:
- #define WM_ACCEPT WM_USER+100 //自定义消息,用于响应连接请求
- afx_msg Void OnAccept(WPARAM wParam,LPARAM lParam) //声明响应连接请求的函数
- ... //省略部分代码
- BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
- //{{AFX_MSG_MAP(CMyApp)
- // NOTE - the ClassWizard will add and remove mapping macros here.
- // DO NOT EDIT what you see in these blocks of generated code!
- //}}AFX_MSG
- ON_COMMAND(ID_HELP, CWinApp::OnHelp)
- ON_MESSAGE(WM_ACCEPT, OnAccept) //处理消息映射
- END_MESSAGE_MAP()
首先,用户需要自定义消息WM_ACCEPT用于响应连接请求,然后添加消息映射将自定义消息和实现函数关联起来。在Win32 API中,WSAAsyncSelect()函数可以将套接字设置为非阻塞模式,其原型如下:
- int WSAAsyncSelect(SOCKET s,HWND hWnd,int wMsg,long lEvent);
用户使用该函数时,应该包含Windows Socket的头文件和相应的库文件。代码如下:
- #include <winsock2.h> //包含Windows Socket头文件
- #pragma comment(lib,"WS2_32.lib") //编译时连接WS2_32库
- ...
使用函数WSAAsyncSelect()时,参数wMsg表示自定义消息WM_ACCEPT。参数lEvent表示通知码,其取值如表4.6所示。该函数调用成功后,会一直检查通知码,直到指定的网络事件发生,否则将返回0。
表4.6 lEvent取值
|
取 值< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> |
含 义 |
|
FD_READ |
表示套接字接收到对方发送的数据, 用户可对其进行读取 |
|
FD_WRITE |
通知用户可以继续发送数据 |
|
FD_ACCEPT |
表示套接字上有连接请求到来 |
|
FD_CONNECT |
套接字连接成功 |
|
FD_CLOSE |
套接字检测到对应的连接被关闭 |
在这里,用户只检测有无连接请求到来,所以lEvent设置为FD_ACCEPT。代码如下:
- ::WSAAsyncSelect(m_Client,m_hSocket,this->m_hWnd,
WM_ACCEPT, FD_ACCEPT| FD_READ);- //将套接字设置为非阻塞模式
当有对应的套接字请求到来时,程序调用自定义消息响应函数进行处理。代码如下:
- void OnAccept(WPARAM wParam,LPARAM lParam)
- {
- SOCKET ss;
- sockaddr_in adder;
- char sz[1024]={0};//定义缓冲区
- switch(LOWORD(lParam))//参数lParam的低字节表示通知码
- { case FD_ACCEPT; //检测到有连接请求到来
- ss=::Accept(m_Client.m_hSocket,adder,sizeof(adder));
- //接受到来的连接请求,返回一个临时套接字
- ... //省略部分代码
- case FD_READ:
- ::recv(ss,&sz,1024,0); //接收数据到缓冲区
- ...//省略部分代码
- }}
客户端检测到连接请求后,调用函数recv()进行接收,并将数据保存在缓冲区sz中。关于接收到的列表信息如何进行显示等操作将在最后一节实例中讲述。在这里,用户需要注意函数Accept()调用成功后会返回一个临时套接字的句柄。
2.获取FTP文件属性
用户发送LIST命令以后,服务器返回信息中包含了文件的一些属性,包括时间、大小等。服务器返回的每条信息都是以"\r\n"结束,在每条信息中以空格分开。
首先,用户需要对缓冲区sz中的数据进行解析得到一条完整的消息。代码如下:
- char buf[100]={0}; //用于保存临时数据
- for(int i=0;i<1024;i++)//循环解析消息数据以获得一条完整的信息
- {
- if(sz[i]!="\")buf[i]==sz[i]; //取得的
信息不是"\",则保存到临时变量- else
- { if(sz[i+1]=="r")MessageBox("成功解析一条消息!");
- //如果取得的是结束符号,则提示成功提取
- }
- }
上面的代码用于提取一条完整的信息,并将其保存在临时变量buf中。接下来,用户可以对提取到的信息再进行详细的解析,以便得到具体的文件属性。代码如下:
- char ch="a"; //初始化字符变量
- CString str=""; //定义字符串
- int i=0,j=0; //定义循环变量
- while(ch!=""&&i<1024)
- {
- if(buf[i]!=""&&buf[i+1]==EOF)str+=(CString)buf[i];
- //如果不是空格则保存在字符串变量中
- else
- {
- ch=buf[i+1]; //如果是空格则移动到下一个字符
- i+=1;
- j+=1;
- str=""; //将字符串变量重新设置
- }
- switch(j) //根据变量j进行选择信息字符段
- {
- case 1:
- MessageBox("文件最后一次保存的日期是:%c",str);
- case 2:
- MessageBox("文件最后一次保存的时间是:%c",str);
- case 3:
- MessageBox("文件的大小是:%c",atoi(str));
- case 4:
- MessageBox("文件的名称是:%c",str);
- }
- }
上述代码实现的功能是对一条信息进行分析,得到文件准确的保存日期、时间和大小。用户需要了解在Windows下,FTP服务器返回的信息格式,例如,08-23-12 10:06AM 16056 list.txt。该字符串第一段"08-23-12"表示文件保存的日期。第二段"10:06AM"表示保存时间。第三段"16056"表示文件大小。第四段"list.txt"表示文件名称。
关于获取FTP文件其他属性的方法,请用户参考其他书籍,本书将不再进行讲述。