zoukankan      html  css  js  c++  java
  • VC FTP服务器程序分析(四)

      下面是数据传输的重点-CDataSocket类,函数不多,都比较重要。

      1、OnAccept  数据tcp服务器被连接的虚函数,由框架调用。

     1 void CDataSocket::OnAccept(int nErrorCode) 
     2 {
     3     // Accept the connection using a temp CSocket object.
     4     CAsyncSocket tmpSocket;
     5     Accept(tmpSocket);
     6     
     7     SOCKET socket = tmpSocket.Detach();
     8     Close();
     9 
    10     Attach(socket);
    11 
    12     m_bConnected = TRUE;
    13     
    14     CAsyncSocket::OnAccept(nErrorCode);
    15 }

      第7行 得到套接字描述符socket。第8行关闭监听的这个套接字,第11行关联socket与本对象,第12行,标记连接标志。这种处理方法少写一个类。因为tcp监听得一个socket,而连接上来的客户端也需要一个socket来与之通信。这样做适合只有一个客户端的情况。

      2、OnReceive  数据接收处理函数

     1 int CDataSocket::Receive()
     2 {
     3     TRACE("OnReceive
    ");
     4     int nRead = 0;
     5     
     6     if (m_pControlSocket->m_nStatus == STATUS_UPLOAD)
     7     {
     8         if (m_File.m_hFile == NULL)
     9             return 0;
    10 
    11         byte data[PACKET_SIZE];
    12         nRead = CAsyncSocket::Receive(data, PACKET_SIZE);
    13 
    14         switch(nRead)
    15         {
    16             case 0:
    17             {
    18                 m_File.Close();
    19                 m_File.m_hFile = NULL;
    20                 Close();
    21                 // tell the client the transfer is complete.
    22                 m_pControlSocket->SendResponse("226 Transfer complete");
    23                 // destroy this socket
    24                 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
    25                 break;
    26             }
    27             case SOCKET_ERROR:
    28             {
    29                 if (GetLastError() != WSAEWOULDBLOCK)
    30                 {
    31                     m_File.Close();
    32                     m_File.m_hFile = NULL;
    33                     Close();
    34                     m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");
    35                     // destroy this socket
    36                     AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
    37                 }
    38                 break;
    39             }
    40             default:
    41             {
    42                 TRY
    43                 {
    44                     m_File.Write(data, nRead);
    45                 }
    46                 CATCH_ALL(e)
    47                 {
    48                     m_File.Close();
    49                     m_File.m_hFile = NULL;
    50                     Close();
    51                     m_pControlSocket->SendResponse("450 Can't access file.");
    52                     // destroy this socket
    53                     AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
    54                     return 0;
    55                 }
    56                 END_CATCH_ALL;
    57                 break;
    58             }
    59         }
    60     }
    61     return nRead;
    62 }

      如果处于上传状态,那么将接收到的数据写入文件。

      3、PreSendFile 与发送文件有关的函数

     1 BOOL CDataSocket::PrepareSendFile(LPCTSTR lpszFilename)
     2 {
     3     // close file if it's already open
     4     if (m_File.m_hFile != NULL)
     5     {
     6         m_File.Close();
     7     }
     8                                       
     9     // open source file
    10     if (!m_File.Open(lpszFilename, CFile::modeRead | CFile::typeBinary))
    11     {
    12         return FALSE;
    13     }
    14     m_nTotalBytesSend = m_File.GetLength();
    15 
    16     if (m_pControlSocket->m_dwRestartOffset < m_nTotalBytesSend)
    17     {
    18         m_nTotalBytesTransfered = m_pControlSocket->m_dwRestartOffset;
    19     }
    20     else
    21     {
    22         m_nTotalBytesTransfered = 0;
    23     }
    24     return TRUE;
    25 }

     初始化文件描述符m_File,m_nTotalBytesSend,m_nTotalBytesTransfered。

     4、 SendFile函数  调用PrepareSendFile,调用OnSend发送文件。

     1 void CDataSocket::SendFile(LPCTSTR lpszFilename)
     2 {
     3     if (!PrepareSendFile(lpszFilename))
     4     {
     5         // change status
     6         m_pControlSocket->m_nStatus = STATUS_IDLE;
     7 
     8         m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");
     9 
    10         // destroy this socket
    11         AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
    12         return;
    13     }
    14     OnSend(0);
    15 }

     5、SendData 发送数据 是为了LIST命令而准备,发送文件目录列表。

     6、OnSend 主要区分了list命令的情况和download的情况。

      1 void CDataSocket::OnSend(int nErrorCode) 
      2 {
      3     CAsyncSocket::OnSend(nErrorCode);
      4     switch(m_pControlSocket->m_nStatus)
      5     {
      6         case STATUS_LIST:
      7         {
      8             while (m_nTotalBytesTransfered < m_nTotalBytesSend)
      9             {
     10                 DWORD dwRead;
     11                 int dwBytes;
     12 
     13                 CString strDataBlock;
     14                 
     15                 dwRead = m_strData.GetLength();
     16                 
     17                 if (dwRead <= PACKET_SIZE)
     18                 {
     19                     strDataBlock = m_strData;
     20                 }
     21                 else
     22                 {
     23                     strDataBlock = m_strData.Left(PACKET_SIZE);
     24                     dwRead = strDataBlock.GetLength();
     25                 }
     26                 
     27                 if ((dwBytes = Send(strDataBlock, dwRead)) == SOCKET_ERROR)
     28                 {
     29                     if (GetLastError() == WSAEWOULDBLOCK) 
     30                     {
     31                         Sleep(0);
     32                         return;
     33                     }
     34                     else
     35                     {
     36                         TCHAR szError[256];
     37                         wsprintf(szError, "Server Socket failed to send: %d", GetLastError());
     38 
     39                         // close the data connection.
     40                         Close();
     41 
     42                         m_nTotalBytesSend = 0;
     43                         m_nTotalBytesTransfered = 0;
     44 
     45                         // change status
     46                         m_pControlSocket->m_nStatus = STATUS_IDLE;
     47 
     48                         m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");
     49 
     50                         // destroy this socket
     51                         AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
     52                     }
     53                 }
     54                 else
     55                 {
     56                     m_nTotalBytesTransfered += dwBytes;
     57                     m_strData = m_strData.Mid(dwBytes);
     58                 }
     59             }
     60             if (m_nTotalBytesTransfered == m_nTotalBytesSend)
     61             {
     62                 // close the data connection.
     63                 Close();
     64 
     65                 m_nTotalBytesSend = 0;
     66                 m_nTotalBytesTransfered = 0;
     67 
     68                 // change status
     69                 m_pControlSocket->m_nStatus = STATUS_IDLE;
     70 
     71                 // tell the client the transfer is complete.
     72                 m_pControlSocket->SendResponse("226 Transfer complete");
     73                 // destroy this socket
     74                 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
     75             }
     76             break;
     77         }
     78         case STATUS_DOWNLOAD:
     79         {
     80             while (m_nTotalBytesTransfered < m_nTotalBytesSend)
     81             {
     82                 // allocate space to store data
     83                 byte data[PACKET_SIZE];
     84                 
     85                 m_File.Seek(m_nTotalBytesTransfered, CFile::begin);
     86 
     87                 DWORD dwRead = m_File.Read(data, PACKET_SIZE);
     88     
     89                 int dwBytes;
     90 
     91                 if ((dwBytes = Send(data, dwRead)) == SOCKET_ERROR)
     92                 {
     93                     if (GetLastError() == WSAEWOULDBLOCK) 
     94                     {
     95                         Sleep(0);
     96                         break;
     97                     }
     98                     else
     99                     {
    100                         TCHAR szError[256];
    101                         wsprintf(szError, "Server Socket failed to send: %d", GetLastError());
    102 
    103                         // close file.
    104                         m_File.Close();
    105                         m_File.m_hFile = NULL;
    106 
    107                         // close the data connection.
    108                         Close();
    109 
    110                         m_nTotalBytesSend = 0;
    111                         m_nTotalBytesTransfered = 0;
    112 
    113                         // change status
    114                         m_pControlSocket->m_nStatus = STATUS_IDLE;
    115 
    116                         m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");
    117 
    118                         // destroy this socket
    119                         AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
    120                     }
    121                 }
    122                 else
    123                 {
    124                     m_nTotalBytesTransfered += dwBytes;
    125                 }
    126             }
    127             if (m_nTotalBytesTransfered == m_nTotalBytesSend)
    128             {
    129                 // close file.
    130                 m_File.Close();
    131                 m_File.m_hFile = NULL;
    132 
    133                 // close the data connection.
    134                 Close();
    135 
    136                 m_nTotalBytesSend = 0;
    137                 m_nTotalBytesTransfered = 0;
    138 
    139                 // change status
    140                 m_pControlSocket->m_nStatus = STATUS_IDLE;
    141 
    142                 // tell the client the transfer is complete.
    143                 m_pControlSocket->SendResponse("226 Transfer complete");
    144                 // destroy this socket
    145                 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
    146             }
    147             break;
    148         }
    149     }
    150 }

      7、OnConnect函数  tcp连接成功时被框架调用的虚函数。

      8、OnClose函数 当数据发送完成或者接收完成后被框架调用的虚函数。主要做清理工作。

      9、

     

  • 相关阅读:
    数据访问(从数据库中访问数据)
    加载类、设计模式(单例模式和工厂模式)
    面向对象之静态
    面向对象三大特性之继承和多态
    面向对象三大特性之封装
    面向对象基础知识
    mysql下载与安装过程
    Idea添加依赖的步骤:
    Java JDBC 在IDEA环境下连接MySQL
    JAVA中集合HashMap嵌套联系
  • 原文地址:https://www.cnblogs.com/kanite/p/5156836.html
Copyright © 2011-2022 走看看