Что вызывает ошибку сломанной трубы? - PullRequest
69 голосов
/ 03 января 2011

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

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

например:.

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

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

Ответы [ 4 ]

47 голосов
/ 03 января 2011

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

8 голосов
/ 03 января 2011

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

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

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

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

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

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

3 голосов
/ 03 января 2011

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

Edit:

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

0 голосов
/ 14 сентября 2018

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...