2

私のソケット サーバーでは、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 を検出した後、sockEv が WSAEnumNetworkEvents によってリセットされない可能性があります。

このゼロイベントは何を意味し、なぜそれが起こるのですか? ドキュメントでそれについて何も見つかりませんでした。

更新: コンパイル可能なサンプル

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 で試しました。

4

1 に答える 1

2

私自身の質問に答えます。なぜ、いつこれが起こるのかを見つけたようです。このゼロイベントは、クライアントソケット(accept()によって返されるソケット)が閉じられた後に発生します。WSAEventSelectでFD_CLOSEを使用しない場合は発生しません。したがって、それを無視することができます。MSDNは、この動作について何も述べていません。

于 2012-09-06T11:00:12.690 に答える