11 KiB
Лабораторная работа №4: Каналы передачи данных
Цель работы
Получить навыки организации обмена информацией между процессами средствами неименованных или именованных каналов в программах на языке C в операционных системах семейства Linux.
Описание задания
Лабораторная работа является модификацией лабораторной работы №3, в которой обмен данными между родительской и дочерними программами производится через программные каналы.
Вариант 12
Программа читает текстовый файл построчно. Для каждой строки первый символ становится ключом, и все вхождения этого символа в строке заменяются пробелами, пока не будет достигнуто максимальное количество замен.
Реализованные решения
1. Решение с неименованными каналами (pipes)
Файлы:
parent_pipe.c- родительская программаchild_pipe.c- дочерняя программа
Принцип работы:
-
Родительский процесс создает три канала для каждого дочернего процесса:
pipe_to_child- для передачи данных дочернему процессуpipe_from_child- для получения обработанных данныхpipe_error- для получения количества замен
-
Родительский процесс:
- Читает данные из входного файла
- Передает данные дочернему процессу через
pipe_to_child - Получает обработанные данные через
pipe_from_child - Записывает результат в выходной файл
-
Дочерний процесс:
- Перенаправляет stdin на чтение из канала (dup2)
- Перенаправляет stdout на запись в канал (dup2)
- Обрабатывает данные согласно варианту 12
- Возвращает количество замен через stderr
Преимущества:
- Простая реализация для родственных процессов
- Автоматическая синхронизация через блокирующие операции чтения/записи
- Нет необходимости в файловых дескрипторах на диске
Недостатки:
- Работает только между родственными процессами
- Ограниченный размер буфера канала
2. Решение с именованными каналами (FIFO)
Файлы:
fifo_server.c- серверная программаfifo_client.c- клиентская программа
Принцип работы:
-
Сервер создает два именованных канала:
/tmp/fifo_request- для получения запросов/tmp/fifo_response- для отправки ответов
-
Клиент:
- Читает данные из входного файла
- Отправляет данные серверу через
fifo_request - Получает обработанные данные через
fifo_response - Записывает результат в выходной файл
-
Сервер:
- Ожидает запросы от клиентов
- Обрабатывает данные согласно варианту 12
- Отправляет результат обратно клиенту
Преимущества:
- Работает между неродственными процессами
- Клиент-серверная архитектура
- Возможность обработки запросов от нескольких клиентов
Недостатки:
- Более сложная реализация
- Требуется управление файлами в файловой системе
- Необходима синхронизация между клиентом и сервером
Компиляция и запуск
Компиляция всех программ
make -f Makefile_lab4 all
Тестирование с неименованными каналами
make -f Makefile_lab4 test_pipes
Тестирование с именованными каналами
Вариант 1: Автоматический тест
make -f Makefile_lab4 test_fifo_auto
Вариант 2: Ручной запуск в двух терминалах
Терминал 1 (сервер):
make -f Makefile_lab4 test_fifo_server
Терминал 2 (клиент):
make -f Makefile_lab4 test_fifo_client
Сравнение с оригинальной версией
make -f Makefile_lab4 test_compare
Запуск всех тестов
make -f Makefile_lab4 test_all
Примеры использования
Неименованные каналы
./parent_pipe ./child_pipe 10 input1.txt output1.txt input2.txt output2.txt
Именованные каналы
Запустить сервер:
./fifo_server 10
В другом терминале запустить клиент:
./fifo_client input1.txt output1.txt
./fifo_client input2.txt output2.txt
Обработка исключительных ситуаций
Программы предусматривают обработку следующих ошибок:
- Отсутствие или неверное количество входных параметров
- Ошибки открытия входного и/или выходного файла
- Ошибки создания каналов
- Ошибки создания дочерних процессов
- Ошибки чтения и записи через каналы
Технические детали
Используемые системные вызовы
Неименованные каналы:
pipe()- создание каналаfork()- создание дочернего процессаdup2()- дублирование файлового дескриптораread()/write()- чтение/запись данныхclose()- закрытие файлового дескриптораwaitpid()- ожидание завершения дочернего процессаexecl()- запуск новой программы
Именованные каналы:
mkfifo()- создание именованного каналаopen()- открытие FIFOread()/write()- чтение/запись данныхclose()- закрытие FIFOunlink()- удаление FIFO
Схема работы каналов
Неименованные каналы (pipes):
Родительский процесс Дочерний процесс
[файл] → read stdin ← pipe
↓ ↓
pipe → write read → process
↓
read ← pipe write → stdout
↓
write → [файл]
Именованные каналы (FIFO):
Клиент Сервер
[файл] → read /tmp/fifo_request ← open
↓ ↓
write → /tmp/fifo_request read → process
↓
read ← /tmp/fifo_response write → /tmp/fifo_response
↓
write → [файл]
Структура проекта
lab4/
├── parent_pipe.c # Родительская программа (pipes)
├── child_pipe.c # Дочерняя программа (pipes)
├── fifo_server.c # Серверная программа (FIFO)
├── fifo_client.c # Клиентская программа (FIFO)
├── parent.c # Оригинальная версия (Lab 3)
├── lab1_var12.c # Оригинальная версия (Lab 1)
├── Makefile_lab4 # Makefile для компиляции и тестирования
└── README_lab4.md # Документация
Контрольные вопросы (стр. 82)
-
Что такое канал (pipe)?
- Канал - это механизм межпроцессного взаимодействия (IPC), представляющий собой однонаправленный канал связи между процессами.
-
В чем разница между именованными и неименованными каналами?
- Неименованные каналы существуют только в памяти и доступны только родственным процессам
- Именованные каналы (FIFO) создаются в файловой системе и доступны любым процессам
-
Как создать канал?
- Неименованный:
int pipe(int fd[2]) - Именованный:
int mkfifo(const char *pathname, mode_t mode)
- Неименованный:
-
Что происходит при чтении из пустого канала?
- Процесс блокируется до тех пор, пока в канал не будут записаны данные
-
Что происходит при записи в заполненный канал?
- Процесс блокируется до тех пор, пока в канале не освободится место
-
Как передать данные через канал?
- Используя системные вызовы
write()для записи иread()для чтения
- Используя системные вызовы
-
Зачем нужно закрывать неиспользуемые концы канала?
- Для корректного определения EOF при чтении
- Для освобождения ресурсов
- Для предотвращения deadlock
Автор
Лабораторная работа выполнена в рамках курса "Системное программирование в среде Linux"