Подтвердить что ты не робот

Close() сокет непосредственно после отправки(): небезопасно?

Является ли это разумным/безопасным для close() сокета непосредственно после последнего send()?

Я знаю, что TCP должен попытаться доставить все оставшиеся данные в буфер отправки даже после закрытия сокета, но могу ли я действительно рассчитывать на это?

Я уверен, что в моем буфере приема нет оставшихся данных, поэтому после моего закрытия не будет отправлено RST.


В моем случае закрытие фактически является самой последней операцией кода перед вызовом exit().

Будет ли стек TCP действительно продолжать попытки и передавать данные даже после того, как процесс отправки его завершен? Это так же надежно, как и ждать произвольного тайм-аута, прежде чем вызвать close(), установив SO_LINGER?

То есть, применяются те же самые таймауты TCP, или они короче? С большим почтовым буфером и медленным подключением время фактического переноса всех буферизованных данных может быть существенным, в конце концов.


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

Подтверждения прикладного уровня не являются опцией (протокол HTTP, и я пишу небольшой сервер).

4b9b3361

Ответ 1

Я читал главную страницу SO_LINGER, или: почему мой tcp ненадежный блог много. Я рекомендую вам прочитать это тоже. В нем рассматриваются крайние случаи передачи больших данных в отношении сокетов TCP.

Я не эксперт в SO_LINGER, но на своем коде сервера (все еще в активной разработке) я делаю следующее:

  1. После того, как последний байт отправлен через send(), я вызываю shutdown(sock, SHUT_WR), чтобы вызвать отправку FIN.

  2. Затем подождите, пока последующий вызов recv() на этом сокете вернет 0 (или recv вернет -1, а errno - это что-то иное, чем EAGAIN/EWOULDBLOCK).

  3. Затем сервер выполняет close() в сокете.

Предполагается, что клиент сначала закроет свой сокет после получения всех байтов ответа.

Но у меня действительно есть тайм-аут между финальным send() и когда recv() показывает EOF. Если клиент никогда не закроет свой конец соединения, сервер все равно перестанет ждать и закроет соединение. У меня 45-90 секунд для этого тайм-аута.

Все мои сокеты являются неблокирующими, и я использую poll/epoll, чтобы получать уведомления о событиях соединения в качестве подсказки, чтобы посмотреть, не пора ли попытаться снова вызвать recv() или send().