0

完了ポート用の小さなテストサーバーをコーディングしようとしています。しかし、AcceptEx を呼び出そうとすると... winsock エラー コードとして常に WSAEINVAL が返されます... 何が間違いだったのかわかりません

http://codepad.org/NEXG3Ssh <- コードパッドのコード

StartWinsock();
 cout << "Winsock initiated\n";
 //Get the number of processors
 DWORD ulProcessors = GetNumberOfProcessors();
 cout << "Number of Processors/Threads, that will be used: " << ulProcessors << endl;
 //Create an completion port
 hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, ulProcessors);
 if(hCompletionPort == NULL)
  ErrorAbort("Could not create completion port");
 cout << "Completion Port created\n";

 //Create threads
 CreateThreads(ulProcessors);
 cout << "Threads created\n";

 //Create socket
 AcceptorSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 addrinfo *final, hints;
 memset(&hints, 0, sizeof(hints));
 hints.ai_family = AF_INET;
 hints.ai_flags = AI_PASSIVE;
 if(getaddrinfo(NULL,"12345", &hints, &final))
  ErrorAbort("Could not retrieve address information");
 if(bind(AcceptorSock,final->ai_addr, final->ai_addrlen))
  ErrorAbort("Could not bind socket");
 freeaddrinfo(final);
 cout << "Acceptor socket created and bound\nStarting to listen on the acceptor socket\n";
 if(listen(AcceptorSock, 2))
  ErrorAbort("Can´t listen on the socket");

 //Add acceptor socket file handle to be observed by the completion port
 if(CreateIoCompletionPort((HANDLE)AcceptorSock, hCompletionPort, NEW_CONNECTION, 0) != hCompletionPort)
  ErrorAbort("A new completion port has been created instead of using the existing one");
 cout << "Acceptor socket associated with the completion port\n";

 ResumeThreads(2);
 char lpOutputBuf[1024];
 int outBufLen = 1024;
 DWORD dwBytes;
 OVERLAPPED over;
 SOCKET newSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


 while(true)
 {
  memset(&over, 0, sizeof(over));
  if(AcceptEx(AcceptorSock, newSock, lpOutputBuf, outBufLen - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16, &dwBytes, &over) == FALSE)
  {
   int x = WSAGetLastError();
   if( x != WSA_IO_PENDING)
    ErrorAbort("Could not acceptex a new connection");
  }
 }
4

2 に答える 2

2

コードの問題は次のとおりです。

while(true)
{
  memset(&over, 0, sizeof(over));
  if(AcceptEx(AcceptorSock, newSock, lpOutputBuf, outBufLen - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16, &dwBytes, &over) == FALSE)
  {
    int x = WSAGetLastError();
    if( x != WSA_IO_PENDING)
    ErrorAbort("Could not acceptex a new connection");
  }
}

AcceptEx関数の2番目のパラメーター(この場合はnewSock)は、接続されていないバインドされていないソケットである必要があります。新しい接続が到着すると、newSockパラメーターは無効なパラメーターになります(現在接続されているため)。これを回避するには、新しいソケットハンドルが必要です。作成されますが、ループは新しい接続が到着するまで待機する必要があります。これを行うには、WSAEVENTを使用する必要があります。最初の関数WSAEventSelectを使用して、FD_ACCEPTネットワークイベントをWSAEVENTに関連付ける必要があります。これは、AcceptThreadを作成する前に実行する必要があります。

g_ev = WSACreateEvent();
if (WSA_INVALID_EVENT == g_ev)
  ErrorAbort("Error occurred while WSACreateEvent()";
if (SOCKET_ERROR == WSAEventSelect(AcceptorSock, g_ev, FD_ACCEPT))
{
  WSACloseEvent(g_ev);
  ErrorAbort("Error occurred while WSAEventSelect().");
}

次に、AcceptThreadはAcceptEx関数を呼び出し、新しい接続を待ちます。新しい接続が到着すると、newSockが完了ポートに追加され、新しいソケットが作成されます。このスレッドには、接続を受け入れるために必要な要素のみが含まれます。

DWORD WINAPI AcceptThread(LPVOID lParam)
{
  SOCKET AcceptorSock = (SOCKET)lParam, new;
  SOCKET newSock; 
  OVERLAPPED over;    
  DWORD wr;

  memset(&over, 0, sizeof(over));
  do
  {
    newSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(AcceptEx(AcceptorSock, newSock, lpOutputBuf, outBufLen - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16, &dwBytes, &over) == FALSE)
    {
      int x = WSAGetLastError();
      if (x != ERROR_IO_PENDING)
      {
        cout << "Could not acceptex a new connection" << endl;
        return 1;
      }
      else
      {
        if (WSA_WAIT_TIMEOUT != (wr = WSAWaitForMultipleEvents(1,  &g_ev, FALSE, INFINITE, FALSE)))
        {
          WSAEnumNetworkEvents(AcceptorSock, g_ev, &WSAEvents);
          if ((WSAEvents.lNetworkEvents & FD_ACCEPT) &&  (0 == WSAEvents.iErrorCode[FD_ACCEPT_BIT]))
          {
            if (CreateIoCompletionPort(newSock, hCompletionPort, 0, 0) == NULL)
            {
              cout << "Error CreateIoCompletionPort" << endl;
              return 2;
            }
            WSAResetEvent(g_ev);
          }
        }
      }
    }
  }while(wr != WSA_WAIT_EVENT_0);
}

いずれかの団体がより多くの情報を必要とする場合、このリンクが役立つ可能性があり ます:http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedscalableapp6b.html http://www.codeproject.com/KB/IP/SimpleIOCPApp.aspx http ://msdn。 microsoft.com/en-us/magazine/cc302334.aspx

于 2010-12-03T03:04:15.037 に答える
-1
SOCKET newSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

WSASocketではなく使用する必要があり、ソケットを作成するとき socketにフラグを渡す必要があります。WSA_FLAG_OVERLAPPED

于 2010-12-03T07:57:07.553 に答える