局域網聊天系統__4.服務器調試篇

這裏主要遇到兩個錯誤,都是粗心吧
1.
    BOOL CServerDlg::VerifyUserAndUpdateUserList(CUserInfo& userInfo, CClientSocket *pClient)
     {
    
     POSITION pos = NULL;
     BOOL bNewUser = TRUE;

     for (pos = m_UserList.GetHeadPosition(); pos!=NULL;)     //遍歷鏈表
     {
          CUserInfo* pUserInfo = (CUserInfo*)m_UserList.GetNext(pos);
         
          if (pUserInfo->m_strName == userInfo.m_strName)                        //如果是已經註冊的用戶
           。。。。。
     
在紅色標記出報錯,剛開始一直以爲是m_UserList出了問題,糾結了好一會,然後發現在調試窗口中this指針和m_UserList中的內容都是非法的。
     
    這個時候就更迷茫了,一個成員函數內部this指針都是無效的,這又當從何說起額。其實當時還是有點犯渾,把成員函數的調用和成員變量的調用都當成是由this指向而使用的了。之後纔想起向上跟蹤,然後到了上一級函數CServerDlg::ProcessPendingReceive 再往上看,找到了CClientSocket::OnReceive 在該函數中,通過          m_pServerDlg->ProcessPendingReceive()。按理說,這裏的ProcessPendingReceive中的this指針就是m_pServerDlg。然後在調試窗口驗證果然:
     
     之後就簡單了 m_pServer的非法值是因爲我在服務器接受到一個新的連接時,創建客戶端套接字類時,忘了傳入服務器的this指針。而恰好CClientSocket有這樣一個默認構造函數,並且我沒有在裏面給m_pServer賦空(其實即使賦空函數仍然會調用,只是在使用成員時,能更精準地定位錯誤)。
     測試了一下這段代碼
#include <iostream>
class A
{
public:
     fun()
     {
          std::cout<<"Just For Fun"<<std::endl;
     }
};

int main()
{
     A *pA = NULL;
     pA->fun();
     return 0;
}
能夠進一步的確認c++類成員函數和普通函數的唯一區別就是隱藏一個this指針,成員函數通過this指針來操控對象數據,並且由於作用域的原因,該成員函數能夠操作類私有成員。除了作用域限制和this指針之外,成員函數和普通函數是一樣的。這也能解釋爲什麼成員函數並不佔用對象內存,因爲它們都放在類裏,它們屬於類,這裏的屬於類就是一種作用域限制,而對象想要調用該函數,比如 a.fun(); pA.fun() 都會轉換爲fun(&a)和fun(pA),然後像普通函數一樣調用成員函數。這個this指針唯一標識對象,因此函數不需要放在對象裏,所有的對象可以共享一份函數代碼。
     錯誤總結:主要是粗心,還有對指針不夠重視,如果當時在無參構造函數裏面將m_pServer賦爲NULL 即使當時粗心沒有傳入參數,也不會因爲this指針爲cdcdcd而浪費時間。當然將指針賦爲NULL的好處遠不在這裏,而在於對進一步的未知數據修改進行攔截,還有就是便於在其他函數中通過ASSERT很方便的判斷指針是否有效,只要你能夠確保無效的指針都被賦NULL了。那麼通過ASSERT(p != NULL)的p指針就基本不會有安全問題

錯誤二:
     這個錯誤也困擾了一些時間,主要之前沒有見過這一類型的錯誤,

在用戶下線時,出現這個錯誤。進行調試定位 到以下幾句
void RemoveChatter(pClient)
{
     ............
     //廣播更新後的列表
     SendUserListToAllChatter();

     //移除在線列表
     if((pos = m_ChatterList.Find(pClient)) != NULL)
          m_ChatterList.RemoveAt(pos);
     ..............
}

然後發現SendUserListToAllChatter裏面會報錯,就一股腦殺進去鼓搗了大半天,結果大敗而歸。由於不知道這個錯誤提示是什麼東東,連文件加載和保存都檢查過了。到最後才意識到:在RemoveChatter的調用處,也就是CClientSocket的OnClose處,有如下如語句:
     void CClientSocket::OnClose(int nErrorCode)
     {
          //停止發送
          ShutDown(1);
          //移除在線列表
          m_pServer->RemoveChatter(this);
          //刪除自身
          delete this;
     }
纔開始有點眉目,ShutDown函數的調用就表示該CClientSocket類不再發送數據了。而在RemoveChatter中,我是先發送後移除的,也就是說,發送的時候發送到了被移除的那個客戶端類那裏,而該類已經ShutDown()了  因此就出現了以上錯誤。而由於在SendUserListToAllChatter中的迭代只有某一次會出錯,也就沒有跟蹤到。
     改正方法只需要將上面兩句交換:
     //移除在線列表
     if((pos = m_ChatterList.Find(pClient)) != NULL)
          m_ChatterList.RemoveAt(pos);     

     //廣播更新後的列表
     SendUserListToAllChatter();


完整源代碼下載地址點擊這裏http://download.csdn.net/detail/wudaijun/4911762
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章