- Pipes: Программные каналы в Linux
- Статья из цикла HuMan
- Выбор термина
- Предисловие
- Введение в программные каналы
- Как это работает
- Как пользоваться программными каналами
- Другие распространенные команды-фильтры
- Сложные программные каналы
- Немного истории
- Понятие именованного канала
- Русские Блоги
- Способ связи между процессами-pipe (pipe)
- Содержание этой главы
- Что такое коммуникация процесса
- Способы коммуникации процесса
- Труба
- Механизм реализации трубы
- Создание конвейера
- Как общаться по трубе
- Связанные правила использования трубопроводной связи
- емкость трубы
Pipes: Программные каналы в Linux
Статья из цикла HuMan
Выбор термина
Какие только термины не используют в русском языке для перевода слова «pipes»: и трубы, и трубопроводы, и конвейеры, и потоки, и прочее. В контексте все эти термины выглядят довольно неуклюже. И вот еще беда — ни от одного из этих существительных нельзя образовать глагол, не говоря уже о том, чтобы называть так символ вертикальной черты. Можно, правда, употребить глагол «конвейеризировать», но такое не написать, не выговорить невозможно. Я пытался делать наметки этой статьи, используя все перечисленные термины, но не был удовлетворен ни одним.
Совершенно случайно, в книге А. Робачевского «Операционная система UNIX» мне встретился термин «программные каналы». Поначалу он показался мне несколько громоздким, но попробовав его на деле, я убедился в его несомненных преимуществах. Он не выглядит смешно и дико как «трубы», от него легко произвести глагол, и, самое главное, он имеет вполне прижившегося на русской почве брата — «именованные каналы», которые никто не назовет «именованными трубопроводами». Итак, решено, в данной статье термин pipes будет звучать как «программные каналы».
Предисловие
Предлагаемая вашему вниманию статья как раз для тех, кто недавно открыл для себя командную строку Линукс.
Введение в программные каналы
Команда dmesg выводит сообщения ядра Линукс о процессе загрузки ОС (те самые, что пробегают по экрану монитора при загрузке системы). Эти сообщения не умещаются на одном экране, и пролетают так быстро, что прочесть их невозможно. Поэтому вывод программы dmesg передают на ввод команде less. (Команда less позволяет выводу команды dmesg заполнить только один экран. Чтобы прочесть следующую порцию текста, нужно нажать клавишу пробела, а чтобы вернуться к предыдущей порции — клавишу b. Прервать работу программы можно клавишей q). Оператором такой передачи служит вертикальная черта (|). (Пробелы до и после вертикальной черты ставятся для удобства чтения, но можно обойтись и без них). Все вместе и есть простейший программный канал.
Того же результата можно достичь, если сначала перенаправить вывод команды dmesg во временный файл, а затем просмотреть содержимое этого файла на экране монитора.
Очевидно, что такая схема менее производительна: во-первых, необходимо давать две команды, во-вторых потому, что следующая команда может начать работать только после завершения первой.
Необходимо пояснить понятия, которые я походя назвал «вводом» и «выводом» программы.
Любая программа командной оболочки (шелла) оперирует с тремя потоками данных: стандартным вводом (stdin), стандартным выводом (stdout), и стандартным сообщением об ошибке (stderr). (Подробно об этом можно прочесть в статье «Перенаправление стандартных потоков данных»).
По умолчанию, стандартный ввод осуществляется с клавиатуры, а стандартный вывод — на экран монитора. Если же мы задействуем оператор программных каналов (|), то стандартный вывод первой программы станет стандартным вводом второй, при этом на экране монитора он уже не появится.
Такая цепочка вовсе не ограничивается двумя программами, но может продолжаться сколь угодно долго.
Как это работает
Даже если посылающая программа производит 5000 байт в секунду, а принимающая программа может обработать только 100 байт в секунду, все равно никакой потери информации не произойдет, так как программные каналы имеют буферы. Вывод посылающей программы собирается в буфере, ставится в очередь. Когда принимающая программа готова считывать данные, операционная система посылает порцию данных из буфера. В случае переполнения буфера, посылающая программа приостанавливается (блокируется), до тех пор, пока принимающая программа не сможет снова считывать данные, тем самым освобождая буфер.
Механизм этого свойства командной оболочки довольно сложен, в данной статье мы не станем его рассматривать, а будем просто пользоваться этой замечательной способностью шелла.
Как пользоваться программными каналами
Кроме вышеприведенного примера с каналом dmesg | less , часто используется канал ls | less . Команда ls позволяет просматривать содержимое директорий, а с опцией -l дает подробные сведения о файлах, «населяющих» указанную директорию. Если директория содержит достаточно файлов, чтобы их список занял больше одного экрана, то применение программного канала с less или more неизбежно:
Для пробы проделайте такой пример:
Только запаситесь терпением — на моей небольшой системе, установленной с одного CD, в выводе было 87 187 строк, сиречь файлов. Дело в том, что опция -R команды ls выводит содержимое директории рекурсивно, то есть открывая подкаталоги, подкаталоги подкаталогов и так далее, пока не перечислит все файлы. Правда, чтобы просмотреть действительно все файлы в директории, нужно войти как администратор (root), потому что некоторые каталоги могут не давать прав доступа рядовому пользователю.
Понятно, что найти «вручную» что-либо в таком списке проблематично, и тут на помощь снова придут программные каналы.
Команда grep найдет нужные вам строки, если вы зададите образец для поиска:
Обратите внимание на символ # в начале командной строки — он означает, что я вошел с правами суперпользователя.
Команды, входящие в состав программных каналов, часто называются командами-фильтрами, так как они пропускают через себя потоки данных.
Среди команд-фильтров самая употребительная, без сомнения, grep. Она применяется везде, где нужно выбрать искомое из большого объема данных. Скажем, просмотреть все, что касается USB в выводе команды dmesg:
Это только начало списка строк, выведенных командой grep -i usb , я не привожу его полностью из экономии места. Опция -i приказывает команде grep не замечать разницы между заглавными и строчными буквами.
Любой системный администратор часто пользуется командой ps. С опциями -e и -f она выводит все процессы, текущие в системе в полной форме (подробно). Процессов этих весьма много, поэтому я не привожу полный вывод команды:
Чтобы найти в этом списке интересующие вас процессы, следует канализировать команду ps с командой grep. Допустим, вас интересуют процессы hald:
С таким коротким списком уже легче работать. (Обратите внимание на последнюю строчку, там представлен сам запущенный нами процесс grep hald ).
Другие распространенные команды-фильтры
sort — сортирует строки по алфавиту или порядку номеров
wc — подсчитывает количество строк, слов, байт или символов в тексте
tr — заменяет одни символы другими
sed — позволяет редактировать текст прямо из командной строки, даже не видя его.
cut — вырезает из текста нужные куски и выдает их на стандартный вывод
head/tail — позволяют ограничить просмотр первыми несколькими строками (head — голова), либо последними несколькими строками (tail — хвост).
В этот список я включил только несколько команд-фильтров, освоив которые, можно вдоволь насладиться составлением самых замысловатых программных каналов.
Сложные программные каналы
Примечание: Символ (\) используется для объединения всех шести строк в одну командную строку.
Команда первая: wget получает содержимое HTML web страницы.
Команда вторая: sed удаляет из текста страницы все символы, не являющиеся пробелами или буквами и заменяет их пробелами.
Команда третья: tr переводит все символы верхнего регистра в нижний регистр (заглавные буквы в строчные), а также конвертирует пробелы в строках в символы новой строки, так что теперь каждое «слово» является новой строкой.
Команда четвертая: grep оставляет только строки, содержащие хотя бы один алфавитный символ (попросту букву), удаляя все пустые строки.
Команда пятая: sort сортирует список «слов» в алфавитном порядке, а с опцией -u удаляет дубликаты.
Команда шестая, и последняя: comm находит строки, общие для двух файлов. Первым файлом является стандартный вывод нашего программного канала, для чего вместо имени первого файла стоит прочерк (-), вторым файлом будет файл words.txt. Строки, которые встречаются только во втором файле и те, что встречаются в обоих файлах, подавляются опциями -2 и -3. Результатом будет список слов, встречающихся только в первом файле. И, если считать файл words.txt неким эталонным словарем, то выходящий список будет содержать слова, которых нет в словаре, то есть написанные с ошибками.
Немного истории
Понятие именованного канала
В отличие от анонимного программного канала, автоматически создаваемого шеллом, именованный канал обладает именем, и создается явно при помощи команд mknod или mkfifo. Создадим именованный канал fifo1:
Теперь запустим процесс, обращающийся к данному каналу:
Несмотря на нажатие клавиши ENTER ничего не происходит, что не удивительно, ведь файл fifo1 пока пуст, и команде grep нечего обрабатывать. Однако консоль оказывается занята ждущим процессом, и разблокировать ее можно только прервав процесс (скажем, нажатием клавиш CTRL+c).
Чтобы наполнить именной канал содержимым, нужно чтобы к нему обратился второй процесс. Для этого мы должны открыть вторую консоль и запустить какую-либо команду, передающую данные в файл fifo1. Например:
Немедленно в первой консоли сработает команда grep:
Совершенно ясно, что пользоваться таким неудобным механизмом в пользовательских целях никто не будет, ведь гораздо проще запустить один программный канал:
и получить тот же результат.
Этот пример я привел лишь для демонстрации создания и работы именованного канала. Другое дело, когда именованные каналы создаются самими процессами для обмена информацией друг с другом. Но повторюсь, что тема эта непростая и в данной статье рассматриваться не будет.
Источник
Русские Блоги
Способ связи между процессами-pipe (pipe)
Содержание этой главы
- Как общаться между процессами с помощью трубы
- Правила и ограничения коммуникации трубного процесса
- Механизм реализации pipe pipe в Linux и структура канала управления pipe
Что такое коммуникация процесса
Взаимодействие процессов — это обмен данными между двумя процессами. В Linux существует несколько способов взаимодействия процессов. В этой статье мы в основном представляем самый простой метод-канал взаимодействия процессов.
Способы коммуникации процесса
Единственный способ обмена информацией между процессами — передача открытых файлов.
Труба
Канал — это одна из старейших и наиболее простых форм системного IPC, все системы Linux предоставляют такой механизм связи. Однако у конвейера есть два следующих ограничения:
- Это полудуплексный режим, то есть данные по каналу могут передаваться только в одном направлении. Если требуется двусторонняя связь, между двумя процессами должны быть установлены два канала;
- Каналы могут использоваться только между двумя процессами с общим предком; —
Механизм реализации трубы
Канал — это буфер, которым управляет ядро, один конец которого подключен к выходу процесса, а другой конец подключен к входу процесса. Буфер конвейера не обязательно должен быть большим, он спроектирован как кольцевая структура данных, когда два процесса завершаются, жизненный цикл конвейера также завершается.
Создание конвейера
Канал создается путем вызова функции конвейера.
Он возвращает два файловых дескриптора по выходному параметру fd,fd [0] открыт для чтения, fd [1] открыт для записи, Выходные данные fd [1] являются входными данными fd [0]. Когда канал создается успешно, функция канала возвращает 0. Если создание не удается, она возвращает -1. Связь между fd [0] и fd [1] показана на рисунке ниже:
Как общаться по трубе
Выше мы установили конвейер в одном процессе, но на самом деле конвейер в одном процессе бесполезен. Обычно процесс сначала вызывает функцию конвейера для создания канала, а затем вызывает функцию fork (). Функция fork изменяет родительский процесс. Соответствующая структура данных наследуется дочернему процессу, так что дочерний процессДескриптор файлаFd [0] и fd [1] в таблице указывают на файл конвейера, на который указывает родительский процесс, так что связь между двумя процессами может быть реализована. Вышеупомянутый процесс выглядит следующим образом:
Связанные правила использования трубопроводной связи
Для конвейера от дочернего процесса к родительскому процессу (запись дочернего процесса, чтение родительского процесса) родительский процесс закрывает fd [1], дочерний процесс закрывает fd [0], когда часть конвейера закрывается (закрывается на основе вышеизложенного Один конец трубы) Работают следующие два правила:
- При чтении канала, сегмент записи которого был закрыт, после того, как все данные были прочитаны,чтение возвращает 0(чтение возвращает 0, чтобы указать, что конец файла был прочитан);
Проверим:
Программа позволяет дочернему процессу записать строку три раза, а затем закрывает дочерний процесс fd [1], то есть закрывает конец записи канала, и не закрывает fd [0] родительского процесса, то есть конец чтения канала.
- Если вы пишете в канал, конец чтения которого закрыт, он будетГенерируйте соответствующие сигналыПроцесс записи сегмента завершается. Если сигнал игнорируется или сигнал захватывается и возвращается обработчиком, команда write вернет -1, а errno будет установлено значениеEPIPE;
Проверим:
Цель кода такова: мы позволяем концу записи (дочернему процессу) всегда записывать строку msg, а конец чтения (родительский процесс) читает три раза, а затем закрывает fd [0] родительского процесса, так что дочерний процесс записывает все время , А родительский процесс не читает. Результаты приведены ниже:
Мы обнаружили, что после того, как родительский процесс закрыл fd [0], дочерний процесс былПрервано ненормально, Из кода выхода и кода сигнала выхода дочернего процесса мы обнаружили, что это сигнал 13 (SIGPIPE) Завершается, поэтому запись в канал, закрытый на конце чтения, не соответствует действительности для PIPE. Операционная система отправит процессу завершения записи после закрытия конца чтенияSIGPIPEВызвать завершение процесса.
- Если концы для чтения и записи канала не закрыты, но конец канала для записи больше не записывает данные в канал. В это время, если в конвейере нет данных, процесс чтения будет заблокирован до тех пор, пока в конвейере не появятся данные, прежде чем считывать данные и возвращаться.
- Если файловый дескриптор, указывающий на конец чтения канала, не закрыт, а тот, который удерживает конец чтения канала, не читает данные из канала, то есть процесс, записывающий данные в канал. Если канал заполнен, а затем записывает данные в канал, напишите снова Вызывает блокировку процесса до тех пор, пока в канале не останется места, прежде чем он продолжит запись данных в канал и возврат.
емкость трубы
Мы можем пройти* man 7 pipe*; Для запроса пропускной способности трубопроводаpipe_capacity
## Механизм реализации конвейера Linux
По сути, конвейер — это тоже своего рода файл, но он отличается от обычного файла. Канал позволяет преодолеть две проблемы, связанные с использованием файлов для обмена данными. Конкретные характеристики следующие:
Канал — это буфер фиксированного размера. В Linux размер буфера составляет одну страницу, что составляет 4 КБ, поэтому его размер не будет увеличиваться без проверки, как у обычных файлов. В Linux ядро используетstruct pipe_inode_infoСтруктура для описания конвейера, эта структура определена вpipe_fs_i.hв.
struct pipe_inode_info структура
Количество буферов
Структура буфера управления
Источник