Что вызывает ошибку сломанной трубы?
Я знаю, что ошибка сломанной трубы выдается, когда сокет на одноранговой стороне закрыт.
Но в моем тесте я отметил, что немедленный вызов send на этой стороне, когда сторона однорангового соединения закрыта, не всегда приводит к ошибке разорванного канала.
Например:
После закрытия сокета на одноранговой стороне (я пробовал чистое закрытие, вызывая close, а также ненормальное закрытие, убивая однорангового), если я пытаюсь отправить 40 байтов, то я не получаю сломанный канал, но, если я пытаюсь отправьте 40000 байт, тогда это немедленно выдаст ошибку сломанного канала.
Что именно приводит к поломке трубы и можно ли предсказать ее поведение?
7 ответов
Для наблюдения за закрытием сети может потребоваться некоторое время - общее время обычно составляет около 2 минут (да, минут!) После закрытия, прежде чем все пакеты, предназначенные для порта, будут считаться мертвыми. Состояние ошибки обнаруживается в какой-то момент. С небольшой записью вы находитесь в MTU системы, поэтому сообщение ставится в очередь для отправки. С большой записью вы больше, чем MTU, и система обнаруживает проблему быстрее. Если вы проигнорируете сигнал SIGPIPE, то функции вернут ошибку EPIPE на разорванном канале - в какой-то момент, когда обнаружится разрыв соединения.
Текущее состояние сокета определяется активностью keep-alive. В вашем случае это возможно, что при выдаче send
вызов, keep-alive
активность говорит, что сокет активен и поэтому send
call запишет необходимые данные (40 байт) в буфер и вернет их без ошибок.
Когда вы отправляете больший кусок, вызов send переходит в состояние блокировки.
Страница man send также подтверждает это:
Когда сообщение не помещается в буфер отправки сокета, send() обычно блокируется, если только сокет не был переведен в неблокирующий режим ввода-вывода. В неблокирующем режиме он вернет EAGAIN в этом случае
Таким образом, при блокировке свободного доступного буфера, если вызывающий абонент уведомляется (с помощью механизма keep-alive) о том, что другой конец больше не присутствует, вызов send не будет выполнен.
С указанной информацией сложно предсказать точный сценарий, но я считаю, что это должно стать причиной вашей проблемы.
Может быть, 40 байтов помещаются в буфер канала, а 40000 байтов - нет?
Редактировать:
Процесс отправки отправляет сигнал SIGPIPE при попытке записи в закрытый канал. Я не знаю точно, когда сигнал отправляется, или как буферный канал влияет на это. Вы можете быть в состоянии восстановиться, перехватывая сигнал с помощью вызова sigaction.
Когда вы закрываете одноранговый узел, вы просто не знаете, прекратил ли он просто отправку или отправку и получение. Поскольку TCP позволяет это, кстати, вы должны знать разницу между закрытием и выключением. Если одноранговый узел перестает отправлять и получать, сначала вы отправите несколько байтов, это будет успешно. Но одноранговое ядро отправит вам RST. Поэтому впоследствии вы отправляете несколько байтов, ваше ядро будет отправлять вам сигнал SIGPIPE, если вы перехватываете или игнорируете этот сигнал, когда ваша посылка возвращается, вы просто получаете ошибку "Сломанный канал", или, если вы этого не делаете, поведение вашей программы по умолчанию дает сбой.,
Вам не нужно отправлять код по сети, чтобы получить эту ошибку. Например, этот код Python 3 (теперь мой любимый фрагмент кода):
while 1:print()
напечатает много новых строк и, в конечном итоге,
Настройки тайм-аута сеанса могут быть причиной поломки канала.
Например: время ожидания сеанса сервера составляет 3 часа, а у балансировщика нагрузки — 1 час.
Балансировщик нагрузки блокируется через 1 час, но сервер продолжает отправлять ответ. В этом случае один конец трубы сломан.
Но это может быть и поведение пользователя. Пользователь закрывает страницу во время загрузки и т. д.
У нас возникла ошибка Broken Pipe после установки новой сети. Убедившись, что порт 9100 открыт и может подключаться к принтеру через порт telnet 9100, мы изменили драйвер принтера с "HP" на "Generic PDF", ошибка сломанной трубы исчезла, и мы смогли успешно выполнить печать.
(RHEL 7, принтеры были торговой маркой Ricoh, конфигурация HP существовала ранее и работала в предыдущей сети)