用VC编写Ftp客户程序

 用VC编写Ftp客户程序

作者:Panda  
转载日期:2002年3月28日
转自
:程序春秋

文章正文

       随着Internet的迅猛发展,网络软件的开发与设计显得越来越重要。最初的网络软件主要是以UNIX操作系统为软件开发环境的,随着Windows个人操作系统的流行,传统的编程界面向这一新的软硬件平台转换变得极为迫切。VC++5.0版的MFC封装了的CSocket类提供了高级的SOCKET支持,为编写因特网环境下基于Windows平台的C/S程序提供了极大的方便。本文通过利用CSocket类编写一个FTP客户程序为例介绍了其使用方法,向你揭开网络编程的秘密。
    
     WINSOCK以动态链接库的形式向程序员提供了一个功能强大的函数集,通过对这个函数集的调用,应用程序可以完成其特定的任务。然而缺点是程序较为繁琐。为了解决这一问题,Microsoft对其推出的Visual C++系列的基本类库(MFC)做了逐步的完善。MFC封装了许多与网络程序设计相关的类。CSocket就是其中之一。
    
     CSocket类(父类为CAsyncSocket)提供了一个高级的SOCKET支持,完成对低层函数的操作,大大降低了编程难度。这里,以编写一个Ftp客户程序来说明如何深入有效地利用CSocket类进行网络软件的开发。
    
     首先,建立一个SDI(单文档界面)应用程序的基本框架。这一步比较简单,在VC++中,MFC AppWizard通过创建一个新的项目(Project)而被激活,选择File菜单中的New选项,选取Project,输入文件名为SuperFTP,选择OK。随后的步骤为VC++自动创建过程,可以参见相关资料,不再详述。最后生成以下几个主要类:
       CMainFrame,
       CSuperFTPApp,
       CSuperFTPDoc,
       CSuperFTPView,
       CAboutDlg。

         
         
     第二步,具体程序的编制。由于整个程序比较长,下面给出主要部分的核心代码并附注释。
       1.MainFrm.cpp:
         ……
         CMainFrame::CMainFrame()
        {
         //初始化指针
         m_ctrlconn=NULL;
         m_dataconn=NULL;
         m_recvconn=NULL;
         }
         //选择菜单项“快速连接”
         void CMainFrame::OnQuickconnect()
         {
         if(!Makeconn())
         MessageBox(“FTP控制链路建立失败!”,“提示”,MB_ICONWARNING);
         if(!MakeRemoteDir())
         MessageBox(“FTP数据链路建立失败!”,“提示”,MB_ICONWARNING);
         }
         //建立控制链路
         BOOL CMainFrame::Makeconn()
         {
         ……
         Quickconn dlg;
         //输入服务器名,用户名,口令
         if (dlg.DoModal()==IDOK)
         {
         fservername=dlg.m_servername;
         fusername=dlg.m_username;
         fpassword=dlg.m_password;
         }
         m_ctrlconn=new ctrlsocket();
         //建立一个SOCKET
         If(!m_ctrlconn->Create(0,SOCK_STREAM,NULL)
         {
         delete m_ctrlconn;
         m_ctrlconn=NULL;
         MessageBox(“Socket()建立失败!”,“提示”,MB_ICONWARNING);
         return FALSE;
         }
         //申请网络事件通知
         If(!m_ctrlconn->AsyncSelect(FD_READ|FD_WRITE|FD_ACCEPT|FD_CONNECT|FD_CLOSE))
         {
         MessageBox(“AsyncSelect()错误!”,“提示”,MB_ICNWARNING);
         return FALSE;
         }
         BeginWaitCursor();
         //向由fservername指定的主机发出连接请求
         if(!m_ctrlconn->Connect(fservername,IPPORT_FTP))
         {
         delete m_ctrlconn;
         m_ctrlconn=NULL;
         MessageBox(远端服务器连接失败!”,“提示”,MB_ICONWARNING);
         return FALSE;
         }
         EndWaitCursor();
         ……
         return TRUE;
         }
         
         如果选择了“匿名”登录,应用程序则自动将用户姓名和口令字填充为:anonymous,guest@unknown
         BOOL CMainFrame::MakeRemoteDir()
         {
         if(m_ctrlconn==NULL)
           {
           (“请连接到服务器!”,“提示”,MB_iconwarwing);
           retrurn FALSE;
           }
           if(!MakeDataListen())
           {
           MessageBox(“数据链路建立失败!”,“提示”,MB_ICONWARNING);
           return FALSE;
           }
           ……
           return TRUE;
         }
         //处理来自远端服务器的响应
         BOOL CMainFrame::Processftp()
         {
         ………
         }
         //建立数据连接“监听”函数
         BOOL CMainFrame::MakeDataListen()
         {
         ……
         m_dataconn=new Listensocket();
         /* 建立一个SOCKET,并与本地主机地址捆绑。作为一个例子,直接插入了本机的IP地址“90.0.0.8”,而在实际应用中应首先通过相应的函数调用取得本地主机地址。
         注意:如果不采用VC++的CSocket类而用其它的方法,需在建立SOCKET之后,调用bind()函数来进行与本地主机地址的捆绑。*/
         if(!m_dataconn->Create(0,SOCK_STREAM,“90.0.0.8”))
         {
         delete m_dataconn;
                m_dataconn=NULL;MessageBox(“Socket()建立失败!”,“提示”,MB_ICONWARNING);
         return FALSE;
         }
         //申请网络事件通知
         if(!m_dataconn->AsyncSelect(FD_ACCEPT))
         {
         delete m_dataconn;
                m_dataconn=NULL;
         MessageBox(“AsyncSelect()错误!”,“提示”,MB_ICONWARNING);
         return FALSE;
         }
         ……
         if(!m_dataconn->Listen(5))
         {
         MessageBox(“listen()错误!”,“提示”,MB_ICONWARNING);
         return FALSE;
         }
         ……
         }
         //接受数据连接请求的函数
         BOOL CMainFrame::AcceptDataConn()
         {
         int num,nRet;
         SOCKADDR_IN RemoteDataAddr;
         num=sizeof(SOCKADDR_IN);
         if(m_recvconn==NULL)
         {
         m_recvconn=new Datasocket();
         }
         if(!m_dataconn->Accept(*m_recvconn,(LPSOCKADDR)&RemoteDataAddr,(int FAR*)&num))
         {
         MessageBox(“accept()错误!”,“提示”,MB_ICONWARWING);
         return FALSE;
         }
         ……
         m_dataconn->Close();
         //申请网络事件通知
         if(!m_recvconn->AsyncSelect(FD_READ|FD_WRITE|FD_CLOSE)
         {
         MessageBox(“Asyncselect()错误!”,“提示”,MB_ICONWARNING);
         return FALSE;
         }
         return TRUE;
         }
         //数据接受函数,接受来自远端服务器的数据
         int CMainFrame::RecvData()
         {
         ……
         int nRet=m_recvconn->Receive(…);
         if (nRet>0)
         {
         …
         }
         else
         {
         …
         }
         ……
         }
         2.ctrlsocket.cpp
         ……
         void ctrlsocket::OnReceive(int nErrorCode)
         {
         //处理网络事件FD_READ
         CSocket::OnReceive(nErrorCode);
         ((CmainFrame *)(AfxGetApp()->m_pMainWnd))->Processftp();
         }
         3.Listensocket.cpp
         ……
         void Listensocket::OnAccept(int nErrorCode)
         {
         //处理网络事件FD_ACCEPT
         CSocket::OnAccept(nErrorCode);
         ((CmainFrame*)AfxGetApp()->m_pMainWnd))->AcceptDataConn();
         }
         4.Datasocket.cpp
         ……
         Datasocket::OnReceive(int nErrorCode)
         {
         //处理网络事件FD_READ
         CAsyncSocket::OnReceive(nErrorCode);
         ((CMainFrame*)(AfxGetApp()->m_pMainWnd))->RecvData();
         }
         void Datasocket::OnSend(int nErrorCode)
         {
         //处理网络事件FD_WRITE
         CAsyncSocket::OnSend(nErrorCode);
         ((CMainFrame*)(AfxGetApp()->m_pMainWnd))->SendData();
         }
    
         程序执行时左下窗口为本地系统,右下窗口为远端系统。通过激活相关的菜单项,就可以对远端主机的文件系统进行下载操作。当然,如果Ftp服务器允许上载,你也可以将自己的文件传送到远端主机。

你可能感兴趣的:(网络,socket,null,delete,mfc,vc++)