首页 > 技术文章 > VC FTP服务器程序分析(四)

kanite 2016-01-25 10:49 原文

  下面是数据传输的重点-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\n");
 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、

 

 

 

推荐阅读