Тестирование для закрытого гнезда

Я пытаюсь проверить замкнутый сокет, который был изящно закрыт одноранговым узлом, не подвергая латентный удар двойной отправки, чтобы вызвать SIGPIPE .

Одно из предположений здесь состоит в том, что сокет, если он был закрыт, был изящно закрыт одноранговым узлом сразу после его последней записи / отправки. Фактические ошибки, такие как преждевременное закрытие, рассматриваются иначе, где в коде.

Если сокет все еще открыт, будет 0 или более байтов данных, которые я на самом деле не хочу выходить из буфера сокета.

Я думал, что могу называть int ret = recv(sockfd, buf, 1, MSG_DONTWAIT | MSG_PEEK); чтобы определить, подключен ли сокет. Если он подключен, но в буфере нет данных, я получу возврат -1 с errno == EAGAIN и errno == EAGAIN для повторного использования. Если он был изящно закрыт сверстником, я получу ret == 0 и открою новое соединение.

Я тестировал это и, похоже, работает. Тем не менее, я подозреваю, что есть небольшое окно между тем, когда я возвращаю последний бит моих данных и когда приходит сверстник FIN в котором я могу получить ложноположительный EAGAIN из моего тестового recv .

Это собирается укусить меня, или есть лучший способ сделать это?

Хорошо, поэтому я провел еще несколько тестов, и это то, что я нашел.

Я установил свой клиент для отправки HTTP/1.1 Connection: close сообщения на сервере, заставляя сервер вызывать «закрыть» после последней записи данных. Когда мой клиент закончил чтение данных из транзакции GET, он проверил бы сокет, чтобы проверить, все ли он открыт, используя вышеописанный метод, а затем попытается выпустить другой GET.

Я обнаружил, что примерно в 30% случаев мой тест произойдет до того, как FIN сервер сервера приведет к ложным срабатываниям и неудачным операциям.

Вероятно, единственным способом сделать это достаточно надежным, скажем, около 99%, было бы введение искусственных задержек, связанных с задержкой соединения между последним чтением и повторным использованием попытки повторного использования сокетов, – однако это в значительной степени повлияло на производительность убийства.

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

Вы контролируете другой конец? Самый надежный способ выполнить «чистое» закрытие сокета – для другого конца отправить сообщение «до свидания».

(Слегка «вне темы», извините). Возможно, это обсуждение может быть полезно четырем вам. Он по-прежнему не отвечает вам на вопрос «FIN», но может помочь вам более легко реагировать на остановку сверстников во время отправки вашей программы.

до свидания