In my socket server I use WSAEventSelect() and WSAEnumNetworkEvents() to detect FD_ACCEPT and FD_CLOSE events.
Here is the simplified version of my code:
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
}
....
}
....
}
The problem is that each time a new connection is accepted from a client, I receive 2 events: first with WSANETWORKEVENTS.lNetworkEvents set to FD_ACCEP, then with WSANETWORKEVENTS.lNetworkEvents set to zero. That is the for(;;) loop is executed 2 times each time a new client is accepted. Or maybe the sockEv is not reset by WSAEnumNetworkEvents after detecting FD_ACCEPT.
What does this zero event mean and why it happens?
I didn’t find anything about it in the documentation.
UPDATE: Compilable sample
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;
}
I tried this code on WinXP 32bit.
Answering my own question. It seems I found why and when this happens. This zero event occurs after the client socket (the socket returned by accept()) is closed. It won’t happen if you don’t use FD_CLOSE with WSAEventSelect. So one can just ignore it.
MSDN says nothing about this behavior.