程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> MFC的CSocket的一個小Bug?

MFC的CSocket的一個小Bug?

編輯:.NET實例教程

今天寫的程序用到了MFC的CSocket類 。

首先在一個自己的線程中調用這個CSocket類對象的創建函數CSocket::Create(),這個線程用來執行ReSipRocate的協議棧。

然後當點擊程序窗口的菜單時,程序的主線程(UI線程)調用銷毀函數CSocket::Close()。當程序是Debug版本的時候,會報告一個斷言錯誤“Debug Assertion Failed. File: sockcore.cpp. Line: 544”。(我用的是VC.Net 2003。)

打開文件看到這個斷言錯誤發生在CSocket的積累CAsyncSocket的處理中。我來回的分析我的CSocket對象的各種操作,確認各個操作均沒有錯誤。好在能單步調試sockcore.cpp文件裡的函數。可以看到斷言的位置為(標為紅色字體):

void PASCAL CAsyncSocket::KillSocket(SOCKET hSocket, CAsyncSocket* pSocket)
{
 ASSERT(CAsyncSocket::LookupHandle(hSocket, FALSE) != NULL);

 _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;

 CAsyncSocket::DetachHandle(hSocket, FALSE);
 if (pState->m_hSocketWindow != NULL)
 {
  ::PostMessage(pState->m_hSocketWindow, WM_SOCKET_DEAD,
   (WPARAM)hSocket, 0L);
  CAsyncSocket::AttachHandle(hSocket, pSocket, TRUE);
 }
}

於是找到LookupHandle()的定義,如下:

CAsyncSocket* PASCAL CAsyncSocket::LookupHandle(SOCKET hSocket, BOOL bDead)
{
 CAsyncSocket* pSocket;
 _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;
 if (!bDead)
 {
  pSocket = (CAsyncSocket*)
   pState->m_pmapSocketHandle->GetValueAt((void*)hSocket);
  if (pSocket != NULL)
   return pSocket;
 }

。。。
 }

看出來問題出在pState->m_pmapSocketHandle->GetValueAt((void*)hSocket),在根據SOCKET hSocket查找對應的CAsyncSocket對象指針時失敗了。於是跟蹤m_pmapSocketHandle這個結構的所有操作的地方。在程序運行的全過程中,只看到將hSocket放入到m_pmapSocketHandle中的操作(pState->m_pmapSocketHandle->SetAt((void*)hSocket, pSocket))。沒有看到從m_pmapSocketHandle中移除hSocket的操作(pState->m_pmapSocketHandle->RemoveKey((void*)hSocket))。然而為什麼使用這個hSocket來查找的時候會失敗呢(pState->m_pmapSocketHandle->GetValueAt((void*)hSocket))?

開始分析的時候覺得是不是程序哪裡越界了,導致這個數據結構被破壞了?太可怕了,不願意相信,還是再看看有沒有別的可能。再看看 _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState這句語句。發現_afxSockThreadState不是一個全局變量,而是一個宏定義。展開來是:

#define _afxSockThreadState AfxGetModuleThreadState()


進一步跟進:

AFX_MODULE_THREAD_STATE* AFXAPI AfxGetModuleThreadState()
{
 return AfxGetModuleState

()->m_thread.GetData();
}

再往下就發現這個這個pState是線程相關的,不同的線程擁有各自不同的pState。當調用CSocket::Create()創建socket時,SIP協議棧線程把這個socket記錄到自己的pState->m_pmapSocketHandle中。等調用CSocket::Close()關閉這個socket時,UI線程在關閉前先去自己的pState->m_pmapSocketHandle中查找這個socket。(當然查不到),所以斷言失敗。

不知道這是一個Bug還是故意這麼設計的。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved