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

84

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

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

Например:

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

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

Джей
источник

Ответы:

59

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

Джонатан Леффлер
источник
4
@varevarao: я не думаю, что постановка передач в очередь и отправка через определенные промежутки времени является обходным решением. Постановка в очередь передачи до тех пор, пока не будет больше MTU для отправки, может быть обходным решением, если ваше приложение может жить с задержками.
Джонатан Леффлер,
11

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

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

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

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

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

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

Vikram.exe
источник
1
Текущее состояние сокета отслеживается активностью ACK. Keepalive - это только одно второстепенное действие ACK источника, и по умолчанию оно отключено.
user207421
3

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

Редактировать:

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

Джоэл
источник
0

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

Кинг конг
источник
-1

У нас возникла ошибка Broken Pipe после установки новой сети. Убедившись, что порт 9100 открыт и может подключаться к принтеру через порт telnet 9100, мы изменили драйвер принтера с «HP» на «Generic PDF», ошибка сломанной трубы исчезла, и мы смогли успешно выполнить печать.

(RHEL 7, принтеры были торговой маркой Ricoh, конфигурация HP существовала ранее и работала в предыдущей сети)

Энди Т
источник