VC FTP服务器程序分析(二)
上面讲到了CClientThread类,打开这个类的实现,这个类实现了4个函数。依次分析:
1、InitInstance 其说明如下:InitInstance必须被重载以初始化每个用户界面线程的新实例。统称,你重载InitInstance函数来执行当线程首次被创建时必须完成的任务。此成员函数仅在用户界面线程中使用。
1 BOOL CClientThread::InitInstance() 2 { 3 // Attach the socket handle to a CSocket object. 4 // This makes sure that the socket notifications are sent to this thread. 5 m_ControlSocket.Attach(m_hSocket); 6 m_ControlSocket.m_pThread = this; 7 8 // send welcome message to client 9 m_ControlSocket.SendResponse("220 欢迎使用CC的FTP 服务器!!!"); 10 11 UINT nPort; 12 m_ControlSocket.GetPeerName(m_strPeerName, nPort); 13 14 // dynamically allocate memory for IP address (receiver will delete it!) 15 int nLength = m_strPeerName.GetLength(); 16 LPSTR lpszPeerName = new char[nLength+1]; 17 lstrcpy(lpszPeerName, m_strPeerName); 18 19 // Post a message to the main thread so that it can update the number of open connections 20 ::PostMessage(m_hWndOwner, WM_THREADSTART, (WPARAM)lpszPeerName, (LPARAM)m_nThreadID); 21 return TRUE; 22 }
第5行,m_ControlSocket类关联了m_hSocket句柄,m_hSocket是在创建线程对象之后传递进来的。m_ControlSocket是与客户端通信使用的控制命令套接字。第9行,调用了m_ControlSocket的成员函数SendResponse。这里涉及到CControlSocket类,这个类下篇分析再讲。这里就是给客户端回复了一个信息,信息里面为什么是220,这里就是具体的通信协议了,后面再讲。
第11至20,就是将客户端信息显示在主窗口上面了。
2、ExitInstance 其说明如下:框架通过很少被重载的Run成员函数调用此函数以退出线程的这个实例;或者当调用InitInstance失败时,调用此函数。除了在Run成员函数内之外,不得在任何地方调用此成员函数。此成员函数仅被用户界面线程使用。当m_bAutoDelete为真时,此函数的缺省实现删除CWinThread对象。如果你希望当线程终止时执行额外的清除工作,请重载此函数。当你的程序代码被执行之后,你的ExitInstance实现应调用基类的ExitInstance函数。
1 int CClientThread::ExitInstance() 2 { 3 // delete this thread from the linked list 4 CServerDlg *pWnd = (CServerDlg *)AfxGetApp()->m_pMainWnd; 5 if (pWnd != NULL) 6 { 7 pWnd->m_CriticalSection.Lock(); 8 POSITION pos = pWnd->m_ThreadList.Find(this); 9 if(pos != NULL) 10 { 11 pWnd->m_ThreadList.RemoveAt(pos); 12 } 13 pWnd->m_CriticalSection.Unlock(); 14 } 15 // dynamically allocate memory for IP address (receiver will delete it!) 16 int nLength = m_strPeerName.GetLength(); 17 LPSTR lpszPeerName = new char[nLength+1]; 18 lstrcpy(lpszPeerName, m_strPeerName); 19 20 // Post message to the main thread that this socket connection has closed 21 ::PostMessage(m_hWndOwner, WM_THREADCLOSE, (WPARAM)lpszPeerName, (LPARAM)m_nThreadID); 22 return CWinThread::ExitInstance(); 23 }
上面这个函数,第4至14行 删除了在界面类中保存的本线程对象指针。第16至21行,给界面发送了线程退出的消息。
3、PostStatusMessage函数,此函数就是在给主窗口发送消息。
1 void CClientThread::PostStatusMessage(LPCTSTR lpszStatus) 2 { 3 CString strData = lpszStatus; 4 5 int nLength = strData.GetLength(); 6 7 // dynamically allocate memory for status message (receiver will delete it!) 8 LPSTR lpszData = new char[nLength+1]; 9 lstrcpy(lpszData, strData); 10 ::PostMessage(m_hWndOwner, WM_ADDTRACELINE, (WPARAM)lpszData, (LPARAM)m_nThreadID); 11 }
WM_ADDTRACELINE从字面上看就是增加一条记录信息。
4、OnDestroyDataConnection 这是一个消息响应函数,也就是一个线程对象如果去接收并处理一个消息,这就是个很好的例子了。
1 BEGIN_MESSAGE_MAP(CClientThread, CWinThread) 2 //{{AFX_MSG_MAP(CClientThread) 3 // NOTE - the ClassWizard will add and remove mapping macros here. 4 //}}AFX_MSG_MAP 5 ON_THREAD_MESSAGE(WM_DESTROYDATACONNECTION, OnDestroyDataConnection) 6 END_MESSAGE_MAP() 7 8 9 void CClientThread::OnDestroyDataConnection(WPARAM wParam, LPARAM lParam) 10 { 11 m_ControlSocket.DestroyDataConnection(); 12 }
这里调用了CControlSocket类的成员函数DestroyDataConnection。下面就分析CConntrolSocket类的实现。