В настоящее время Python считается зрелым языком программирования, который широко используется специалистами по обработке данных и инженерами по искусственному интеллекту (ИИ) из-за его простоты и легкочитаемого синтаксиса.
В данном руководстве мы обсудим [Errno 32] Broken pipe в Python, известное сообщение об ошибке, которое мы часто видим при взаимодействии с файловой системой. Мы разберем причину ее возникновения, а также способы ее избежать и исправить в коде.
«Сломанный канал» обычно считается ошибкой IOError (сокращение от «Ошибка ввода-вывода»), которая произошла на уровне системы Linux. Обычно она возникает при чтении и записи файлов или, другими словами, при выполнении ввода / вывода файлов или сетевого ввода / вывода (через сокеты).
Эквивалентная системная ошибка Linux – EPIPE, взятая из кодов ошибок GNU libc.
Макрос: int EPIPE
“Broken pipe.” означает, что на другом конце конвейера нет считывания процесса. Каждая функция библиотеки, вызывающая код ошибки, также выдает сигнал SIGPIPE; этот сигнал завершает программу, если не обрабатывается или не блокируется. Следовательно, программа никогда не отобразит EPIPE до тех пор, пока она не обработает или не заблокирует SIGPIPE.
Из приведенного выше утверждения мы можем сделать вывод, что система, отправляющая сигнал SIGPIPE, вызывает ошибку [Errno 32] Broken pipe в механизме межпроцессного взаимодействия Linux.
Например, система Linux внутренне использует другой сигнал, называемый SIGINT. В Linux команда Ctrl + C отправит сигнал SIGINT, чтобы завершить процесс, или мы можем использовать команду kill для достижения того же эффекта.
Python по умолчанию не игнорирует SIGPIPE. Однако он преобразует сигнал в исключение и вызывает ошибку – IOError: [Errno 32] Сломанный канал каждый раз, когда он получает SIGPIPE.
Ошибка “сломанный канал” при подключении к терминалу Linux
Всякий раз, когда мы сталкиваемся с ошибкой [Errno 32] Broken pipe при попытке передать вывод скрипта Python другой программе, например:
$ python file_name.py | head
Объяснение:
Вышеупомянутый синтаксис конвейера создаст процесс, отправляющий данные в восходящем направлении, и процесс, читающий данные в нисходящем направлении. Когда нисходящему потоку не нужно читать данные восходящего потока, он отправит сигнал SIGPIPE процессу восходящего потока.
Когда нисходящий поток не должен читать данные восходящего потока? Давайте разберемся в этом на примере. Команда head в этом примере должна прочитать достаточно строк, чтобы сообщить восходящему потоку, что нам больше не нужно его читать, и она отправит сигнал SIGPIPE процессу восходящего потока.
Всякий раз, когда восходящий процесс является программой Python, возникает ошибка типа IOError: [Errno 32] Broken pipe.
Как избежать ошибки “сломанный канал”?
Если мы не заботимся о правильном перехвате SIGPIPE и нам нужно быстро запустить процесс, вставьте следующий фрагмент кода в начало программы Python.
Синтаксис:
from signal import signal, SIGPIPE, SIG_DFL #Ignore SIG_PIPE and don't throw exceptions on it...(http://docs.python.org/library/signal.html) signal(SIGPIPE,SIG_DFL)
Объяснение:
В приведенном выше фрагменте кода мы перенаправили сигналы SIGPIPE на стандартный SIG_DFL, который система обычно игнорирует.
Однако рекомендуется остерегаться руководства Python по библиотеке сигналов, чтобы предостеречь от такой обработки SIGPIPE.
Перехват IOError во избежание ошибки Broken pipe
Поскольку ошибка Broken pipe является ошибкой IOError, мы можем разместить блок try / catch, чтобы ее перехватить, как показано в следующем фрагменте кода:
Синтаксис:
import sys, errno try: ### IO operation ### except IOError as e: if e.errno == errno.EPIPE: ### Handle the error ###
Объяснение:
В приведенном выше фрагменте кода мы импортировали модуль sys и errno и разместили блок try / catch, чтобы перехватить возникшее исключение и обработать его.
Возможное решение проблемы в многопроцессорной программе
В программах, которые используют рабочие процессы для ускорения обработки и многоядерные процессоры, мы можем попытаться уменьшить количество рабочих процессов, чтобы проверить, сохраняется ли ошибка или нет.
Большое количество рабочих процессов может конфликтовать друг с другом при попытке взять под контроль ресурсы системы или разрешение на запись на диск.
Изучаю Python вместе с вами, читаю, собираю и записываю информацию опытных программистов.
I’ve been dabbling in the Linux world for a good decade now, and it never ceases to surprise me with its quirks and nuances. I mean, who wouldn’t love the charm of the terminal, the power of the command line, and the satisfaction of troubleshooting a complex problem? Today, we’re going to dive headfirst into one of the most common issues that Linux users encounter: the dreaded ‘Broken Pipe’ error.
Trust me, I know how frustrating it can be when you’re working on a crucial task, and bam! The terminal throws this error at you. But rest assured, my friends, we’re not helpless here! As overwhelming as it may seem, with a little patience and understanding, it’s absolutely fixable. So, let’s roll up our sleeves and get down to business!
The ‘Broken Pipe’ error: What is it?
Just to give a brief overview for beginners (and a refresher for the veterans), the ‘Broken Pipe’ error typically occurs when one process is trying to write data to another process that is no longer available to receive it. In other words, the communication channel (or “pipe”) between the two processes has somehow been “broken.”
One thing I’ve learned throughout my Linux journey is that Linux is all about communication. That’s what makes it so powerful yet sometimes so tricky. And the ‘Broken Pipe’ error is a prime example of communication gone awry.
Example that demonstrates the ‘Broken Pipe’ error
Let’s use a simple case involving two popular Unix commands: yes and head.
The yes command continuously outputs a string until it is killed, and head command outputs the first part of files. When we pipe the output of yes into head, head will stop after it has printed out the first ten lines (which is its default behavior), and it will close its input pipe. But yes will still try to write to the pipe, and that’s when we get a ‘Broken Pipe’ error.
Here’s the command you can try:
yes | head
Now, if you run this command in a terminal, you may not see an error. That’s because the shell automatically ignores the ‘Broken Pipe’ signal (SIGPIPE). However, if you run it in a script, the script will exit due to the error.
Let’s put it in a script to see the error:
#!/bin/bash yes | head echo "Script finished"
If you run this script, you’ll see that “Script finished” does not get printed because the script exits when the ‘Broken Pipe’ error occurs.
Now, let’s handle the error using trap as we discussed earlier:
#!/bin/bash trap 'echo "Broken pipe signal detected" >&2' PIPE yes | head echo "Script finished"
This time, the script doesn’t exit when the ‘Broken Pipe’ error occurs. Instead, it prints “Broken pipe signal detected” and continues to the end, printing “Script finished”. This is a simple but clear illustration of the ‘Broken Pipe’ error and how to handle it.
Identifying the cause: The first step towards a solution
To fix any error, we first need to understand its cause. One common reason for this error, which I personally detest because it always seems to happen at the worst possible time, is network instability. You might see this error if you’re SSH-ing into a remote server, and your internet connection is unstable or drops out for a moment. The server tries to send data, but since your computer isn’t connected anymore, the pipe is “broken.”
Another cause can be when a command tries to write output to a pipe or file, but the pipe has been closed or the file has been removed. This often happens when you’re piping the output of one command into another, and the second command ends before the first one does. As a quick example, let’s say we’re using the yes command piped into head. If head finishes execution before yes, it closes the pipe, leading to the ‘Broken Pipe’ error. Oh, the number of times this has caught me out!
Fixing the error: Time to get our hands dirty
Now, onto the most exciting part, at least for me – fixing the error! Depending on the cause, there are a few ways to handle this:
Case 1: Network instability
If you’re dealing with an unstable network causing your SSH connections to drop, you can use tools like autossh, mosh, or screen.
- autossh: This handy tool automatically restarts SSH sessions and port forwarding if they crash, helping to maintain the connection.
- mosh: An excellent alternative to SSH, mosh provides a robust and responsive connection, even with intermittent network connectivity.
- screen: This utility allows you to start a screen session, run your command, and then detach from the session. You can later reattach to the session, and it’s as if you never left!
I must confess, I’m a huge fan of mosh for its simplicity and robustness. But feel free to choose the one that suits your needs and preferences!
Case 2: Commands writing to a closed pipe
For the scenario where a command is trying to write to a closed pipe, we can trap the ‘Broken Pipe’ signal in our scripts and handle it gracefully. To do this, we use the trap command in bash scripting.
Here’s a simple example:
trap 'echo "Pipe has broken, but we're not going to crash and burn!" >&2' PIPE yes | head
In this script, if a ‘Broken Pipe’ signal is detected, the message “Pipe has broken, but we’re not going to crash and burn!” is printed to standard error.
Keeping a watchful eye: Prevention is better than cure
Lastly, I’d like to share a piece of wisdom I’ve gathered over the years: An ounce of prevention is worth a pound of cure. It’s far better to prevent errors than to fix them. Keep your scripts clean, ensure you handle exceptions, and regularly check your network connectivity if you’re working on remote servers.
Wrapping up
In conclusion, while the ‘Broken Pipe’ error can be a nuisance, it’s not the end of the world, nor is it the end of your Linux journey. In fact, it’s just the beginning of a deeper understanding of how Linux operates. It’s these little challenges that, in my opinion, make Linux not just an operating system, but an adventure!
Remember, every problem has a solution, and every error is a stepping stone to becoming a better Linux user. I hope this blog post helps you navigate the ‘Broken Pipe’ error with confidence and ease. Until next time, happy troubleshooting!
BrokenPipeError at /ru/api/v1/my_url/
[Errno 32] Broken pipe
Request Method: POST
Request URL: https://apihrc.wienerdeming.com/ru/api/v1/my_url/
Django Version: 2.0
Python Executable: /my_project/.venv/bin/uwsgi
Python Version: 3.6.1
Python Path: [‘.’, », ‘/my_project/.venv/lib64/python36.zip’, ‘/my_project/.venv/lib64/python3.6’, ‘/my_project/.venv/lib64/python3.6/lib-dynload’, ‘/usr/lib64/python3.6’, ‘/usr/lib/python3.6’, ‘/my_project/.venv/lib/python3.6/site-packages’, ‘/my_project’, ‘/my_project/apps’]
Server time: Пн, 30 Июл 2018 16:02:43 +0500
Installed Applications:
[‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘django.contrib.gis’,
‘easy_thumbnails’,
‘django_filters’,
‘rest_framework’,
‘dynamic_rest’,
‘rest_framework.authtoken’,
‘easy_pdf’,
‘corsheaders’,
‘parler’,
*’my_apps’
]
Installed Middleware:
[‘raven.contrib.django.middleware.SentryMiddleware’,
‘django.middleware.security.SecurityMiddleware’,
‘django.contrib.sessions.middleware.SessionMiddleware’,
‘django.middleware.locale.LocaleMiddleware’,
‘corsheaders.middleware.CorsMiddleware’,
‘django.middleware.common.CommonMiddleware’,
‘django.middleware.csrf.CsrfViewMiddleware’,
‘django.contrib.auth.middleware.AuthenticationMiddleware’,
‘django.contrib.messages.middleware.MessageMiddleware’,
‘django.middleware.clickjacking.XFrameOptionsMiddleware’,
‘system.utils.middleware.RequestLogsMiddleware’]
Traceback:
File «/my_project/.venv/lib/python3.6/site-packages/django/core/handlers/exception.py» in inner
35. response = get_response(request)
File «/my_project/.venv/lib/python3.6/site-packages/django/core/handlers/base.py» in _get_response
128. response = self.process_exception_by_middleware(e, request)
File «/my_project/.venv/lib/python3.6/site-packages/django/core/handlers/base.py» in _get_response
126. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File «/my_project/.venv/lib/python3.6/site-packages/django/views/decorators/csrf.py» in wrapped_view
54. return view_func(*args, **kwargs)
File «/my_project/.venv/lib/python3.6/site-packages/rest_framework/viewsets.py» in view
95. return self.dispatch(request, *args, **kwargs)
File «/my_project/.venv/lib/python3.6/site-packages/rest_framework/views.py» in dispatch
494. response = self.handle_exception(exc)
File «/my_project/.venv/lib/python3.6/site-packages/rest_framework/views.py» in handle_exception
454. self.raise_uncaught_exception(exc)
File «/my_project/.venv/lib/python3.6/site-packages/rest_framework/views.py» in dispatch
491. response = handler(request, *args, **kwargs)
File «/my_project/.venv/lib/python3.6/site-packages/rest_framework/mixins.py» in create
21. self.perform_create(serializer)
File «/my_project/.venv/lib/python3.6/site-packages/rest_framework/mixins.py» in perform_create
26. serializer.save()
File «/my_project/.venv/lib/python3.6/site-packages/rest_framework/serializers.py» in save
214. self.instance = self.create(validated_data)
File «/usr/lib64/python3.6/contextlib.py» in inner
53. return func(*args, **kwds)
File «/my_project/apps/applications/serializers/application_action.py» in create
83. self._submit_to_client(application, validated_data.get(‘comment’, «»))
File «/my_project/apps/applications/serializers/application_action.py» in _submit_to_client
113. send = gmail.messages.send_message(message=message)
File «/my_project/apps/mailboxes/utils/gmail/messages.py» in send_message
129. message = self.service.users().messages().send(userId=’me’, body=message).execute()
File «/my_project/.venv/lib/python3.6/site-packages/googleapiclient/_helpers.py» in positional_wrapper
130. return wrapped(*args, **kwargs)
File «/my_project/.venv/lib/python3.6/site-packages/googleapiclient/http.py» in execute
835. method=str(self.method), body=self.body, headers=self.headers)
File «/my_project/.venv/lib/python3.6/site-packages/googleapiclient/http.py» in _retry_request
179. raise exception
File «/my_project/.venv/lib/python3.6/site-packages/googleapiclient/http.py» in _retry_request
162. resp, content = http.request(uri, method, *args, **kwargs)
File «/my_project/.venv/lib/python3.6/site-packages/oauth2client/transport.py» in new_request
175. redirections, connection_type)
File «/my_project/.venv/lib/python3.6/site-packages/oauth2client/transport.py» in request
282. connection_type=connection_type)
File «/my_project/.venv/lib/python3.6/site-packages/httplib2/__init__.py» in request
1322. (response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
File «/my_project/.venv/lib/python3.6/site-packages/httplib2/__init__.py» in _request
1072. (response, content) = self._conn_request(conn, request_uri, method, body, headers)
File «/my_project/.venv/lib/python3.6/site-packages/httplib2/__init__.py» in _conn_request
996. conn.request(method, request_uri, body, headers)
File «/usr/lib64/python3.6/http/client.py» in request
1239. self._send_request(method, url, body, headers, encode_chunked)
File «/usr/lib64/python3.6/http/client.py» in _send_request
1285. self.endheaders(body, encode_chunked=encode_chunked)
File «/usr/lib64/python3.6/http/client.py» in endheaders
1234. self._send_output(message_body, encode_chunked=encode_chunked)
File «/usr/lib64/python3.6/http/client.py» in _send_output
1065. self.send(chunk)
File «/usr/lib64/python3.6/http/client.py» in send
986. self.sock.sendall(data)
File «/usr/lib64/python3.6/ssl.py» in sendall
965. v = self.send(data[count:])
File «/usr/lib64/python3.6/ssl.py» in send
935. return self._sslobj.write(data)
File «/usr/lib64/python3.6/ssl.py» in write
636. return self._sslobj.write(data)
Exception Type: BrokenPipeError at /ru/api/v1/my_url/
Exception Value: [Errno 32] Broken pipe
Request information:
USER: admin2
Видеть «Сломанную трубу» в этой ситуации редко, но нормально.
Когда вы запускаете type rvm | head -1
, bash выполняется type rvm
в одном процессе, head -1
в другом. 1 стандартный вывод из type
подключен к «записи» конец трубы , то из стандартного ввода head
к «читать» конец. Оба процесса выполняются одновременно.
head -1
Процесс считывает данные из стандартного ввода (обычно в куски 8 КБ), вывести в одной строке ( в соответствии с -1
параметром), и выходы, в результате чего «читать» конец трубы должен быть закрыт. Поскольку rvm
функция довольно длинная (около 11 кБ после анализа и восстановления bash), это означает, что head
при выходе type
все еще остается несколько кБ данных для записи.
На этом этапе, поскольку type
он пытается выполнить запись в канал, чей другой конец был закрыт — сломанный канал, — функция write (), которую он вызвал, вернет ошибку EPIPE, переведенную как «Broken pipe». В дополнение к этой ошибке ядро также отправляет сигнал SIGPIPE type
, который по умолчанию немедленно завершает процесс.
(Сигнал очень полезен в интерактивных оболочках, так как большинство пользователей не хотят, чтобы первый процесс продолжал выполняться и пытался писать в никуда. Между тем, неинтерактивные службы игнорируют SIGPIPE — это не будет хорошо для долго работающего демона, чтобы умереть от такой простой ошибки — поэтому они находят код ошибки очень полезным.)
Однако доставка сигнала не происходит на 100% немедленно, и могут быть случаи, когда write () возвращает EPIPE, и процесс продолжает работать некоторое время до получения сигнала. В этом случае у вас type
будет достаточно времени, чтобы заметить неудачную запись, перевести код ошибки и даже напечатать сообщение об ошибке в stderr, прежде чем SIGPIPE прекратит его. (В сообщении об ошибке указано «-bash: type:», поскольку type
это встроенная команда самого bash.)
Похоже, что это чаще встречается в многопроцессорных системах, поскольку type
процесс и код доставки сигнала ядра могут работать на разных ядрах, буквально одновременно.
Можно было бы удалить это сообщение, исправив type
встроенную функцию (в исходном коде bash) для немедленного выхода при получении EPIPE от функции write ().
Тем не менее, это не о чем беспокоиться, и это никак не связано с вашей rvm
установкой.
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:
:client_loop: send disconnect: Broken pipe
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:
ssh -o ServerAliveInterval=600 username@server_ip_address
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:
touch ~/.ssh/config
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:
chmod 600 ~/.ssh/config
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):
echo "ServerAliveInterval 600" >> ~/.ssh/config
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:
Host *
ServerAliveInterval 600
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.