室内设计网站,静态网页框架用什么软件做,东莞产品网站建设,书签制作 小学生 一等奖CControlSocket类的分析#xff0c;CControlSocket类的内容比较多#xff0c;为什么呢。因为通信控制命令的传输全部在这里#xff0c;通信协议的多样也导致了协议解析的多样。 1、OnReceive 其大致说明#xff1a;本函数由框架调用#xff0c;通知套接字缓冲中有数据CControlSocket类的内容比较多为什么呢。因为通信控制命令的传输全部在这里通信协议的多样也导致了协议解析的多样。 1、OnReceive 其大致说明本函数由框架调用通知套接字缓冲中有数据可以调用Receive函数取出。 1 void CControlSocket::OnReceive(int nErrorCode) 2 {3 try4 {5 TCHAR buff[BUFFER_SIZE1];6 7 int nRead Receive(buff, BUFFER_SIZE);8 switch (nRead)9 {
10 case 0:
11 Close();
12 break;
13
14 case SOCKET_ERROR:
15 if (GetLastError() ! WSAEWOULDBLOCK)
16 {
17 TCHAR szError[256];
18 wsprintf(szError, OnReceive error: %d, GetLastError());
19 AfxMessageBox (szError);
20 }
21 break;
22
23 default:
24 if ((m_RxBuffer.GetLength() nRead) BUFFER_OVERFLOW)
25 {
26 ((CClientThread *)m_pThread)-PostStatusMessage(Buffer overflow: DOS attack?);
27
28 // buffer overflow (DOS attack ?)
29 AfxGetThread()-PostThreadMessage(WM_QUIT,0,0);
30 }
31 else
32 if (nRead ! SOCKET_ERROR nRead ! 0)
33 {
34 // terminate the string
35 buff[nRead] 0;
36 m_RxBuffer CString(buff);
37
38 GetCommandLine();
39 }
40 break;
41 }
42 }
43 catch(...)
44 {
45 // something bad happened... (DOS attack?)
46 ((CClientThread *)m_pThread)-PostStatusMessage(Exception occurred in CSocket::OnReceive()!);
47 // close the connection.
48 AfxGetThread()-PostThreadMessage(WM_QUIT,0,0);
49 }
50 CSocket::OnReceive(nErrorCode);
51 } 这个函数就是读控制命令套接字及相应的错误处理。接收到的数据保存在了m_RxBuffer中。接下来GetCommandLine函数解析接收到的数据。 2、GetCommandLine函数 解析命令数据 1 void CControlSocket::GetCommandLine()2 {3 CString strTemp;4 int nIndex;5 6 while(!m_RxBuffer.IsEmpty()) //有接收到的数据待处理7 {8 nIndex m_RxBuffer.Find(\r\n); //找一条完整的命令的结束符9 if (nIndex ! -1)
10 {
11 strTemp m_RxBuffer.Left(nIndex); //将这条命令提取出来
12 m_RxBuffer m_RxBuffer.Mid(nIndex 2); //更新m_RxBuffer 去掉已经提取出来的命令
13 if (!strTemp.IsEmpty())
14 {
15 m_strCommands.AddTail(strTemp); //可能while循环中提取出多条命令这里增加一个队列
16 // parse and execute command
17 ProcessCommand(); //去处理这些命令,如果直接处理命令的话就没有上面m_strCommandsz这个队列缓冲了
18 }
19 }
20 else
21 break;
22 }
23 } 该有的解释已经在上面了。CString::Mid的函数与我记忆中的可能有些差别特意查询下。CString CString ::Mid(int nFirst) const 返回值返回一个包含指定范围字符的拷贝的CString对象。nFirst 此CString对象中的要被提取的子串的第一个字符的从零开始的索引。 4、ProcessCmd 解释这些命令这个函数比较长值得学习的也有很多。 1 void CControlSocket::ProcessCommand()2 {3 CString strCommand, strArgs;4 5 // get command6 CString strBuff m_strCommands.RemoveHead(); //得到第一条待解析的命令7 int nIndex strBuff.Find( ); //查找空格8 if (nIndex -1)9 {10 strCommand strBuff; 11 }12 else13 {14 strCommand strBuff.Left(nIndex); //这几行代码就是去掉命令语句里开始的空格如果有15 strArgs strBuff.Mid(nIndex1); //并将命令关键字和参数分离开来16 }17 strCommand.MakeUpper(); //命令关键字全部转大写18 19 // log command20 ((CClientThread *)m_pThread)-PostStatusMessage(strCommand strArgs); //在界面上打印收到的命令及参数21 22 if ((m_nStatus STATUS_LOGIN) (strCommand ! USER strCommand ! PASS)) //这句话后面应该有错23 { //应该是strArgs ! PASS24 SendResponse(530 Please login with USER and PASS.);25 return;26 }27 28 // specify username29 if (strCommand USER) //是USER命令 30 {31 // only accept anonymous account32 if (strArgs.CompareNoCase(AfxGetApp()-GetProfileString(Settings, userName, sunrise)) 0)33 {34 SendResponse(331 User name ok, need password.);35 m_strUserName strArgs; //保存登陆上来的用户名36 }37 else38 SendResponse(530 Not logged in. No such account.);39 }40 else41 // specify password42 if (strCommand PASS) //是PASS命令43 {44 if (m_strUserName.IsEmpty()) //要先USER命令45 {46 SendResponse(503 Login with USER first.);47 return;48 }49 50 //密码是meng51 if (strArgs.CompareNoCase(AfxGetApp()-GetProfileString(Settings, password, meng)) ! 0)52 {53 SendResponse(503 password is wrong.);54 return;55 }56 // login client57 m_strHomeDir ((CServerDlg *)AfxGetApp()-m_pMainWnd)-m_strHomeDirectory; //设置主目录58 m_strCurrentDir m_strHomeDir; //设置当前目录59 60 SendResponse(230 User logged in.); //回复登陆成功61 m_nStatus STATUS_IDLE; //修改状态62 }63 else64 // close connection65 if (strCommand QUIT) //QUIT命令66 {67 // send goodbye message to client68 SendResponse(220 Goodbye.);69 70 Close();71 72 // tell our thread we have been closed73 AfxGetThread()-PostThreadMessage(WM_QUIT,0,0);74 }75 else76 // change transfer type77 if (strCommand TYPE) 78 {79 SendResponse(200 Type set to %s., strArgs);80 }81 else82 // print current directory83 if ((strCommand PWD) || (strCommand XPWD))84 {85 CString strRelativePath;86 GetRelativePath(m_strCurrentDir, strRelativePath); //获取当前目录87 SendResponse(257 \%s\ is current directory., strRelativePath);88 }89 else90 // change working directory91 if (strCommand CWD)92 {93 DoChangeDirectory(strArgs); //更改路径94 }95 else96 // change to parent directory 97 if (strCommand CDUP)98 {99 DoChangeDirectory(..);
100 }
101 else
102 // specify IP and port (PORT a1,a2,a3,a4,p1,p2) - IP address a1.a2.a3.a4, port p1*256p2.
103 if (strCommand PORT) //在这里指定端口
104 {
105 CString strSub;
106 int nCount0;
107
108 while (AfxExtractSubString(strSub, strArgs, nCount, ,)) //这里又提取了参数这个命令是在干嘛
109 {
110 switch(nCount)
111 {
112 case 1: // a1
113 m_strRemoteHost strSub;
114 m_strRemoteHost .;
115 break;
116 case 2: // a2
117 m_strRemoteHost strSub;
118 m_strRemoteHost .;
119 break;
120 case 3: // a3
121 m_strRemoteHost strSub;
122 m_strRemoteHost .;
123 break;
124 case 4: // a4
125 m_strRemoteHost strSub;
126 break;
127 case 5: // p1
128 m_nRemotePort 256*atoi(strSub);
129 break;
130 case 6: // p2
131 m_nRemotePort atoi(strSub);
132 break;
133 }
134 }
135 SendResponse(200 Port command successful.);
136 }
137 else
138 // list current directory (or a specified file/directory)
139 if ((strCommand LIST) ||
140 (strCommand NLST))
141 {
142 StripParameters(strArgs);
143
144 CString strResult;
145 if (!GetDirectoryList(strArgs, strResult))
146 {
147 return;
148 }
149
150 SendResponse(150 Opening ASCII mode data connection for directory list.);
151
152 // create data connection with client
153 if (CreateDataConnection()) //在这里就创建了数据套接字连接了
154 {
155 if (strResult.IsEmpty())
156 {
157 // close data connection with client
158 DestroyDataConnection();
159
160 SendResponse(226 Transfer complete.);
161 m_nStatus STATUS_IDLE;
162 return;
163 }
164 }
165 else
166 {
167 // close data connection with client
168 DestroyDataConnection(); //不成功则销毁
169 return;
170 }
171
172 m_nStatus STATUS_LIST; //
173
174 m_pDataSocket-AsyncSelect();
175
176 // send the listing
177 m_pDataSocket-SendData(strResult);
178 }
179 else
180 // retrieve file
181 if (strCommand RETR)
182 {
183 if (((CServerDlg *)AfxGetApp()-m_pMainWnd)-m_bAllowDownload)
184 {
185 DoRetrieveFile(strArgs);
186 }
187 else
188 {
189 SendResponse(550 Permission denied.);
190 }
191 }
192 else
193 // client wants to upload file
194 if (strCommand STOR)
195 {
196 if (((CServerDlg *)AfxGetApp()-m_pMainWnd)-m_bAllowUpload)
197 {
198 DoStoreFile(strArgs);
199 }
200 else
201 {
202 SendResponse(550 Permission denied.);
203 }
204 }
205 else
206 // delete file
207 if (strCommand DELE)
208 {
209 if (((CServerDlg *)AfxGetApp()-m_pMainWnd)-m_bAllowDelete)
210 {
211 DoDeleteFile(strArgs);
212 }
213 else
214 {
215 SendResponse(550 Permission denied.);
216 }
217 }
218 else
219 // remove directory
220 if ((strCommand RMD) || (strCommand XRMD))
221 {
222 if (((CServerDlg *)AfxGetApp()-m_pMainWnd)-m_bAllowDelete)
223 {
224 DoDeleteDirectory(strArgs);
225 }
226 else
227 {
228 SendResponse(550 Permission denied.);
229 }
230 }
231 else
232 // create directory
233 if ((strCommand MKD) || (strCommand XMKD))
234 {
235 if (((CServerDlg *)AfxGetApp()-m_pMainWnd)-m_bAllowCreateDirectory)
236 {
237 DoCreateDirectory(strArgs);
238 }
239 else
240 {
241 SendResponse(550 Permission denied.);
242 }
243 }
244 else
245 // rename file or directory (part 1)
246 if (strCommand RNFR)
247 {
248 if (((CServerDlg *)AfxGetApp()-m_pMainWnd)-m_bAllowRename)
249 {
250 DoRenameFrom(strArgs);
251 }
252 else
253 {
254 SendResponse(550 Permission denied.);
255 }
256 }
257 else
258 // rename file or directory (part 2)
259 if (strCommand RNTO)
260 {
261 if (((CServerDlg *)AfxGetApp()-m_pMainWnd)-m_bAllowRename)
262 {
263 DoRenameTo(strArgs);
264 }
265 else
266 {
267 SendResponse(550 Permission denied.);
268 }
269 }
270 else
271 // restart transfer from x
272 if (strCommand REST)
273 {
274 m_dwRestartOffset atol(strArgs);
275 SendResponse(350 Restarting at %d., m_dwRestartOffset);
276 }
277 else
278 // get file size
279 if (strCommand SIZE)
280 {
281 CString strLocalPath;
282 GetLocalPath(strArgs, strLocalPath);
283
284 // check if directory exists
285 if (!FileExists(strLocalPath, FALSE))
286 {
287 SendResponse(550 File not found.);
288 return;
289 }
290 CFileStatus status;
291 CFile::GetStatus(strLocalPath, status);
292 SendResponse(213 %d, status.m_size);
293 }
294 else
295 // switch to passive mode
296 if (strCommand PASV)
297 {
298 // delete existing datasocket
299 DestroyDataConnection();
300
301 // create new data socket
302 m_pDataSocket new CDataSocket(this);
303
304 if (!m_pDataSocket-Create(gFixedDataPort))
305 {
306 DestroyDataConnection();
307 SendResponse(421 Failed to create socket.);
308 return;
309 }
310 // start listening
311 m_pDataSocket-Listen();
312 m_pDataSocket-AsyncSelect();
313
314 CString strIP, strTmp;
315 UINT nPort;
316
317 // get our ip address
318 GetSockName(strIP, nPort);
319 // retrieve port
320 m_pDataSocket-GetSockName(strTmp, nPort);
321 // replace dots
322 strIP.Replace(., ,);
323 // tell the client which address/port to connect to
324 SendResponse(227 Entering Passive Mode (%s,%d,%d)., strIP, nPort/256, nPort%256);
325 m_bPassiveMode TRUE;
326 }
327 else
328 // abort transfer
329 if ((strCommand ABOR) || (strCommand.Right(4) ABOR))
330 {
331 if (m_pDataSocket)
332 {
333 if (m_nStatus ! STATUS_IDLE)
334 {
335 SendResponse(426 Data connection closed.);
336 }
337 // destroy data connection
338 m_pThread-PostThreadMessage(WM_DESTROYDATACONNECTION, 0 ,0);
339 }
340 SendResponse(226 ABOR command successful.);
341 }
342 else
343 // get system info
344 if (strCommand SYST)
345 {
346 SendResponse(215 UNIX emulated by Baby FTP Server.);
347 }
348 else
349 // dummy instruction
350 if (strCommand NOOP)
351 {
352 SendResponse(200 NOOP command successful.);
353 }
354 else
355 {
356 SendResponse(502 Command not implemented.);
357 }
358 } View Code 首先从命令行语句里拆分出命令关键字和参数。这里面的命令要是一个个列出来太长了。主要是要弄清楚FTP通信的流程也就是这些命令的内在逻辑等到具体开发某个功能的时候再一一弄清楚就可以了。 5、m_pDataSocket是CControlSocket中的成员变量指向的是数据传输socket。在什么地方创建了CDataSocket呢在LIST/NLIST命令中调用了 CreateDataConnection函数这里创建了CDataSocket。然后在PASV命令里也创建了CDataSocket。这其实就是文件数据传输时的两种模式前一种作为tcp客户端后一种作为tcp服务器。下面是CreateDataConnect函数 1 BOOL CControlSocket::CreateDataConnection()2 {3 if (!m_bPassiveMode)4 {5 m_pDataSocket new CDataSocket(this);6 if (m_pDataSocket-Create())7 {8 m_pDataSocket-AsyncSelect(FD_CONNECT | FD_CLOSE | FD_ACCEPT);9 // connect to remote site
10 if (m_pDataSocket-Connect(m_strRemoteHost, m_nRemotePort) 0)
11 {
12 if (GetLastError() ! WSAEWOULDBLOCK)
13 {
14 SendResponse(425 Cant open data connection.);
15 return FALSE;
16 }
17 }
18 }
19 else
20 {
21 SendResponse(421 Failed to create data connection socket.);
22 return FALSE;
23 }
24 }
25
26 // wait until were connected
27 DWORD dwTickCount GetTickCount() 5000;
28 while (!m_pDataSocket-m_bConnected)
29 {
30 DoEvents();
31 if (dwTickCount GetTickCount())
32 {
33 SendResponse(421 Failed to create data connection socket.);
34 return FALSE;
35 }
36 }
37 return TRUE;
38 } 数据传输socket已tcp客户端的形式连接服务器注意连接的端口和服务器ip。这两个参数都在参数PORT解析时被设置。 转载于:https://www.cnblogs.com/kanite/p/5153637.html