как получить FD_CLOSE в IOCP (GetQueuedCompletionStatus)?
От: valaar  
Дата: 30.03.11 03:34
Оценка:
Здравствуйте!

Пишу приложение на WSA и IOCP. Сокет связан с портом заверешния через CreateIoCompletionPort, поэтому все вызовы WSARecv/WSASend идут асинхронно, а в GetQueuedCompletionStatus() по OVERLAPPED.InternalHigh = 0 определяю, что клиент уже отвалился.

Вопрос 1: Насколько корректно определение отвалившегося клиента по OVERLAPPED.InternalHigh = 0 из GetQueuedCompletionStatus(), то есть возможна ли ситуация, когда мне придёт сообщение о нулевом приёме/отправке, а клиент всё ещё жив?

Если создать (WSACreateEvent) и привязать (WSAEventSelect) к конкретному сокету событие с FD_CLOSE, то с помощью WSAWaitForMultipleEvents() могу поймать факт отключения сокета. В MSDN есть пример отслеживания событий для нескольких сокетов, но там для каждого создаётся своё событие. Учитывая, что ждать можно не больше 64 одновременно, то подход с индивидуальными событиями не подходит. Можно событие привязать сразу к нескольким сокетам, но WSAEnumNetworkEvents() позволяет узнать подробности о событиях лишь конкретного сокета.

Вопрос 2: Можно ли при наличии события (WSAWaitForMultipleEvents()) определить список сокетов-инициаторов без полного перебора?
или с точки зрения IOCP
Вопрос 3: Можно ли заставить IOCP сообщить о разрыве соединения в GetQueuedCompletionStatus() (или иначе) без инициации WSARecv/WSASend?

То есть вопрос в определении факта разрыва связи. Очевидно, что WSA понимает, как это сделать и успешно генерирует событие FD_CLOSE, но как-то безымянно :(

Заранее благодарен за помощь!
Re: как получить FD_CLOSE в IOCP (GetQueuedCompletionStatus)
От: Gomes Россия http://irazin.ru
Дата: 30.03.11 05:20
Оценка: 2 (1) +1
Смотри по lpNumberOfBytes == 0. Вызовы WSARecv/WSASend должны быть. Ничего другого придумывать не надо.
Re[2]: как получить FD_CLOSE в IOCP (GetQueuedCompletionStat
От: valaar  
Дата: 30.03.11 07:36
Оценка:
G>Смотри по lpNumberOfBytes == 0.
Спасибо, действительно, этот параметр у меня есть и нет смысла в OVERLAPPED забираться.

С другой стороны, M$ уже выработали у меня неприязнь к этому параметру, поскольку в документации к WSARecv сказано:
lpNumberOfBytesRecvd [out]
A pointer to the number, in bytes, of data received by this call if the receive operation completes immediately.
Use NULL for this parameter if the lpOverlapped parameter is not NULL to avoid potentially erroneous results. This parameter can be NULL only if the lpOverlapped parameter is not NULL.

Но, если передать NULL, то в Output окне получу "Access violation writing to address 0x00000000", что для меня тоже достаточно erroneous results.
Такая вот документация+реализация :(

G>Вызовы WSARecv/WSASend должны быть. Ничего другого придумывать не надо.

Представьте себе comet сервер и десятки тысяч подключённых клиентов. Соединение должно висеть, а отправка/получение возникают по событиям, причём один из клиентов постоянно их цепляет, другой раз в пять минут, а третий может полдня ничего не получать. Если малоактивный клиент отваливается, то FD_CLOSE уже давно пришёл, но Completion Port (и я тоже) ещё ничего об этом не знаем, поэтому количество ресурсов (сокетов) постепенно уменьшаются. Предусматривать и гнать дополнительный (к TCP/IP) стеку трафик совсем не хочется.
В итоге, получается какая-то разорванная реализация winsock: есть два подхода, но ни один не включает другой :(
Re[3]: как получить FD_CLOSE в IOCP (GetQueuedCompletionStat
От: Gomes Россия http://irazin.ru
Дата: 30.03.11 08:04
Оценка:
Здравствуйте, valaar, Вы писали:

V>Но, если передать NULL, то в Output окне получу "Access violation writing to address 0x00000000", что для меня тоже достаточно erroneous results.


Честно, не помню, передавал когда-нибудь NULL или нет, а сейчас проверять лень.


V>Представьте себе comet сервер и десятки тысяч подключённых клиентов. Соединение должно висеть, а отправка/получение возникают по событиям, причём один из клиентов постоянно их цепляет, другой раз в пять минут, а третий может полдня ничего не получать.


Что мешает повесить всем WSARecv?
Re[3]: как получить FD_CLOSE в IOCP (GetQueuedCompletionStat
От: Аноним  
Дата: 30.03.11 08:05
Оценка:
Здравствуйте, valaar, Вы писали:

V>Представьте себе comet сервер и десятки тысяч подключённых клиентов. Соединение должно висеть, а отправка/получение возникают по событиям, причём один из клиентов постоянно их цепляет, другой раз в пять минут, а третий может полдня ничего не получать. Если малоактивный клиент отваливается, то FD_CLOSE уже давно пришёл, но Completion Port (и я тоже) ещё ничего об этом не знаем, поэтому количество ресурсов (сокетов) постепенно уменьшаются. Предусматривать и гнать дополнительный (к TCP/IP) стеку трафик совсем не хочется.


А если у того клиента, который очень долго (часы) не использует своё соединение, просто отваливается сеть (у клиента проблемы с электоэнергией) ... как в этом случае сервер должен будет узнать о том, что соединение "мёртвое" ?
Re[4]: как получить FD_CLOSE в IOCP (GetQueuedCompletionStat
От: valaar  
Дата: 30.03.11 08:50
Оценка:
G>Что мешает повесить всем WSARecv?
Представьте, что WSARecv сработает — я получу блок данных, но по логике программы его ещё не жду. Опять оказываемся в ситуации, что нет ясности, когда клиент отвалится. Запустить ещё раз WSARecv — только отъем у себя память, а до логической точки, когда они понадобятся может пройти ещё неопределённое время.
Готов согласиться, что тут можно было бы озадачиться вопросами архитектуры приложения, которое не хочет получить от клиента данные и как-нибудь отреагировать, но пишу лишь сетевую библиотеку-обёртку, которой пользуется другая программа (не моя), поэтому интерфейс и семантика работы довольно жёстко заданы.



А>А если у того клиента, который очень долго (часы) не использует своё соединение, просто отваливается сеть (у клиента проблемы с электоэнергией) ... как в этом случае сервер должен будет узнать о том, что соединение "мёртвое" ?

Таких клиентов значительно меньше, чем тех, которые честно отсоединятся. Но и "проблемных" поймает раз в пару часов SO_KEEPALIVE. Только я об этом не узнаю...
Re[5]: как получить FD_CLOSE в IOCP (GetQueuedCompletionStat
От: Gomes Россия http://irazin.ru
Дата: 30.03.11 09:17
Оценка:
Здравствуйте, valaar, Вы писали:

V>Представьте, что WSARecv сработает — я получу блок данных, но по логике программы его ещё не жду.


Это реальная программа с реальным протоколом, или сферический конь?


V>Запустить ещё раз WSARecv — только отъем у себя память, а до логической точки, когда они понадобятся может пройти ещё неопределённое время.


Да, запустить ещё раз WSARecv.

Если это не устраивает — только пользовательский KeepAlive.
Re[6]: как получить FD_CLOSE в IOCP (GetQueuedCompletionStat
От: valaar  
Дата: 30.03.11 10:21
Оценка:
G>Это реальная программа с реальным протоколом, или сферический конь?

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

Сам же протокол уже содержал программный KeepAlive, но я отвечаю за "чёрный ящик" (сетевую библиотеку) и понимаю, что уведомить о разрыве соединения могу только путём перебора всех соединений в ответ на FD_CLOSE или пока оставить как есть, но внутренний перфекционизм всё ещё требует красоты и законченности...
Re[7]: как получить FD_CLOSE в IOCP (GetQueuedCompletionStat
От: Gomes Россия http://irazin.ru
Дата: 30.03.11 10:33
Оценка:
Здравствуйте, valaar, Вы писали:

V>Сам же протокол уже содержал программный KeepAlive

Не понял, в чем тогда проблема?

V>уведомить о разрыве соединения могу только путём перебора всех соединений в ответ на FD_CLOSE

Зачем? Причем здесь FD_CLOSE?

V>но внутренний перфекционизм всё ещё требует красоты и законченности...

Тогда не надо придумывать ничего лишнего.
Re[8]: как получить FD_CLOSE в IOCP (GetQueuedCompletionStat
От: valaar  
Дата: 30.03.11 13:31
Оценка:
G>Не понял, в чем тогда проблема?
G>Зачем? Причем здесь FD_CLOSE?
В качестве иллюстрации придумал следующий пример: рыбалка на удочки с колокольчиками. Можно смотреть за поклёвками отдельно и точно знать, клюёт или нет, а можно сидеть в стороне и при звуке колокольчика понять, что клюёт. Единственная в этом случае проблема — куда бежать, на какую удочку смотреть. Поэтому и думал, что должен же быть способ, который позволит решить сразу все вопросы, но оказалось, что его нет, а жаль...
Re[9]: как получить FD_CLOSE в IOCP (GetQueuedCompletionStat
От: Gomes Россия http://irazin.ru
Дата: 30.03.11 13:47
Оценка: +1
Здравствуйте, valaar, Вы писали:

V>Поэтому и думал, что должен же быть способ, который позволит решить сразу все вопросы, но оказалось, что его нет, а жаль...

Просто нет особой проблемы ;) Ну то есть в реальности, а не в воображении.
Re[10]: как получить FD_CLOSE в IOCP (GetQueuedCompletionSta
От: valaar  
Дата: 31.03.11 12:44
Оценка:
Здравствуйте, Gomes, Вы писали:

G>Просто нет особой проблемы ;) Ну то есть в реальности, а не в воображении.

В целом согласен, но есть ещё множество вещей в которых придётся покопаться, например, в быстром закрытии IOCP.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.