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 完有正常释放的啊,为什么第二次接收再申请时就内存不足了呢?
9 个解决方案
#1
任务管理器看看内存增长情况, 程序中间有多个return 可能容易造成内存泄漏,
推荐把缓冲区指针放到类中,方便管理, 一次申请 多次使用
推荐把缓冲区指针放到类中,方便管理, 一次申请 多次使用
#2
奇怪的是从任务管理器上看,内存并没有增加什么,因为才接收第二个包就内存不足了。一次申请多次使用怕不行哦,因为我每次接收的数据报大小可能不一样。
#3
看看new的时候dwMaxNum申请的内存到底有多大,是不是超过了
#4
从最后一条日志
2. 寄存器端口处发现6280个字节的可读数据,并开始申请堆内存空间!
看,申请的空间为6280个字节大小,也不算多啊。
#5
1. 现代的PC都有虚拟内存的技术,很少出现 内存不足 这种错误,即使偶尔出现,也是运行很长时间以后才会出现的。
2. 检查你的代码,看一下是不是new和delete配对了,不配对肯定有内存泄露。至少我看到了WSARecvFrom读取错误的部分代码没有delete。
2. 检查你的代码,看一下是不是new和delete配对了,不配对肯定有内存泄露。至少我看到了WSARecvFrom读取错误的部分代码没有delete。
#6
确实,这里是个失误,不过程序问题应该不发生在该处,从日志看,WSARecvFrom一直没有进入错误处理部分。
#7
是否存在越界操作的问题? 数据包是否完整有判断吗?
memcpy(m_pchBuffer,wsabuf.buf,dwMaxNum); //很怀疑这一句 屏蔽掉看看
memcpy(m_pchBuffer,wsabuf.buf,dwMaxNum); //很怀疑这一句 屏蔽掉看看
#8
把后续的对缓冲区的操作注释掉试试。
new 会抛出异常,不会返回 NULL 指针的。
new 会抛出异常,不会返回 NULL 指针的。
#9
从日志看,错误不发生在此处。就是在New处报错的。
#1
任务管理器看看内存增长情况, 程序中间有多个return 可能容易造成内存泄漏,
推荐把缓冲区指针放到类中,方便管理, 一次申请 多次使用
推荐把缓冲区指针放到类中,方便管理, 一次申请 多次使用
#2
奇怪的是从任务管理器上看,内存并没有增加什么,因为才接收第二个包就内存不足了。一次申请多次使用怕不行哦,因为我每次接收的数据报大小可能不一样。
#3
看看new的时候dwMaxNum申请的内存到底有多大,是不是超过了
#4
从最后一条日志
2. 寄存器端口处发现6280个字节的可读数据,并开始申请堆内存空间!
看,申请的空间为6280个字节大小,也不算多啊。
#5
1. 现代的PC都有虚拟内存的技术,很少出现 内存不足 这种错误,即使偶尔出现,也是运行很长时间以后才会出现的。
2. 检查你的代码,看一下是不是new和delete配对了,不配对肯定有内存泄露。至少我看到了WSARecvFrom读取错误的部分代码没有delete。
2. 检查你的代码,看一下是不是new和delete配对了,不配对肯定有内存泄露。至少我看到了WSARecvFrom读取错误的部分代码没有delete。
#6
确实,这里是个失误,不过程序问题应该不发生在该处,从日志看,WSARecvFrom一直没有进入错误处理部分。
#7
是否存在越界操作的问题? 数据包是否完整有判断吗?
memcpy(m_pchBuffer,wsabuf.buf,dwMaxNum); //很怀疑这一句 屏蔽掉看看
memcpy(m_pchBuffer,wsabuf.buf,dwMaxNum); //很怀疑这一句 屏蔽掉看看
#8
把后续的对缓冲区的操作注释掉试试。
new 会抛出异常,不会返回 NULL 指针的。
new 会抛出异常,不会返回 NULL 指针的。
#9
从日志看,错误不发生在此处。就是在New处报错的。