MFC寫的一個基于訊息的異步套節字通訊,出問題的代碼是在接收檔案的時候,發送方以while回圈的方式發送,接收方在OnSocket訊息中不停的接收,在接收第二個帶檔案內容的資料報發生了記憶體不足的情況,我通過寫日志的方式跟蹤到是New時不成功報出的錯誤,現在把代碼貼出來,并附上運行日志,請大家幫忙分析原因。
void CCallDlg::OnSock(WPARAM wParam,LPARAM lParam)
{
DWORD dwMaxNum = 0;
int curPackSize=0;//當前資料報大小
CString sExtra="",mQSerial="",mQueues="",mFilePath="",sCurLog="";
switch(LOWORD(lParam))
{
case FD_READ:
{
sCurLog="1. 檢查套節字暫存器可讀取的位元組數!\r\n";
OnWriteLog(sCurLog);
::ioctlsocket(mCallSocket,FIONREAD,&dwMaxNum);//
sCurLog.Format("2. 暫存器埠處發現%d個位元組的可讀資料,并開始申請堆記憶體空間!\r\n",dwMaxNum);
OnWriteLog(sCurLog);
char* pBuffer =NULL;
pBuffer=new char[dwMaxNum]; //定義一個緩沖區
if(!pBuffer)
{
sCurLog="2-1. 堆記憶體陣列pBuffer申請失敗!\r\n";
OnWriteLog(sCurLog);
}
char* m_pchBuffer=NULL;
memset(pBuffer,0,dwMaxNum);
sCurLog="3. 資料成功考備到堆記憶體陣列pBuffer中!\r\n";
OnWriteLog(sCurLog);
CPackage mPacMsg;
WSABUF wsabuf;
wsabuf.buf=pBuffer;
wsabuf.len=(unsigned long)dwMaxNum;
DWORD dwRead=0;
DWORD dwFlag=0;
SOCKADDR_IN addrFrom;//接收到來的地址資訊
int len=sizeof(SOCKADDR);
sCurLog="4. 開始從套節字埠讀取資料!\r\n";
OnWriteLog(sCurLog);
if(SOCKET_ERROR==WSARecvFrom(mCallSocket,&wsabuf,1,&dwRead,&dwFlag,
(SOCKADDR*)&addrFrom,&len,NULL,NULL))
{
// DWORD error=WSAGetLastError();
// WSASendError(error);
MessageBox("從服務器獲取資料失敗,請重啟或聯系相關部門解決!");
return;
}//先接收到資料,然后分類處理
//MessageBox("收到一個包!");
sCurLog.Format("5. 從套節字埠讀取資料!共讀取%d個位元組!\r\n",dwRead);
OnWriteLog(sCurLog);
memcpy(&mPacMsg,wsabuf.buf,sizeof(mPacMsg));//從pBuffer中起始位置考備sizeof(Msg)個位元組到&Msg地址中
curPackSize=mPacMsg.m_dwDatalen;//記錄該次資料報大小
sCurLog="6. 資訊包獲取完畢!\r\n";
OnWriteLog(sCurLog);
if(mPacMsg.m_nMsgType==MT_SENDDATA)
{
sCurLog="7. 開始獲取完整資料報!\r\n";
OnWriteLog(sCurLog);
m_pchBuffer = new char[mPacMsg.m_dwDatalen];
memset(m_pchBuffer,0,mPacMsg.m_dwDatalen);
memcpy(m_pchBuffer,wsabuf.buf,dwMaxNum);//dwMaxNum與dwDatalen大小應該一致
sCurLog="8. 資料報獲取完畢,并開始分析!\r\n";
OnWriteLog(sCurLog);
switch(mPacMsg.m_nSubType)
{
case ST_FILE://語音檔案
{
if (m_bFirst|| mPacMsg.m_nFlag==-1)//一個檔案的首次接收
{
m_bFirst=false;
mFilePath=".\\voice\\測驗.txt";
// mFilePath.Format(".\\voice\\%s.wav",CPublicData::mDeptName);
m_File.Open(mFilePath,CFile::modeCreate|CFile::modeReadWrite);
char* pchTmp = m_pchBuffer + sizeof(CPackage);
m_File.WriteHuge(pchTmp,curPackSize-sizeof(CPackage));
pchTmp = NULL;
if (mPacMsg.m_dwFileLen==curPackSize-sizeof(CPackage))
{
m_File.Close();
m_bFirst = TRUE;
}
}
else if (mPacMsg.m_nFlag==0) //檔案傳輸程序中
{
char* pTmp = m_pchBuffer + sizeof(CPackage);
m_File.WriteHuge(pTmp,curPackSize-sizeof(CPackage));
pTmp = NULL;
}
else if (mPacMsg.m_nFlag==1) //檔案傳輸結束
{
char* pTmp = m_pchBuffer + sizeof(CPackage);
m_File.WriteHuge(pTmp,curPackSize-sizeof(CPackage));
m_bFirst = TRUE;
m_File.Close();
pTmp = NULL;
}
}
break;
case ST_IMAGE://圖片檔案
{
}
break;
}
sCurLog="9. 釋放堆記憶體:pBuffer與m_pchBuffer!\r\n";
OnWriteLog(sCurLog);
delete []pBuffer;
pBuffer=NULL;
delete [] m_pchBuffer;
m_pchBuffer = NULL;
return;
}
else//MT_SENDDATA訊息應該被首先檢測,其它訊息中不需要用到pBuffer,最先判斷后,如果該資料報不是MT_SENDDATA訊息時,即可以及時釋放pBuffer堆記憶體
{
sCurLog="10. 釋放堆記憶體:pBuffer!\r\n";
OnWriteLog(sCurLog);
delete []pBuffer;
pBuffer=NULL;
}//EndIF
.
省略部份代碼
.
}
}
}
OnWriteLog(sCurLog);為寫運行日志函式,現在把運行日志貼出來
1. 檢查套節字暫存器可讀取的位元組數!
2. 暫存器埠處發現8192個位元組的可讀資料,并開始申請堆記憶體空間!
3. 資料成功考備到堆記憶體陣列pBuffer中!
4. 開始從套節字埠讀取資料!
5. 從套節字埠讀取資料!共讀取6280個位元組!
6. 資訊包獲取完畢!
7. 開始獲取完整資料報!
8. 資料報獲取完畢,并開始分析!
9. 釋放堆記憶體:pBuffer與m_pchBuffer!
1. 檢查套節字暫存器可讀取的位元組數!
2. 暫存器埠處發現6280個位元組的可讀資料,并開始申請堆記憶體空間!
從日志可以看出,接收第二個資料報時,在日志2處報“記憶體不足”崩潰了。從程式中看就是在pBuffer=new char[dwMaxNum]; //定義一個緩沖區,時沒有成功。
搞不明白,第一時執行時,我new 完有正常釋放的啊,為什么第二次接收再申請時就記憶體不足了呢?
uj5u.com熱心網友回復:
任務管理器看看記憶體增長情況, 程式中間有多個return 可能容易造成記憶體泄漏,推薦把緩沖區指標放到類中,方便管理, 一次申請 多次使用
uj5u.com熱心網友回復:
奇怪的是從任務管理器上看,記憶體并沒有增加什么,因為才接收第二個包就記憶體不足了。一次申請多次使用怕不行哦,因為我每次接收的資料報大小可能不一樣。
uj5u.com熱心網友回復:
看看new的時候dwMaxNum申請的記憶體到底有多大,是不是超過了uj5u.com熱心網友回復:
從最后一條日志
2. 暫存器埠處發現6280個位元組的可讀資料,并開始申請堆記憶體空間!
看,申請的空間為6280個位元組大小,也不算多啊。
uj5u.com熱心網友回復:
1. 現代的PC都有虛擬記憶體的技術,很少出現 記憶體不足 這種錯誤,即使偶爾出現,也是運行很長時間以后才會出現的。2. 檢查你的代碼,看一下是不是new和delete配對了,不配對肯定有記憶體泄露。至少我看到了WSARecvFrom讀取錯誤的部分代碼沒有delete。
uj5u.com熱心網友回復:
確實,這里是個失誤,不程序式問題應該不發生在該處,從日志看,WSARecvFrom一直沒有進入錯誤處理部分。
uj5u.com熱心網友回復:
是否存在越界操作的問題? 資料包是否完整有判斷嗎?memcpy(m_pchBuffer,wsabuf.buf,dwMaxNum); //很懷疑這一句 屏蔽掉看看
uj5u.com熱心網友回復:
把后續的對緩沖區的操作注釋掉試試。new 會拋出例外,不會回傳 NULL 指標的。
uj5u.com熱心網友回復:
從日志看,錯誤不發生在此處。就是在New處報錯的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/127721.html
標籤:基礎類
上一篇:opencv3.0------BackgroundSubtractorMOG的頭檔案
下一篇:機器人視覺
