Что вызывает ошибку сломанной трубы?


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

но в моем тесте я заметил, что немедленный вызов "send" на этой стороне, когда одноранговая сторона закрыта, не всегда приводит к ошибке сломанной трубы.

например:

после закрытия сокета на стороне peer (я попытался очистить закрытие, вызвав close, а также ненормальное закрытие, убив peer), если я попытаюсь отправить 40 байт, то я не получаю сломанную трубу, но, если я попробуйте отправить 40000 байт, то он сразу дает сломанную ошибку трубы.

Что именно вызывает сломанную трубу и можно ли предсказать ее поведение?

4 58

4 ответа:

Это может занять время для сети близко, чтобы наблюдать - общее время номинально около 2 минут (да, минут!) после закрытия перед пакетами, предназначенными для порта, все считаются мертвыми. При обнаружении ошибки в какой-то момент. При небольшой записи вы находитесь внутри MTU системы, поэтому сообщение помещается в очередь для отправки. С большой записью вы больше, чем MTU, и система быстрее обнаруживает проблему. Если вы игнорируете сигнал SIGPIPE, то функции вернет ошибку EPIPE на сломанной трубе - в какой-то момент, когда обнаружена сломанность соединения.

текущее состояние сокета определяется активностью "keep-alive". В вашем случае это возможно, что когда вы выдаете send вызов keep-alive activity говорит, что сокет активен и поэтому send вызов будет записывать необходимые данные (40 байт) в буфер и возвращает без каких-либо ошибок.

когда вы отправляете больший кусок, вызов send переходит в состояние блокировки.

страница отправки также подтверждает это:

когда сообщение не помещается в буфер отправки сокета, send () обычно блокирует, если сокет не был помещен в неблокирующий режим ввода-вывода. В неблокирующем режиме он вернет EAGAIN в этом случае

таким образом, при блокировке свободного доступного буфера, если вызывающий абонент уведомлен (с помощью механизма keep-alive), что другой конец больше не присутствует, вызов send завершится неудачей.

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

может быть, 40 байт помещается в буфер канала, а 40000 байт нет?

Edit:

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

когда peer close, вы просто не знаете, просто ли он перестает отправлять или как отправлять, так и получать.Поскольку TCP позволяет это, кстати, вы должны знать разницу между закрытием и выключением. Если одноранговый узел прекратит отправку и получение, сначала вы отправите несколько байтов, это будет успешно. Но одноранговое ядро отправит вас первым. Таким образом, впоследствии вы отправляете несколько байтов, ваше ядро отправит вам сигнал SIGPIPE, если вы поймаете или проигнорируете этот сигнал, когда ваша отправка вернется, вы просто получите ошибку сломанной трубы, или если вы не поведение по умолчанию вашей программе сбой.