GetQueuedCompletionStatus отложен

Я написал сложную библиотеку для управления сетевой связью на основе механизма iocp. Проблема в том, что когда сервер закрывает соединение, вызывая метод API closesocket(), эта информация иногда передается клиенту с задержкой на секунды или даже минуты. Мой код для обнаружения закрытия соединения выглядит так (упрощенно):

ok = GetQueuedCompletionStatus(completion_port, &io_size, (PULONG_PTR)&context, &overlapped, 40);

if (!ok) {
   // something went broken
  DWORD err = GetLastError();
  if (err == ERROR_CONNECTION_REFUSED) {
         // connection failed
  } else if (err == ERROR_SEM_TIMEOUT) {
        // connection timeout
  } else if (err == ERROR_NETNAME_DELETED) {
        // connection closure - point of interest
  } else if (err != WAIT_TIMEOUT) {
        // unknown error
  }
} else {
    // process incomming or outgoing data
}

Почему это происходит? Мне нужно знать о закрытии соединения немедленно, чтобы иметь возможность подключиться к серверу резервного копирования (не так сильно загружен - из-за этого происходит отключение).


person truthseeker    schedule 29.04.2011    source источник
comment
Не имеет прямого отношения к вашему вопросу, но вы должны проверять значение перекрытия, а также код возврата в своем обработчике. Когда перекрывается == NULL, это означает, что GetQueuedCompletionStatus не удалось, когда перекрывается != NULL, это означает, что запрос ввода-вывода не выполнен.   -  person Aaron Klotz    schedule 30.04.2011


Ответы (2)


Как вы закрываете соединение?

Если вы просто вызываете closesocket(), то вы инициируете последовательность выключения, которая попытается гарантировать, что все данные, которые в настоящее время ожидают, достигнут места назначения. Это может занять некоторое время, особенно если сетевое соединение было перегружено, дейтаграммы потеряны и происходит повторная передача TCP.

Если вы хотите сразу же закрыть соединение и потерять все ожидающие данные, установите для задержки значение 0, а затем закройте сокет. Это выдаст RST для соединения, и вы получите это намного быстрее.

person Len Holgate    schedule 29.04.2011

Я пытался поэкспериментировать с параметром linger, как писал Лен, но это не помогло. Мне помогло добавление вызова функции shutdown() непосредственно перед closesocket(). После анализа пакетов, достигающих сетевого интерфейса на клиенте (с помощью WireShark), я обнаружил, что пакет RST был заменен пакетом FIN. Любопытно, что пакет RST не задерживался. Таким образом, операционная система знала, что соединение было закрыто, но по какой-то неизвестной причине эта информация была передана на прикладной уровень с большой задержкой. Я измерил задержки от 10 секунд до 4 минут.

person truthseeker    schedule 01.05.2011