还有些问题继续请教unsigned大哥!
我的工作线程中处理代码如下,但根据我的理解,红色标注的问题1处释放的应该是GetQueuedCompletionStatus()函数对应的那个有事件完成通知的socket的PerHandleData和PerIOData吧,这样的话下面就没法执行了,肯定是错误的,但是该如何才能得到对应的每一个已经accept到的socket对应的PerHandleData和PerIOData,以便我在close时将其对应的PerHandleData和PerIOData也释放呢?
请赐教!多谢!
while(1)
{
time_t NowTime = time(0); GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED*)&PerIOData, INFINITE); CurSock = PerHandleData->Socket;
pthis->m_NELinkPool.GetSocketInfo(CurSock, &CurSockInfo); if ((NowTime > CheckLinkTime) && (NowTime - CheckLinkTime) > 30)
{
// 检查所有socket是否超时。如果超时,关闭socket. 并同步NE连接池和信息表
for (bool b=pthis->m_NELinkPool.MoveBegin(&CurSockInfo); b; b=pthis->m_NELinkPool.MoveNext(&CurSockInfo))
{
if (difftime(time(0), CurSockInfo.LastTime) > 1200)
{
SOCKET tempsock = CurSockInfo.Socket;
closesocket(tempsock);
pthis->m_NELinkPool.DeleteSocket(tempsock);
pthis->m_BeapTable.DeleteSocket(tempsock);
pthis->DoNESocketTimeoutEvent(tempsock); GlobalFree(PerHandleData); // 问题1
GlobalFree(PerIOData); // 问题2
} int result = send(CurSockInfo.Socket, "keep_alive_msg", strlen("keep_alive_msg"), 0);
} CheckLinkTime = NowTime;
} // 首先检查套接字上是否发生错误,如果发生了则关闭套接字并清楚同套接字相关的SOCKET_INFORATION结构体
if (BytesTransferred == 0 && (PerIOData->OperationType == RECV_POSTED || PerIOData->OperationType == SEND_POSTED))
{
printf("Closing Socket %d, code = %d\n", PerHandleData->Socket, WSAGetLastError());
closesocket(PerHandleData->Socket);
pthis->m_NELinkPool.DeleteSocket(PerHandleData->Socket);
pthis->m_BeapTable.DeleteSocket(PerHandleData->Socket); GlobalFree(PerHandleData);
GlobalFree(PerIOData); continue;
} // 接收到数据时
if (PerIOData->OperationType == RECV_POSTED)
{
actlen = BytesTransferred;
memset(buf, 0, sizeof(buf));
strncpy(buf, PerIOData->Buffer, actlen);
pthis->m_NELinkPool.SetCurTime(CurSock, time(NULL));
pthis->DoNERecvDataEvent(CurSock, CurSockInfo.ip, buf, actlen); // 获取完整包
proxy = NO_PROXY;
string pack = "";
BEAP_FACTORY factoryVer = UNKNOWN;
for (bool b=pthis->m_NELinkPool.GetFirstPacket(CurSock, buf, actlen, pack, &proxy, &factoryVer);
b;
b=pthis->m_NELinkPool.GetNextPacket(CurSock, pack, &proxy, &factoryVer))
{
// 注意:curSockInfo中laststr少了刚刚接收的信息, 如果以下要使用laststr字段,需修改代码
pthis->DealNEEvent(pack.c_str(), static_cast<int>(pack.size()), proxy, CurSockInfo, factoryVer);
}
} Flags = 0;
ZeroMemory(&(PerIOData->OVerlapped), sizeof(OVERLAPPED)); PerIOData->DATABuf.buf = PerIOData->Buffer;
PerIOData->DATABuf.len = DATA_BUFSIZE; if (WSARecv(PerHandleData->Socket, &(PerIOData->DATABuf), 1, &RecvBytes, &Flags, &(PerIOData->OVerlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError()); closesocket(PerHandleData->Socket);
pthis->m_NELinkPool.DeleteSocket(PerHandleData->Socket);
pthis->m_BeapTable.DeleteSocket(PerHandleData->Socket);
GlobalFree(PerHandleData);
GlobalFree(PerIOData);
}
}
}
我的工作线程中处理代码如下,但根据我的理解,红色标注的问题1处释放的应该是GetQueuedCompletionStatus()函数对应的那个有事件完成通知的socket的PerHandleData和PerIOData吧,这样的话下面就没法执行了,肯定是错误的,但是该如何才能得到对应的每一个已经accept到的socket对应的PerHandleData和PerIOData,以便我在close时将其对应的PerHandleData和PerIOData也释放呢?
请赐教!多谢!
while(1)
{
time_t NowTime = time(0); GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED*)&PerIOData, INFINITE); CurSock = PerHandleData->Socket;
pthis->m_NELinkPool.GetSocketInfo(CurSock, &CurSockInfo); if ((NowTime > CheckLinkTime) && (NowTime - CheckLinkTime) > 30)
{
// 检查所有socket是否超时。如果超时,关闭socket. 并同步NE连接池和信息表
for (bool b=pthis->m_NELinkPool.MoveBegin(&CurSockInfo); b; b=pthis->m_NELinkPool.MoveNext(&CurSockInfo))
{
if (difftime(time(0), CurSockInfo.LastTime) > 1200)
{
SOCKET tempsock = CurSockInfo.Socket;
closesocket(tempsock);
pthis->m_NELinkPool.DeleteSocket(tempsock);
pthis->m_BeapTable.DeleteSocket(tempsock);
pthis->DoNESocketTimeoutEvent(tempsock); GlobalFree(PerHandleData); // 问题1
GlobalFree(PerIOData); // 问题2
} int result = send(CurSockInfo.Socket, "keep_alive_msg", strlen("keep_alive_msg"), 0);
} CheckLinkTime = NowTime;
} // 首先检查套接字上是否发生错误,如果发生了则关闭套接字并清楚同套接字相关的SOCKET_INFORATION结构体
if (BytesTransferred == 0 && (PerIOData->OperationType == RECV_POSTED || PerIOData->OperationType == SEND_POSTED))
{
printf("Closing Socket %d, code = %d\n", PerHandleData->Socket, WSAGetLastError());
closesocket(PerHandleData->Socket);
pthis->m_NELinkPool.DeleteSocket(PerHandleData->Socket);
pthis->m_BeapTable.DeleteSocket(PerHandleData->Socket); GlobalFree(PerHandleData);
GlobalFree(PerIOData); continue;
} // 接收到数据时
if (PerIOData->OperationType == RECV_POSTED)
{
actlen = BytesTransferred;
memset(buf, 0, sizeof(buf));
strncpy(buf, PerIOData->Buffer, actlen);
pthis->m_NELinkPool.SetCurTime(CurSock, time(NULL));
pthis->DoNERecvDataEvent(CurSock, CurSockInfo.ip, buf, actlen); // 获取完整包
proxy = NO_PROXY;
string pack = "";
BEAP_FACTORY factoryVer = UNKNOWN;
for (bool b=pthis->m_NELinkPool.GetFirstPacket(CurSock, buf, actlen, pack, &proxy, &factoryVer);
b;
b=pthis->m_NELinkPool.GetNextPacket(CurSock, pack, &proxy, &factoryVer))
{
// 注意:curSockInfo中laststr少了刚刚接收的信息, 如果以下要使用laststr字段,需修改代码
pthis->DealNEEvent(pack.c_str(), static_cast<int>(pack.size()), proxy, CurSockInfo, factoryVer);
}
} Flags = 0;
ZeroMemory(&(PerIOData->OVerlapped), sizeof(OVERLAPPED)); PerIOData->DATABuf.buf = PerIOData->Buffer;
PerIOData->DATABuf.len = DATA_BUFSIZE; if (WSARecv(PerHandleData->Socket, &(PerIOData->DATABuf), 1, &RecvBytes, &Flags, &(PerIOData->OVerlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError()); closesocket(PerHandleData->Socket);
pthis->m_NELinkPool.DeleteSocket(PerHandleData->Socket);
pthis->m_BeapTable.DeleteSocket(PerHandleData->Socket);
GlobalFree(PerHandleData);
GlobalFree(PerIOData);
}
}
}
{
// 检查所有socket是否超时。如果超时,关闭socket. 并同步NE连接池和信息表
for (bool b=pthis->m_NELinkPool.MoveBegin(&CurSockInfo); b; b=pthis->m_NELinkPool.MoveNext(&CurSockInfo))
{
if (difftime(time(0), CurSockInfo.LastTime) > 1200)
{
SOCKET tempsock = CurSockInfo.Socket;
closesocket(tempsock);
pthis->m_NELinkPool.DeleteSocket(tempsock);
pthis->m_BeapTable.DeleteSocket(tempsock);
pthis->DoNESocketTimeoutEvent(tempsock); GlobalFree(PerHandleData); // 问题1
GlobalFree(PerIOData); // 问题2
} int result = send(CurSockInfo.Socket, "keep_alive_msg", strlen("keep_alive_msg"), 0);
} CheckLinkTime = NowTime;
}这段检查代码请放到定时器当中,所有的删除操作都不要做,只需要调用closesocket。如果需要发送数据,请在CloseSocket之前发送。
对于超时检查的部分流程大致是:
定时器(Unit_PurifierTimer.cpp,多媒体定时器,所以只有一个定时器事件处理函数PurifierTimerProc)
到达一定时间,触发回收事件SetEvent回收线程函数体(Unit_PurifierThread.cpp)在此之前等待两个事件,一个是程序退出事件,另一个则是上面的提到的回收事件
1.退出事件触发,结束线程
2.回收事件触发,进行回收操作,判断有符合条件的则调用DumpConnection(Unit_Connections.cpp),置入回收站,并设置回收时间。接着对回收站当中的连接进行清理,收回之后过一段时间,则清除。象这种逻辑实际上是为了方便使得不会在多个线程当中对同一个内存块进行重复释放。任何时间里面,只要判断到需要收回连接,则置入回收站(除非本来就在回收站),过一段时间自动由定时线程进行回收。
但是现在用了完成端口实现,完成端口每次accept一个socket后都会为其GlobalAlloc两个对应的空间,PerIOData和PerHandleData,问题就是我在上述判断连接超时时如果仅调用closesocket的话就没有将socket对应的PerIOData和PerHandleData释放,肯定要造成内存泄露的吧。可是如果要释放的话我又该怎么才能将需要关闭的socket对应的PerIOData和PerHandleData释放掉呢?unsigned大哥的定时器回收做的很好,不过我想通过一种简单的办法实现,不知道有没有可行的方法呢?需要我每次accept一个socket后分配PerIOData和PerHandleData时将分配的地址保存起来吗?
有点晕了
有点晕了
==========
保存socket就行了,定时器只须closesocket
int ilenght = sizeof(iSeconds);
for (list<IOBuffer*>::iterator iter = pThis->IOAceeptList.begin();
iter != pThis->IOAceeptList.end(); iter ++)
{
if ((*iter)!= NULL)
{
::getsockopt((*iter)->m_Socket, SOL_SOCKET, SO_CONNECT_TIME, (char *)&iSeconds, &ilenght);
if (iSeconds != -1 && iSeconds > 120)
{
//非正常连接,关闭连接,并将SOCKET从ACCEPT队列中删除
if ( (*iter)->m_Socket != INVALID_SOCKET )
{
closesocket((*iter)->m_Socket);
(*iter)->m_Socket = INVALID_SOCKET;
}你搞一个接收链表,在接收线程中不停止的getsockopt就可以,接收超时你可以直接关闭SOCKET, 你投递的ACCEPT会在GetQueuedCompletionStatus中响应,在这里可以回收你投递的ACCEPT的内存.
那为每个socket分配的PerIOData和PerHandleData系统会自动释放吗?还是通过别的方法来处理呢?
,,,GetQueuedCompletionStatus和GetQueuedCompletionStatus之间,要尽量缩短时间
,,,一般这个地方,只处理判断操作(连接,接收,发送,错误),处理部分,一般都是剥离到另外的线程中做2,你放在这里,超时判断并不准确,如果没有IO操作完成,你不会执行到超时判断这一步代码
,,,如果在1200s内没有IO操作完成,你的程序就表现出bug了3,从socket 可以反取到该socket所在的PerHandleData和PerIOData