在我的套接字服务器中,我使用WSAEventSelect()和WSAEnumNetworkEvents()来检测FD_ACCEPT和FD_CLOSE事件。
以下是我的代码的简化版本:
HANDLE sockEv=CreateEvent(NULL,TRUE,FALSE,NULL);
WSAEventSelect(servSocket,sockEv,FD_ACCEPT|FD_CLOSE);
for(;;) {
if(WSAWaitForMultipleEvents(1,&sockEv,FALSE,INFINITE,FALSE)==WSA_WAIT_EVENT_0) {
WSANETWORKEVENTS wsaEvents={0};
WSAEnumNetworkEvents(servSocket,sockEv,&wsaEvents);
if((wsaEvents.lNetworkEvents & FD_ACCEPT)==FD_ACCEPT) {
SOCKET clntSock=accept(servSocket,(sockaddr*)clientAddr,&addrlen);
....
}
else if (wsaEvents.lNetworkEvents==0) {
// this event occurs after each FD_ACCEPT event
}
....
}
....
}
问题是每次从客户端接受新连接时,我都会收到2个事件:首先将WSANETWORKEVENTS.lNetworkEvents设置为FD_ACCEP,然后将WSANETWORKEVENTS.lNetworkEvents设置为零。也就是说,每次接受新客户端时,for(;;)循环执行2次。或者在检测到FD_ACCEPT后,WSAEnumNetworkEvents可能没有重置sockEv。
这个零事件是什么意思以及它为什么会发生? 我在文档中没有找到任何相关内容。
更新:可编辑的样本
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2),&wsaData);
try {
SOCKET servSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
sockaddr_in serv={0};
serv.sin_family=AF_INET;
serv.sin_addr.s_addr=htonl(INADDR_ANY);
serv.sin_port=htons(18081);
memset(serv.sin_zero,0,sizeof(serv.sin_zero));
if(bind(servSocket,(sockaddr*)&serv,sizeof(serv))==SOCKET_ERROR)
throw WSAGetLastError();
if(listen(servSocket,SOMAXCONN)==SOCKET_ERROR)
throw WSAGetLastError();
HANDLE sockEv=CreateEvent(NULL,TRUE,FALSE,NULL);
if(WSAEventSelect(servSocket,sockEv,FD_ACCEPT|FD_CLOSE)==SOCKET_ERROR)
throw WSAGetLastError();
for(;;) {
if(WSAWaitForMultipleEvents(1,&sockEv,FALSE,INFINITE,FALSE)!=WSA_WAIT_EVENT_0)
throw -1;
WSANETWORKEVENTS wsaEvents={0};
if(WSAEnumNetworkEvents(servSocket,sockEv,&wsaEvents)==SOCKET_ERROR)
throw WSAGetLastError();
if((wsaEvents.lNetworkEvents & FD_ACCEPT)==FD_ACCEPT) {
SOCKET clntSocket=accept(servSocket,0,0);
closesocket(clntSocket);
puts("accept");
}
else if(wsaEvents.lNetworkEvents==0) {
puts("zero event");
}
}
}
catch(int errorCode) {
printf("Last Error: %d\n",errorCode);
}
WSACleanup();
return 0;
}
我在WinXP 32bit上试过这段代码。
答案 0 :(得分:2)
回答我自己的问题。我似乎发现了为什么以及何时发生这种情况。在客户端套接字(由accept()返回的套接字)关闭后发生此零事件。如果您不将WS_CLOSE与WSAEventSelect一起使用,则不会发生这种情况。所以人们可以忽略它。 MSDN对此行为一无所知。