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;
}

...全文
182 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和数据库操作分开,加个缓冲类

18,356

社区成员

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

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