WinSocket Send 内存泄漏疑问

jingxs1202 2012-12-23 12:55:50
问题是这样的,我封装了socket和ODBC(大量借鉴了前辈的成果,表示感谢),单独使用都没有问题,但如果把数据集发送到客户端时,经过大约20次(与socket缓冲区大小有关)后,数据库就不能正常工作了。请教高人指点。
(全部代码贴不下,感兴趣的请给邮箱地址,只贴出关键函数)
Socket:

int CJXSSocket::Receive(char *recvbuff, int nBuffLen, int nFlag/*=0*/, int nTimeOut/*=0*/)
{
int nRecvCount=0;
if (nBuffLen<=0)
{
m_strError.Format(_T("接收缓冲区太小。"));
return nRecvCount;
}
if (!m_bConnected)
{
m_strError.Format(_T("尚未连接服务器。"));
return nRecvCount;
}
//准备超时判定
struct timeval timeout;
timeout.tv_sec=nTimeOut/1000;
timeout.tv_usec=nTimeOut%1000;
m_bTimeOut=FALSE;
fd_set fdRead;
FD_ZERO(&fdRead);
SOCKET sktSelect=m_socket;
FD_SET(sktSelect, &fdRead);
fd_set fdError=fdRead;
//setsockopt(m_socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(timeout));
int nSelectRet=0;
if (nTimeOut==0)
nSelectRet=select(sktSelect+1,&fdRead, 0, &fdError, NULL);
else
nSelectRet=select(sktSelect+1,&fdRead, 0, &fdError, &timeout);
switch(nSelectRet)
{
case 0:
m_bDataTooOld=TRUE;
m_bTimeOut=TRUE;
m_strError.Format(_T("接收数据超时,错误代码是:%d"), WSAGetLastError());
break;
case -1:
m_strError.Format(_T("接收数据失败,错误代码是:%d"), WSAGetLastError());
break;
default:
if(FD_ISSET(sktSelect,&fdRead))
{
nRecvCount=recv(m_socket, recvbuff, nBuffLen, nFlag);
//if (nRecvCount==0||nRecvCount == SOCKET_ERROR) //发送端关闭连接,或接收错误
// OnClose(WSAGetLastError());
if (nRecvCount==0) //发送端关闭连接
OnClose(WSAGetLastError());
else if (nRecvCount == SOCKET_ERROR) //接收错误
{
ULONG lErrorCode=WSAGetLastError();
if (lErrorCode>=WSAENETDOWN && lErrorCode<=WSAESHUTDOWN)
OnClose(lErrorCode);
//else if(lErrorCode==EAGAIN) //接收超时
//{
// m_bDataTooOld=TRUE;
// m_bTimeOut=TRUE;
// m_strError.Format(_T("接收数据超时,错误代码是:%d"), lErrorCode);
//}
else
m_strError.Format(_T("接收数据失败,错误代码是:%d"), lErrorCode);

//printf("Error code:%d\n", lErrorCode);
}
//上次接收操作超时,本次丢弃上次未做接收处理的数据
else
{
if (m_bDataTooOld)
{
m_bDataTooOld=FALSE;
//超时自动丢弃上次应该接收的数据
//Receive(recvbuff, nBuffLen, nFlag, nTimeOut);
}
}
}
else
m_strError.Format(_T("未知接收状态,错误码是:%d"), WSAGetLastError());
if (FD_ISSET(sktSelect,&fdError))
{
printf("Error this socket");
}
}
//printf("Receive count %d\n", nRecvCount);
return nRecvCount;
}
BOOL CJXSSocket::ReceiveOneFrame(char *pframe, int nFrameLen, int nFlag/*=0*/, int nTimeOut/*=0*/)
{
int nRecvCount=0;
int nRecv=0;
//char *pBuff;//=(char *)pframe;
char *pBuff=(char *)pframe;
//pBuff=new char[nFrameLen+1];
//memset(pBuff, 0, sizeof(char)*(nFrameLen+1));
while(nRecvCount<nFrameLen)
{
nRecv=Receive(pBuff+nRecvCount, nFrameLen-nRecvCount, nFlag, nTimeOut);
if (nRecv>0)
{
nRecvCount+=nRecv;
//pBuff+=nRecv;
if (nRecvCount>=nFrameLen)
break;
}
else
return FALSE;
}
//memcpy(pframe, pBuff, sizeof(char)*nFrameLen);
//delete []pBuff;
return TRUE;
}
int CJXSSocket::Send(char *sendbuff, int nBuffLen, int nFlag/*=0*/, int nTimeOut/*=0*/)
{
int nSend=0;
if (nBuffLen<=0)
{
m_strError.Format(_T("没有要发送的数据。"));
return nSend;
}
if (!m_bConnected)
{
m_strError.Format(_T("尚未连接服务器。"));
return nSend;
}
//准备超时判定
struct timeval timeout;
timeout.tv_sec=nTimeOut/1000;
timeout.tv_usec=nTimeOut%1000;
fd_set fdWrite;
FD_ZERO(&fdWrite);
SOCKET sktSelect=m_socket;
FD_SET(sktSelect, &fdWrite);
fd_set fdError=fdWrite;

//setsockopt(m_socket,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(timeout));
int nSelectRet=0;
if (nTimeOut==0)
nSelectRet=select(sktSelect+1, 0, &fdWrite, &fdError, NULL);
else
nSelectRet=select(sktSelect+1, 0, &fdWrite, &fdError, &timeout);
switch(nSelectRet)
{
case 0:
m_bDataTooOld=TRUE;
m_bTimeOut=TRUE;
m_strError.Format(_T("发送数据超时,错误代码是:%d"), WSAGetLastError());
break;
case -1:
m_strError.Format(_T("发送数据失败,错误代码是:%d"), WSAGetLastError());
break;
default:
if(FD_ISSET(sktSelect,&fdWrite))
{
nSend=send(m_socket, sendbuff, nBuffLen, nFlag);
m_bTimeOut=FALSE;
if (nSend==SOCKET_ERROR) //发送异常
{
ULONG lErrorCode=WSAGetLastError();
if (lErrorCode==EAGAIN)
{
m_bTimeOut=TRUE;
m_strError.Format(_T("发送数据超时,错误代码是:%d"), lErrorCode);
}
else
{
m_strError.Format(_T("数据发送失败,错误码是:%d"), lErrorCode);
if (lErrorCode!=WSAEINPROGRESS && lErrorCode!=WSAEWOULDBLOCK)
OnClose(lErrorCode);
}
}
else if (nSend==0)
OnClose(WSAGetLastError()); //接收端已关闭连接
}
if(FD_ISSET(sktSelect,&fdError))
{
m_strError.Format(_T("数据发送失败,错误码是:%d"), WSAGetLastError());
printf("OOB comming...\n");
}
}
//else
//{
// printf("%d", WSAGetLastError());
//}
return nSend;
}
BOOL CJXSSocket::SendOneFrame(char *pframe, int nFrameLen, int nFlag/*=0*/, int nTimeOut/*=0*/)
{
if (nFrameLen<=0)
return FALSE;
int nSendCount=0;
int nSend=0;
BOOL bRet=TRUE;
//char *pBuff;//=(char *)pframe;
char *pBuff=(char *)pframe;
//pBuff=new char[nFrameLen+1];//(char *)malloc(sizeof(char)*(nFrameLen+1));
////pDel=pBuff;
//memset(pBuff, 0, sizeof(char)*(nFrameLen+1));
//memcpy(pBuff, pframe, sizeof(char)*nFrameLen);

while(nSendCount<nFrameLen)
{
//WSASend(
nSend=Send(pBuff+nSendCount, nFrameLen-nSendCount, nFlag);
if(nSend>0)
{
nSendCount+=nSend;
//pBuff+=nSend;
if (nSendCount>=nFrameLen)
break;
}
else
bRet = FALSE;
}
//delete []pBuff;
return bRet;
}

ODBC


SQLRETURN CJXSSQLDirect::ExecuteSQL(LPCTSTR srtCommand)
{
//SetBusy();
BOOL bRet=TRUE;
SQLRETURN nRet=SQL_ERROR;
if (m_hStmt!=INVALID_HANDLE_VALUE && m_hStmt!=NULL)
TRYODBC(m_hStmt, SQL_HANDLE_STMT, nRet=SQLFreeStmt(m_hStmt,SQL_CLOSE));
if (bRet)
TRYODBC(m_hDBC, SQL_HANDLE_DBC, SQLAllocHandle(SQL_HANDLE_STMT, m_hDBC, &m_hStmt));
if (bRet)
TRYODBC(m_hStmt, SQL_HANDLE_STMT, SQLSetStmtAttr(m_hStmt, SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY, SQL_IS_INTEGER));
if (bRet)
TRYODBC(m_hStmt, SQL_HANDLE_STMT, SQLSetStmtAttr(m_hStmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_READ_ONLY, SQL_IS_INTEGER));
if (bRet)
TRYODBC(m_hStmt, SQL_HANDLE_STMT, SQLSetStmtAttr(m_hStmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)1, SQL_IS_INTEGER));
if (bRet)
TRYODBC(m_hStmt, SQL_HANDLE_STMT, nRet=SQLExecDirect(m_hStmt, (SQLCHAR *)srtCommand, SQL_NTS));
if (bRet)
bRet=InitCols(nRet);
return nRet;
}
SQLRETURN CJXSSQLDirect::Skip(void)
{
BOOL bRet=TRUE;
SQLRETURN nRet=SQL_NO_DATA;
if (m_hStmt==INVALID_HANDLE_VALUE ||!m_hStmt)
bRet=FALSE;
if (bRet)
TRYODBC(m_hStmt,SQL_HANDLE_STMT, nRet=SQLFetch(m_hStmt));
//InitCols(nRet);
if (bRet)
{
CJXSSQLColumn *pCol;
for (int idx=0; idx<m_arrCols.GetCount(); idx++)
{
if (!m_hStmt)
AfxMessageBox(_T("Skip 导致了句柄空"));
pCol=m_arrCols.GetAt(idx);
if (pCol->m_nIndex>=0)
{
TRYODBC(m_hStmt, SQL_HANDLE_STMT, SQLGetData(m_hStmt, pCol->m_nIndex, pCol->m_nDataType, pCol->m_pValue,pCol->m_nWidth, &pCol->m_nDataSize));
if (bRet)
{
if (pCol->m_nDataSize==SQL_NULL_DATA)
memset(pCol->m_pValue, 0, sizeof(SQLCHAR)*pCol->m_nWidth);
continue;
}
else
break;
}
}
}
return nRet;
}
void *CJXSSQLDirect::GetCol(int nIdx)
{
if (nIdx>=0 && nIdx<m_arrCols.GetCount())
return m_arrCols.GetAt(nIdx)->m_pValue;
return NULL;
}
void *CJXSSQLDirect::GetCol(LPCTSTR strColName)
{
for (int idx=0; idx<m_arrCols.GetCount(); idx++)
{
if (m_arrCols.GetAt(idx)->m_strName.Trim()==strColName)
return GetCol(idx);
}
return NULL;
}

...全文
247 8 打赏 收藏 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
jingxs1202 2012-12-24
  • 打赏
  • 举报
回复
观察各变量情况,发现m_hStmt=0,查找整个工程,没有将其置0的语句,很是奇怪!
jingxs1202 2012-12-24
  • 打赏
  • 举报
回复
单独测试ODBC结果:重复运行select name from spt_values,然后遍历结果集(2506条记录),到第98214次后,反馈:"[HY001] [Microsoft][ODBC SQL Server Driver]内存分配失败 (0)",请高手帮忙分析分析。
jingxs1202 2012-12-24
  • 打赏
  • 举报
回复
是的,我也估计是socket的问题,但说来也就那么简单地处理了下,确实看不出来问题在哪里。现在甚至连检查的思路都没有了。
UDX协议 2012-12-24
  • 打赏
  • 举报
回复
我估计是SOCKET的问题,一般ODBC这些玩意,出错率低
jingxs1202 2012-12-24
  • 打赏
  • 举报
回复
我又测试了一下,ODBC在1.7万次的时候会出问题。
jingxs1202 2012-12-23
  • 打赏
  • 举报
回复
感谢你们的回答,这个问题困扰我2个星期了。2楼的缓冲类是什么意思?我在测试代码中,分别只用socket和只操作数据库,12万次均无任何问题,但只要把数据库内容发送到客户端就会在交换大约2万次后Send减速一半,在4万次以后就出现数据库不确定的故障(一会儿是句柄无效,一会儿是句柄不合法...)。很奇怪的是,偶尔有一次是完全正确的。
xumaojun 2012-12-23
  • 打赏
  • 举报
回复
楼主先定位一下是socket通信内存泄露还是数据库操作内存泄露。
ouyh12345 2012-12-23
  • 打赏
  • 举报
回复
socket和数据库操作分开,加个缓冲类
内容概要:本文介绍了基于Matlab代码实现的电力系统机组组合优化调度方法,适用于IEEE14、IEEE30和IEEE118节点标准测试系统。该资源聚焦于电力系统中发电机组的优化调度问题,通过智能优化算法实现对机组启停、出力分配等决策的最优化,旨在降低运行成本、提升系统可靠性和经济性。文中系统阐述了从数学模型构建、多类型约束处理到优化算法设计与仿真实验验证的完整研究流程,并提供了可复现的Matlab代码,涵盖目标函数设定、约束条件建模及算法求解过程,适用于电力系统调度、能源优化等相关领域的科研与教学实践。; 适合人群:具备电力系统分析、运筹学基础及Matlab编程能力的高校学生、科研人员和工程技术人员,尤其适合从事电力系统优化、智能算法应用研究的研究生与青年学者。; 使用场景及目标:①用于电力系统机组组合(UC)问题的教学实验与课程设计;②支撑科研工作中对遗传算法、粒子群算法等智能优化算法在电力系统调度中应用的研究;③为含可再生能源接入的现代电网调度提供仿真平台与技术参考,助力低碳电力系统规划与运行。; 阅读建议:建议读者结合电力系统调度理论与优化建模知识,深入理解机组组合问题的数学本质与物理约束,再通过Matlab代码进行仿真实践,重点关注算法收敛性、多目标权衡策略与不同测试系统间的性能对比,以实现理论与实践的深度融合。
内容概要:本文研究了一种基于TCN-BiGRU-Attention混合神经网络模型的风电功率预测方法,旨在提升预测精度。该模型融合了时间卷积网络(TCN)对局部时序特征的强大提取能力、双向门控循环单元(BiGRU)对时间序列前后依赖关系的双向捕捉能力,以及注意力(Attention)机制对关键时间步特征的自适应加权聚焦能力。研究采用多变量输入方式,综合纳入风速、风向、温度等多种气象因素作为输入特征,实现风电功率的单步预测。通过对实际风电场数据的实验验证,该模型在预测精度方面相较于单一模型或其他组合模型展现出显著优势,有效降低了预测误差。; 适合人群:具备一定机器学习与深度学习基础,从事新能源预测、电力系统调度或相关领域研究的科研人员与工程技术人员。; 使用场景及目标:①应用于风电场功率实时预测,提升电网调度的稳定性与安全性;②为电力市场交易、储能配置和可再生能源消纳提供高精度数据支持;③作为深度学习模型融合设计的参考案例,推动时序预测技术的发展。; 阅读建议:此资源提供了完整的Matlab代码实现,读者在学习时应重点关注模型结构的设计原理、多变量特征的处理方式以及Attention机制的融入方法,建议结合代码进行复现实验,调整参数以深入理解各组件对最终预测性能的影响。
内容概要:本文聚焦于非线性值迭代自适应动态规划(ADP)算法的研究,通过复现Matlab代码深入探讨离散时间非线性系统的策略迭代方法。文章系统阐述了ADP算法的核心原理,重点分析了其在处理非线性系统时的优势与挑战,并详细展示了值迭代与策略迭代在优化控制策略中的具体实现过程。研究强调了通过迭代优化实现系统性能最大化的方法论,同时提供了完整的代码与文档资源,便于读者进行深入学习与实践。; 适合人群:具备一定编程基础,尤其是对Matlab有初步了解的研发人员,以及从事控制理论、自动化、人工智能等领域的研究人员和研究生。; 使用场景及目标:① 为控制理论与自动化领域的研究者提供非线性系统控制策略设计与实现的实用案例;② 为学生和初学者提供学习与理解自适应动态规划算法及其在非线性系统中应用的实践机会;③ 推动相关领域的学术交流与技术进步,激发更多研究者投身于非线性控制系统的研究与优化。; 阅读建议:此资源兼具理论深度与实践指导。建议读者在学习过程中紧密结合理论知识与代码操作,动手实现算法,并通过调整参数或应用场景来深化理解。同时,可参考提供的参考资料,进一步探索自适应动态规划领域的最新研究进展。

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧