Как можно надежно обнаружить отключенный TCP-сокет с помощью MsgWaitForMultipleObjects? - PullRequest
6 голосов
/ 29 сентября 2011

Витая включает в себя реактор, реализованный поверх MsgWaitForMultipleObjects. Очевидно, у реактора есть проблемы с надежным обращением внимания, когда заканчивается TCP-соединение, по крайней мере, в случае, когда одноранговый узел отправляет несколько байтов, а затем быстро закрывает соединение. Кажется, что происходит:

  1. Реактор вызывает MsgWaitForMultipleObjects с некоторыми ручками розеток и QS_ALLINPUT.
  2. Вызов завершается и указывает дескриптор сокета в этом состоянии (то есть имеет байты, ожидающие чтения и был закрыт одноранговым узлом), активен.
  3. Реактор отправляет это уведомление в общую реализацию TCP.
  4. Реализация TCP считывает доступные байты из сокета. Некоторые из них доставляются в код приложения.
  5. Управление возвращается в реактор, который в конечном итоге снова вызывает MsgWaitForMultipleObjects.
  6. MsgWaitForMultipleObjects больше никогда не означает, что ручка активна. Реализация TCP никогда не сможет снова взглянуть на сокет, поэтому она никогда не сможет обнаружить, что соединение закрыто.

Это создает впечатление, что MsgWaitForMultipleObjects - механизм уведомления, инициируемый ребром. Документация MSDN гласит:

Waits until one or all of the specified objects are in the signaled state
or the time-out interval elapses.

Это не похоже на запуск по краям. Звучит как срабатывание уровня.

Действительно ли MsgWaitForMultipleObjects вызвано фронтом? Или это вызвано уровнем, и это неправильное поведение вызвано каким-то другим аспектом его поведения?

Добавление Документы MSDN для WSAEventSelect объясняют, что здесь происходит, в том числе указывают, что FD_CLOSE в основном одноразовое событие. После того, как он дал сигнал один раз, вы никогда его не получите. Это объясняет, почему у Twisted такая проблема. Мне все еще интересно услышать, как эффективно использовать MsgWaitForMultipleObjects с учетом этого ограничения.

1 Ответ

1 голос
/ 29 сентября 2011

Чтобы использовать WSAEventSelect и дифференцировать действия, вам необходимо позвонить WSAEnumNetworkEvents.Убедитесь, что вы обрабатываете каждое событие, о котором было сообщено, а не только первое.

WSAAsyncSelect облегчает определение причины и часто используется вместе с MsgWaitForMultipleObjects.

Таким образом, вы могли бы использовать WSAAsyncSelect вместо WSAEventSelect.

Кроме того, я думаю, что у вас есть фундаментальное неправильное понимание разницы между триггерным и триггерным уровнями.Похоже, ваши рассуждения больше связаны с автоматическим сбросом, чем с событиями ручного сброса.

...