GetQueuedCompletionStatus блокирует навсегда

#sockets #io-completion-ports

#сокеты #завершение ввода-вывода-порты

Вопрос:

Я пишу серверное приложение и хочу использовать порты IOCompletion, поэтому я написал прототип для сервера, но я столкнулся с проблемой GetQueuedCompletionStatus, которую он никогда не возвращает (блокирует). Ниже приведен мой код:

 bool CreateSocketOverlappedServer()
{
  WSADATA wsaData;
  SOCKADDR_IN sockaddr;

  if(WSAStartup(MAKEWORD(2,2,),amp;wsaData)){
    _tprintf(_T("Unable to start upn"));
    return false;
  }

  SrvSocket = WSASocket(AF_INET,SOCK_STREAM,0,NULL,NULL,WSA_FLAG_OVERLAPPED);
  if(SrvSocket==INVALID_SOCKET){
    _tprintf(_T("Unable to start socketn"));
    return false;
  }

  sockaddr.sin_family = AF_INET;
  sockaddr.sin_port = htons(10000);
  sockaddr.sin_addr.s_addr = INADDR_ANY;

  /* now bind the socket */
  if(bind(SrvSocket, (SOCKADDR *)amp;sockaddr, sizeof(SOCKADDR_IN))==SOCKET_ERROR){
    _tprintf(_T("Unable to bind socketn"));
    return false;
  }

  if(listen(SrvSocket, 5)==SOCKET_ERROR){
    _tprintf(_T("Error listeningn"));
    return false;
  }

  return true;
}
  


 void WorkerThread(void *arg)
{
   bool bret= false;
   DWORD dwTransferedBytes=0;
   CLIENTS *client;
   PPER_IO_OPERATION_DATA data;

   /* Just sleep for now */
   while(true){
     _tprintf(_T("Entering whilen"));
     bret = GetQueuedCompletionStatus(hIocp,amp;dwTransferedBytes,(PULONG_PTR)amp;client,(LPOVERLAPPED *) amp;data,INFINITE);
     if(!bret){
       _tprintf(_T("Unable to process completion portn"));
     }
   }
   //Sleep(10000); 
}
  

 void AcceptClientConnections(void *arg)
{
  SOCKET ClientSocket;
  CLIENTS *c;

  _tprintf(_T("Start accepting client connectionsn"));


  while(true){  
    ClientSocket = accept(SrvSocket, NULL,NULL);

    if(ClientSocket==INVALID_SOCKET){
      _tprintf(_T("Unable to accept connectionn"));
      continue;
    }

    /* do an association with completion port */
    c = (CLIENTS *)malloc(sizeof(CLIENTS));
    c->sock = ClientSocket;

    /* associate with completion port */
    if(!CreateIoCompletionPort((HANDLE)ClientSocket, hIocp,  (ULONG_PTR)c,0)){
      _tprintf(_T("Unable to associate with completion portn: %d"),GetLastError());

    }

  }
}
  

Есть идеи?
заранее спасибо.

Ответ №1:

Вы неправильно используете порт завершения, поэтому ему нечего делать, и, следовательно, нет статуса для отчета. Использование порта завершения с сокетами - это двухэтапный процесс, но вы выполняете только половину шагов.

Прочитайте следующую статью MSDN для получения подробной информации:

Сокеты Windows 2.0: запись масштабируемых приложений Winsock с использованием портов завершения

Комментарии:

1. Возможно, вы также захотите взглянуть на мою бесплатную клиент-серверную платформу IOCP, которая показывает несколько более продвинутое использование IOCP, чем образец MSDN, и, надеюсь, ее немного легче повторно использовать в вашем прототипе: serverframework.com/products---the-free-framework.html

2. Реми, пожалуйста, поясни это, я создаю порт Iocompletion, например: hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,0,0,), затем связываю каждый принятый сокет с этим портом завершения, в моем пуле потоков вызывается GetQueuedCompletionStatus, но я сталкиваюсь с тем, что он никогда не возвращается, я имею в видуон блокируется навсегда, я подключаюсь к серверу через telnet и отправляю любую строку, но GetQueuedCompletionStatus блокирует. есть предложения?

3. Вы не показали начальный CreateIoCompletionPort() вызов в опубликованном вами коде и не показали никакого кода, который использует сокеты после их подключения. Например, вы вызываете WSARecv() со WSAOVERLAPPED структурой, чтобы начать чтение из принятого сокета через перекрывающийся ввод-вывод? Вам нужно это сделать, чтобы инициировать GetQueuedCompletionStatus() входящие данные.

4. Извините, потому что я не показываю вызов CreateIoCompletionPort, но вызов WSARecv выполняется после GetQueuedCompletionStatus, верно?

5. Нет, вы должны вызвать WSARecv() after accept() возвращает новый дескриптор сокета для клиента. GetQueuedCompletionStatus() невозможно сообщить о состоянии для чего-то, что еще не было поставлено в очередь. Вы ставите в очередь перекрывающееся чтение с WSARecv() , затем GetQueuedCompletionStatus() сообщает, когда чтение фактически получает некоторые данные от клиента, затем вы отправляете другое WSARecv() в очередь другой операции чтения и так далее. То же самое с отправкой данных. Ставьте в очередь операцию отправки с WSASend() помощью, затем GetQueuedCompletionStatus() сообщает, когда отправка завершена.

Ответ №2:

Одна из возможностей: проверьте, связали ли вы сокет прослушивателя с портом завершения (сам допустил эту ошибку). Если вы этого не сделаете, функция GetQueuedCompletionStatus() заблокирует навсегда.