Close() сокет непосредственно после отправки(): небезопасно?
Является ли это разумным/безопасным для close()
сокета непосредственно после последнего send()
?
Я знаю, что TCP должен попытаться доставить все оставшиеся данные в буфер отправки даже после закрытия сокета, но могу ли я действительно рассчитывать на это?
Я уверен, что в моем буфере приема нет оставшихся данных, поэтому после моего закрытия не будет отправлено RST.
В моем случае закрытие фактически является самой последней операцией кода перед вызовом exit()
.
Будет ли стек TCP действительно продолжать попытки и передавать данные даже после того, как процесс отправки его завершен? Это так же надежно, как и ждать произвольного тайм-аута, прежде чем вызвать close()
, установив SO_LINGER?
То есть, применяются те же самые таймауты TCP, или они короче? С большим почтовым буфером и медленным подключением время фактического переноса всех буферизованных данных может быть существенным, в конце концов.
Меня вообще не интересует уведомление о последнем отправленном байте; Я просто хочу, чтобы они, в конечном итоге, смогли максимально быстро добраться до удаленного хоста.
Подтверждения прикладного уровня не являются опцией (протокол HTTP, и я пишу небольшой сервер).
Ответы
Ответ 1
Я читал главную страницу SO_LINGER, или: почему мой tcp ненадежный блог много. Я рекомендую вам прочитать это тоже. В нем рассматриваются крайние случаи передачи больших данных в отношении сокетов TCP.
Я не эксперт в SO_LINGER
, но на своем коде сервера (все еще в активной разработке) я делаю следующее:
После того, как последний байт отправлен через send()
, я вызываю shutdown(sock, SHUT_WR)
, чтобы вызвать отправку FIN.
Затем подождите, пока последующий вызов recv()
на этом сокете вернет 0 (или recv вернет -1, а errno - это что-то иное, чем EAGAIN
/EWOULDBLOCK
).
Затем сервер выполняет close()
в сокете.
Предполагается, что клиент сначала закроет свой сокет после получения всех байтов ответа.
Но у меня действительно есть тайм-аут между финальным send()
и когда recv()
показывает EOF. Если клиент никогда не закроет свой конец соединения, сервер все равно перестанет ждать и закроет соединение. У меня 45-90 секунд для этого тайм-аута.
Все мои сокеты являются неблокирующими, и я использую poll/epoll, чтобы получать уведомления о событиях соединения в качестве подсказки, чтобы посмотреть, не пора ли попытаться снова вызвать recv()
или send()
.