局域网聊天系统__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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章