- Fixing Broken Pipe Error With SSH Connection
- Fixing broken pipe error with SSH
- Method 1: Client side SSH configuration change
- Method 2: Server side SSH config change
- Linux pipes tips & tricks
- Pipe — что это?
- Логика
- Простой дебаг
- Исходный код, уровень 1, shell
- Исходный код, уровень 2, ядро
- Tips & trics
- What causes the Broken Pipe Error?
- 4 Answers 4
- What does the Broken pipe message mean in an SSH session?
- 9 Answers 9
- What makes a Unix process die with Broken pipe?
- 3 Answers 3
Fixing Broken Pipe Error With SSH Connection
If you use SSH to connect to remote Linux servers, you’ll notice that if you keep your SSH session inactive for some time and then try to use it again, the SSH session disconnects with an error message like this:
On some systems, it will display ‘Write failed: Broken pipe’ or ‘Connection closed by remote host’.
Let’s see what causes this error and how to go about keeping your SSH connection alive.
Fixing broken pipe error with SSH
As you may have guessed, the SSH connection is closed because of inactivity. There is no set value but it usually around 5 minutes or so.
What you can do to avoid the SSH session disconnection is to send an ‘alive message’ either from the server to client ( ClientAliveInterval ) or from client to server ( ServerAliveInterval ) at certain time interval.
This way, you keep the SSH session alive because there is a communication between the client and server and the server understands that client is still there.
Now, there are two ways to do that. Either you send the alive message from the client to the server or from the server to the client.
- If you connect to multiple servers via SSH, set it on your machine.
- If you are a sysadmin and several of users complain about frequent SSH connection disconnect, you may set it on the server.
Method 1: Client side SSH configuration change
Let’s say you want to keep your SSH connection alive with up to 10 minutes (600 seconds) of idle time.
While connecting to the remote Linux system through SSH, you can mention the ServerAliveInterval value like this:
Now, this thing work but manually entering this option each time you connect to the server is tiresome. Why not make it permanent?
I hope you are aware of the SSH config files. On the client side, you can take advantage of it to set certain SSH parameters for specific connections or all of them. I have explained SSH config file in detail here.
First, make sure that you have the ssh config file. If not create it:
It is important to give it the correct file permissions otherwise you’ll have permission denied error while connecting via SSH.
Use the chmod command and add the following file permission to it:
If you’re feeling lazy or don’t want to go in detail, use this command to set the alive interval to 600 seconds (10 minutes):
This will set the ServerAliveInterval value to 10 minutes for all SSH connection you’ll use. Give it a try if you want to.
If you want to make it more proper, you should add it like this:
Method 2: Server side SSH config change
The SSH config file for the server is usually located at /etc/ssh/sshd_config.
If you open this file, you’ll find two parameters of interest here:
- ClientAliveInterval : This is the inactivity time period after which the server will send an alive message to the ssh connected client.
- ClientAliveCountMax : This is the number of attempts the server will make to send the alive message.
Say, you set ClientAliveInterval to 200 seconds and ClientAliveCountMax to 3. This means the server will send alive message after 200 seconds. If there is no activity from the client, it will again send an alive message at 400 seconds. No response/activity from the client and another alive message is sent at 600 seconds. After this (600 seconds) the SSH connection is disconnected.
You can edit the /etc/ssh/sshd_config file in your favorite terminal based text editor like Vim. Look for ClientAliveInterval and ClientAliveCountMax entries. Remove the # key at the beginning of the lines and give them the appropriate value.
Save and exit the file.
Please do not set the SSH connection timeout to several hours. That would be a waste of resources.
I hope this tutorial helped you to fix the broken pipe error issue with SSH connection. Your feedback is welcome.
Источник
Linux pipes tips & tricks
Pipe — что это?
Pipe (конвеер) – это однонаправленный канал межпроцессного взаимодействия. Термин был придуман Дугласом Макилроем для командной оболочки Unix и назван по аналогии с трубопроводом. Конвейеры чаще всего используются в shell-скриптах для связи нескольких команд путем перенаправления вывода одной команды (stdout) на вход (stdin) последующей, используя символ конвеера ‘|’:
grep выполняет регистронезависимый поиск строки “error” в файле log, но результат поиска не выводится на экран, а перенаправляется на вход (stdin) команды wc, которая в свою очередь выполняет подсчет количества строк.
Логика
Конвеер обеспечивает асинхронное выполнение команд с использованием буферизации ввода/вывода. Таким образом все команды в конвейере работают параллельно, каждая в своем процессе.
Размер буфера начиная с ядра версии 2.6.11 составляет 65536 байт (64Кб) и равен странице памяти в более старых ядрах. При попытке чтения из пустого буфера процесс чтения блокируется до появления данных. Аналогично при попытке записи в заполненный буфер процесс записи будет заблокирован до освобождения необходимого места.
Важно, что несмотря на то, что конвейер оперирует файловыми дескрипторами потоков ввода/вывода, все операции выполняются в памяти, без нагрузки на диск.
Вся информация, приведенная ниже, касается оболочки bash-4.2 и ядра 3.10.10.
Простой дебаг
Исходный код, уровень 1, shell
Т. к. лучшая документация — исходный код, обратимся к нему. Bash использует Yacc для парсинга входных команд и возвращает ‘command_connect()’, когда встречает символ ‘|’.
parse.y:
Также здесь мы видим обработку пары символов ‘|&’, что эквивалентно перенаправлению как stdout, так и stderr в конвеер. Далее обратимся к command_connect():make_cmd.c:
где connector это символ ‘|’ как int. При выполнении последовательности команд (связанных через ‘&’, ‘|’, ‘;’, и т. д.) вызывается execute_connection():execute_cmd.c:
PIPE_IN и PIPE_OUT — файловые дескрипторы, содержащие информацию о входном и выходном потоках. Они могут принимать значение NO_PIPE, которое означает, что I/O является stdin/stdout.
execute_pipeline() довольно объемная функция, имплементация которой содержится в execute_cmd.c. Мы рассмотрим наиболее интересные для нас части.
execute_cmd.c:
Таким образом, bash обрабатывает символ конвейера путем системного вызова pipe() для каждого встретившегося символа ‘|’ и выполняет каждую команду в отдельном процессе с использованием соответствующих файловых дескрипторов в качестве входного и выходного потоков.
Исходный код, уровень 2, ядро
Обратимся к коду ядра и посмотрим на имплементацию функции pipe(). В статье рассматривается ядро версии 3.10.10 stable.
fs/pipe.c (пропущены незначительные для данной статьи участки кода):
Если вы обратили внимание, в коде идет проверка на флаг O_NONBLOCK. Его можно выставить используя операцию F_SETFL в fcntl. Он отвечает за переход в режим без блокировки I/O потоков в конвеере. В этом режиме вместо блокировки процесс чтения/записи в поток будет завершаться с errno кодом EAGAIN.
Максимальный размер блока данных, который будет записан в конвейер, равен одной странице памяти (4Кб) для архитектуры arm:
arch/arm/include/asm/limits.h:
Для ядер >= 2.6.35 можно изменить размер буфера конвейера:
Максимально допустимый размер буфера, как мы видели выше, указан в файле /proc/sys/fs/pipe-max-size.
Tips & trics
В примерах ниже будем выполнять ls на существующую директорию Documents и два несуществующих файла: ./non-existent_file и. /other_non-existent_file.
Перенаправление и stdout, и stderr в pipe
или же можно использовать комбинацию символов ‘|&’ (о ней можно узнать как из документации к оболочке (man bash), так и из исходников выше, где мы разбирали Yacc парсер bash):
Перенаправление _только_ stderr в pipe
Shoot yourself in the foot
Важно соблюдать порядок перенаправления stdout и stderr. Например, комбинация ‘>/dev/null 2>&1′ перенаправит и stdout, и stderr в /dev/null.
Получение корректного кода завершения конвейра
По умолчанию, код завершения конвейера — код завершения последней команды в конвеере. Например, возьмем исходную команду, которая завершается с ненулевым кодом:
И поместим ее в pipe:
Теперь код завершения конвейера — это код завершения команды wc, т.е. 0.
Обычно же нам нужно знать, если в процессе выполнения конвейера произошла ошибка. Для этого следует выставить опцию pipefail, которая указывает оболочке, что код завершения конвейера будет совпадать с первым ненулевым кодом завершения одной из команд конвейера или же нулю в случае, если все команды завершились корректно:
Shoot yourself in the foot
Следует иметь в виду “безобидные” команды, которые могут вернуть не ноль. Это касается не только работы с конвейерами. Например, рассмотрим пример с grep:
Здесь мы печатаем все найденные строки, приписав ‘new_’ в начале каждой строки, либо не печатаем ничего, если ни одной строки нужного формата не нашлось. Проблема в том, что grep завершается с кодом 1, если не было найдено ни одного совпадения, поэтому если в нашем скрипте выставлена опция pipefail, этот пример завершится с кодом 1:
В больших скриптах со сложными конструкциями и длинными конвеерами можно упустить этот момент из виду, что может привести к некорректным результатам.
Источник
What causes the Broken Pipe Error?
I know that broken pipe error is thrown when the socket on the peer side is closed.
But, in my test I have noted that an immediate ‘send’ call on this side when the peer side is closed doesn’t always lead to a broken pipe error.
After closing the socket on peer side (I have tried clean closing by calling close and also abnormal closing by killing the peer), if I try to send 40 bytes, then I don’t get a broken pipe, but, if I try to send 40000 bytes then it immediately gives broken pipe error.
What exactly causes broken pipe and can it’s behavior be predicted?
4 Answers 4
It can take time for the network close to be observed — the total time is nominally about 2 minutes (yes, minutes!) after a close before the packets destined for the port are all assumed to be dead. The error condition is detected at some point. With a small write, you are inside the MTU of the system, so the message is queued for sending. With a big write, you are bigger than the MTU and the system spots the problem quicker. If you ignore the SIGPIPE signal, then the functions will return EPIPE error on a broken pipe — at some point when the broken-ness of the connection is detected.
The current state of a socket is determined by ‘keep-alive’ activity. In your case, this is possible that when you are issuing the send call, the keep-alive activity tells that the socket is active and so the send call will write the required data (40 bytes) in to the buffer and returns without giving any error.
When you are sending a bigger chunk, the send call goes in to blocking state.
The send man page also confirms this:
When the message does not fit into the send buffer of the socket, send() normally blocks, unless the socket has been placed in non-blocking I/O mode. In non-blocking mode it would return EAGAIN in this case
So, while blocking for the free available buffer, if the caller is notified (by keep-alive mechanism) that the other end is no more present, the send call will fail.
Predicting the exact scenario is difficult with the mentioned info, but I believe, this should be the reason for you problem.
Источник
What does the Broken pipe message mean in an SSH session?
Sometimes my SSH session disconnects with a Write failed: Broken pipe message. What does it mean? And how can I keep my session open?
I know about screen , but that’s not the answer I’m looking for. I think this is a sshd config option.
9 Answers 9
It’s possible that your server closes connections that are idle for too long. You can update either your client ( ServerAliveInterval ) or your server ( ClientAliveInterval )
To update your server (and restart your sshd )
/.ssh/config on my Mac, do I have to create it there or it’s is somewhere else?
/.ssh ) first. So mkdir -p
If you want to have a longer connection period, in the client add:
ServerAliveCountMax by default this is set to 3. Therefore once the ServerAliveInterval has sent 3 small packs of info to your server it will then automatically log out. Setting it to 1200 means this process will have to occur at least 1200 times. In short you should be connected at least 30*1200 seconds (10 hours).
An alternative solution would be to use mosh — the mobile shell. In contrast to ssh it connects via UDP and supports roaming. You can start your session at home, suspend your laptop, take it to work / friends / wherever else you have internet, unsuspend your laptop and continue to work as if nothing has happened. It is especially useful if you are on a lousy internet connection: It shows instant feedback if your keystrokes don’t reach the server and continuously tries to reestablish the connection.
Installation and setup are simple: It is now included in all current Linux (plus a few non-Linux) distributions and it coordinates the session initialization and authentication via a prior ssh connection. So if you are able to connect via ssh user@server you are very likely to be able to connect with mosh just by calling mosh user@server , if the mosh packages are installed on both ends.
The main reason for connection failures is that you have to reach the server on a UDP port (default range: 60000-61000) for mosh to work. So if the server is behind a firewall you are mostly out of luck if can’t punch holes in it yourself (security implications).
Источник
What makes a Unix process die with Broken pipe?
Here are some options I thought of, not sure which is the right one.
- There was an I/O error reading from the pipe.
- The process writing to the other end of the pipe died with a failure.
- All processes who could write to the pipe have closed it.
- The write buffer of the pipe is full.
- The peer has closed the other direction of the duplex pipe.
- Writing failed because there are no processes which could read from the pipe.
- A system call returned the EPIPE error, and there was no error handler installed.
3 Answers 3
A process receives a SIGPIPE when it attempts to write to a pipe (named or not) or socket of type SOCK_STREAM that has no reader left.
It’s generally wanted behaviour. A typical example is:
You don’t want find to keep on running once head has terminated (and then closed the only file descriptor open for reading on that pipe).
The yes command typically relies on that signal to terminate.
Will write «y» until some-command terminates.
Note that it’s not only when commands exit, it’s when all the reader have closed their reading fd to the pipe. In:
There will be 1 (the subshell), then 2 (subshell + sleep), then 1 (subshell) then 0 fd reading from the pipe after the subshell explicitely closes its stdin, and that’s when yes will receive a SIGPIPE.
Above, most shells use a pipe(2) while ksh93 uses a socketpair(2) , but the behaviour is the same in that regard.
When a process ignores the SIGPIPE, the writing system call (generally write , but could be pwrite , send , splice . ) returns with a EPIPE error. So processes wanting to handle the broken pipe manually would typically ignore SIGPIPE and take action upon a EPIPE error.
Источник