Именованные каналы¶
Именованный канал (англ. named pipe, также известный как FIFO — First In, First Out) — это один из методов межпроцессного взаимодействия (IPC) в операционных системах, реализующий однонаправленную или двунаправленную передачу данных между процессами через специальный файл в файловой системе. В отличие от неименованных (анонимных) каналов, которые существуют только в рамках родственных процессов и не имеют имени в файловой системе, именованный канал представлен в виде файла особого типа, что позволяет взаимодействовать любым процессам, имеющим доступ к этому файлу, независимо от их происхождения.
¶История
Концепция именованных каналов впервые была реализована в операционной системе Unix, начиная с версии System III (1982 год). Разработка была направлена на расширение возможностей анонимных каналов, которые были введены ещё в ранних версиях Unix (1970-е годы) и позволяли связывать только процессы, созданные одним родителем. Именованные каналы решили эту проблему, предоставив механизм обмена данными между произвольными процессами через файловую систему.
В операционной системе Microsoft Windows поддержка именованных каналов появилась в версии Windows NT 3.1 (1993 год) и с тех пор является неотъемлемой частью Win32 API. В Windows именованные каналы интегрированы в сетевую подсистему, что позволяет использовать их для взаимодействия между процессами на разных компьютерах в локальной сети.
¶Принцип работы
Именованный канал работает по принципу FIFO (первым пришёл — первым ушёл). Данные, записанные в канал одним процессом, читаются другим процессом в том же порядке. Канал представляет собой буфер в оперативной памяти, управляемый ядром операционной системы, но доступ к нему осуществляется через файловый дескриптор (в Unix) или дескриптор файла (в Windows), связанный с именем в файловой системе.
¶Создание
В Unix-подобных системах именованный канал создаётся с помощью системного вызова mkfifo() или команды mkfifo. В Windows для создания именованного канала используется функция CreateNamedPipe() из Win32 API. При создании указываются параметры: имя канала (в Windows — в формате \\.\pipe\имя_канала), режим доступа (только чтение, только запись или двунаправленный), размер буфера, количество возможных экземпляров канала и другие атрибуты.
¶Открытие и использование
Процессы открывают именованный канал как обычный файл: в Unix — с помощью системного вызова open(), в Windows — с помощью CreateFile(). После открытия канал ведёт себя как поток данных: данные записываются через write() (или WriteFile()) и читаются через read() (или ReadFile()). Важной особенностью является блокирующий режим: если процесс пытается прочитать данные из пустого канала, он блокируется до тех пор, пока данные не появятся, или до истечения тайм-аута (если задан). Аналогично, запись в полный канал блокируется до освобождения места.
¶Ограничения
- Именованные каналы не поддерживают произвольный доступ (seek) — данные читаются последовательно.
- Размер буфера ограничен (обычно от 4 КБ до 64 КБ в зависимости от системы), что может вызывать блокировки при интенсивной передаче данных.
- В Unix канал существует только в рамках одной файловой системы (не может быть создан на смонтированной сетевой файловой системе, например NFS).
- В Windows именованные каналы могут использоваться по сети, но требуют аутентификации и могут быть подвержены сетевым задержкам.
¶Виды и режимы
¶По направлению передачи данных
- Однонаправленные (simplex): данные передаются только в одном направлении — от писателя к читателю.
- Двунаправленные (duplex): данные могут передаваться в обоих направлениях. В Windows именованные каналы по умолчанию двунаправленные, в Unix для двунаправленного обмена часто создают два отдельных канала.
¶По режиму работы
- Блокирующий (blocking): процесс приостанавливается до завершения операции чтения/записи. Это стандартный режим.
- Неблокирующий (non-blocking): в Unix задаётся флагом
O_NONBLOCKпри открытии. В этом случае чтение из пустого канала возвращает ошибку, а запись в полный канал — ошибку или частичную запись. В Windows неблокирующий режим реализуется через асинхронный ввод-вывод (overlapped I/O).
¶По количеству соединений
- Один экземпляр: канал создаётся для одного соединения между двумя процессами.
- Множественные экземпляры: в Windows можно создать несколько экземпляров одного именованного канала, что позволяет обслуживать несколько клиентов одновременно (например, как в модели «клиент-сервер»).
¶Применение
Именованные каналы широко используются в системном и прикладном программировании для организации взаимодействия между процессами, особенно в следующих сценариях:
- Взаимодействие между сервером и клиентом: например, в Windows службы (сервисы) часто используют именованные каналы для связи с управляющими приложениями. Пример — служба SQL Server, которая может принимать запросы через именованный канал.
- Передача данных между процессами с разными правами: поскольку канал представлен файлом, можно настроить права доступа к нему, что позволяет контролировать, какие процессы могут читать или писать в канал.
- Обмен данными в реальном времени: в системах автоматизации, где требуется быстрая передача небольших объёмов данных (например, в промышленных контроллерах).
- Эмуляция ввода-вывода: в отладчиках и эмуляторах терминалов именованные каналы используются для перенаправления ввода-вывода между процессами.
- Взаимодействие между процессами в разных окружениях: в Windows именованные каналы могут работать через сеть, что позволяет связывать процессы на разных компьютерах в одной локальной сети.
¶Примеры использования
¶В Unix-подобных системах
Создание именованного канала в командной строке:
``bash mkfifo mypipe ``
Запись в канал из одного терминала:
``bash echo "Hello, World!" > mypipe ``
Чтение из канала в другом терминале:
``bash cat mypipe ``
В результате в терминале чтения появится сообщение «Hello, World!». Канал остаётся в файловой системе до явного удаления.
¶В Windows (на C++)
```cpp
¶include <windows.h>
¶include <iostream>
int main() { // Создание именованного канала HANDLE hPipe = CreateNamedPipe( L"\\\\.\\pipe\\MyPipe", // Имя канала PIPE_ACCESS_DUPLEX, // Двунаправленный доступ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, // Неограниченное количество экземпляров 4096, // Размер выходного буфера 4096, // Размер входного буфера 0, // Тайм-аут по умолчанию NULL // Атрибуты безопасности );
if (hPipe == INVALID_HANDLE_VALUE) { std::cerr << "CreateNamedPipe failed, error: " << GetLastError() << std::endl; return 1; }
// Ожидание подключения клиента ConnectNamedPipe(hPipe, NULL);
// Чтение данных от клиента char buffer[1024]; DWORD bytesRead; ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL); buffer[bytesRead] = '\0'; std::cout << "Received: " << buffer << std::endl;
// Отправка ответа const char* reply = "Hello from server!"; DWORD bytesWritten; WriteFile(hPipe, reply, strlen(reply), &bytesWritten, NULL);
CloseHandle(hPipe); return 0; } ```
¶Сравнение с другими механизмами IPC
| Механизм | Особенности | Преимущества | Недостатки |
|---|---|---|---|
| Именованные каналы | Файл в ФС, FIFO, может быть сетевым (Windows) | Простота использования, поддержка прав доступа, работа через сеть (Windows) | Только последовательный доступ, ограниченный буфер, блокирующие операции |
| Анонимные каналы | Только для родственных процессов, не имеют имени | Простота, низкие накладные расходы | Не могут использоваться между произвольными процессами |
| Сокеты | Сетевые, работают через TCP/UDP | Гибкость, поддержка сети, произвольный доступ | Более сложная настройка, большие накладные расходы |
| Разделяемая память | Общая область памяти, синхронизация через семафоры | Высокая скорость, поддержка произвольного доступа | Сложность синхронизации, риск гонок данных |
| Очереди сообщений | Асинхронная передача сообщений | Надёжность, поддержка приоритетов | Ограниченный размер сообщений, сложность настройки |
¶Интересные факты
- В Unix-подобных системах именованные каналы часто используются в сценариях оболочки для организации конвейеров между командами без создания временных файлов.
- В Windows именованные каналы могут быть использованы для взаимодействия между 32-битными и 64-битными процессами, что невозможно для некоторых других механизмов IPC.
- Именованные каналы поддерживаются в среде выполнения .NET (класс
NamedPipeServerStreamиNamedPipeClientStream), что упрощает их использование в приложениях на C#. - В операционной системе Linux именованные каналы имеют ограничение на размер буфера, который можно изменить через файл
/proc/sys/fs/pipe-max-size(требуются права root).
¶Источники
- Стивенс, У. Р. (1992). Advanced Programming in the UNIX Environment. Addison-Wesley.
- Microsoft Docs. (2023). Named Pipes (Windows API).
- Tanenbaum, A. S. (2007). Modern Operating Systems (3rd ed.). Prentice Hall.
- man-страницы:
mkfifo(1),pipe(7),fifo(7)(Linux).
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →


