最近发现我那简单得不再简单的IOCP+UDP的底层出错了,在大数据量的时候经常会报错,并且清一色都是报的:报0xC000000005,读取0x00000010错误.报错之后,整个程序的堆栈就全部破坏掉了.从发现问题到今日问题的解决,已经过去了一个月的时间.
唯一能够找到相关的资料只有:http://www.cppblog.com/HendricLee/archive/2008/07/29/57436.html
但是事实上,我的Overlapped都是复用的.因此,不大可能是此问题导致的.经过测试证明,也确实与此无关.
昨晚上又做了一系列的测试,结果到最后依旧是无果,百般无奈之下,只好问人,后面QQ好友Sagasarate告诉了我原委,我知道之后,只有两种感觉:想哭,想撞墙.
至于为什么,请看以下代码便知了.非常非常之低级的错误.
bool CUDPRecvSendThread::postRecvRequest(CUdpOverLappedRecv* pOverLappedRecv)
{
ASSERT(pOverLappedRecv);
if (pOverLappedRecv == NULL) return false;
pOverLappedRecv->Reset();
DWORD dwBytesRecv = 0;
DWORD dwFlags = 0;
int nSenderAddrSize = sizeof (sockaddr_in);
int rc = 0;
rc = ::WSARecvFrom(m_ServerSocket, pOverLappedRecv->GetWsaBuffer(), 1, &dwBytesRecv, &dwFlags,
pOverLappedRecv->GetClientAddr(), &nSenderAddrSize,
pOverLappedRecv->GetOverlapped(), NULL);
if (rc == SOCKET_ERROR)
{
DWORD dwErrorCode = ::WSAGetLastError();
if (dwErrorCode != WSA_IO_PENDING)
{
return false;
}
}
return true;
}
请对照着MSDN看.
如果没看出来,那我来告诉你是为什么.
问题就在于WSARecvFrom的7个参数.
MSDN的描述:
lpFromlen [in, out]
A pointer to the size, in bytes, of the "from" buffer required only if lpFrom is specified.
你会发现,这个参数是一个输入输出值.而WSARecvFrom投递的是一个异步的IOCP请求,故而,出了此方法(CUDPRecvSendThread::postRecvRequest)之后,nSenderAddrSize这个临时变量就会被回收.不出事才怪了.
好吧,这事就是我干出来的.今年竟是做一些脑残的事情.肿么了我这是.T_T
要解决这个问题,最好的办法就是把nSenderAddrSize作为CUdpOverLappedRecv的成员变量保存,这样生命周期可以得以保证.
好吧,这件脑残事就这么结了.