У меня проблема с Winsock2, использующим IOCP (перекрывающийся режим ввода-вывода), когда мне нужно закрыть соединение после отправки запрошенных данных.
Я обнаружил, что если я отправлю некоторые данные и закрою сокет сразу после отправки, то данные не будут (или частично будут) отправлены, потому что нет времени отправить пакет перед закрытием.
Я также обнаружил, что есть несколько методов отключения, таких как WSA_SendDisconnect()
, которые я сейчас использую.
Сейчас текущая реализация выглядит примерно так:
Отправка данных
Установка флага, указывающего на намерение закрыть соединение после отправки
Когда происходит событие IOCP относительно события отправки, если флаг установлен и
bytecount > 0
, я снова отправляю пустой буфер, просто чтобы убедиться, что все данные были отправленыКогда происходит событие IOCP относительно события отправки, если флаг установлен и
bytecount == 0
, я сбрасываю флаг и вызываюWSA_SendDisconnect()
с пустым буфером, чтобы отправить отключить сообщение- Когда происходит событие IOCP относительно события отправки без установленного флага и
bytecount == 0
, я вызываюclosesocket()
и уничтожаю контекст.
С помощью этой процедуры я мог сделать почти уверенным, что сокет отключится только после того, как все данные будут отправлены, на самом деле это работает очень хорошо, но когда я тестирую программу в некоторых очень редких случаях 10-15 раз из 1000000 тестов что-то не так . (Было бы очень сложно определить точную проблему, программа работает как веб-сервер, и я тестирую ее с помощью apachebench и siege, после теста я получаю сводку, где я вижу иногда 10-15 неудачных запросов. .)
Я был почти уверен, что ошибка связана с тем, что сокет не может отправить весь пакет до закрытия, поэтому я поставил небольшую задержку перед socketclose()
, и с тех пор я получаю ноль неудачных запросов, но, конечно, это не решение, а просто способ отфильтровать то, что может вызвать проблему.
Метод, который я реализовал, очевидно, не имеет надлежащего способа определить, все ли отправлено сокетом перед закрытием, хотя я начинаю закрываться только после завершения последней фиктивной записи.
Что было бы лучшим решением для закрытия сокета только после того, как весь буфер отправки был фактически записан в сеть?
Ps: Пробовал играть с NoDelay и настройкой LingerState, не помогло.
DisconnectEx
сTF_REUSE_SOCKET
. когда этот запрос завершен, вы можете закрыть сокет - person RbMm   schedule 27.03.2019closesocket
после завершенияDisconnectEx
. передайте ему свой iocp, он быстрее вернетERROR_IO_PENDING
, и когда io завершится после этого, можно закрыть или повторно использовать сокет - person RbMm   schedule 27.03.2019