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

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

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

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

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

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

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

Ответ 1

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

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

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

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

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

Ответ 2

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

Ответ 3

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

Bye