239 lines
11 KiB
Markdown
239 lines
11 KiB
Markdown
# Лабораторная работа №4: Каналы передачи данных
|
||
|
||
## Цель работы
|
||
Получить навыки организации обмена информацией между процессами средствами неименованных или именованных каналов в программах на языке C в операционных системах семейства Linux.
|
||
|
||
## Описание задания
|
||
|
||
Лабораторная работа является модификацией лабораторной работы №3, в которой обмен данными между родительской и дочерними программами производится через программные каналы.
|
||
|
||
### Вариант 12
|
||
Программа читает текстовый файл построчно. Для каждой строки первый символ становится ключом, и все вхождения этого символа в строке заменяются пробелами, пока не будет достигнуто максимальное количество замен.
|
||
|
||
## Реализованные решения
|
||
|
||
### 1. Решение с неименованными каналами (pipes)
|
||
|
||
**Файлы:**
|
||
- `parent_pipe.c` - родительская программа
|
||
- `child_pipe.c` - дочерняя программа
|
||
|
||
**Принцип работы:**
|
||
1. Родительский процесс создает три канала для каждого дочернего процесса:
|
||
- `pipe_to_child` - для передачи данных дочернему процессу
|
||
- `pipe_from_child` - для получения обработанных данных
|
||
- `pipe_error` - для получения количества замен
|
||
|
||
2. Родительский процесс:
|
||
- Читает данные из входного файла
|
||
- Передает данные дочернему процессу через `pipe_to_child`
|
||
- Получает обработанные данные через `pipe_from_child`
|
||
- Записывает результат в выходной файл
|
||
|
||
3. Дочерний процесс:
|
||
- Перенаправляет stdin на чтение из канала (dup2)
|
||
- Перенаправляет stdout на запись в канал (dup2)
|
||
- Обрабатывает данные согласно варианту 12
|
||
- Возвращает количество замен через stderr
|
||
|
||
**Преимущества:**
|
||
- Простая реализация для родственных процессов
|
||
- Автоматическая синхронизация через блокирующие операции чтения/записи
|
||
- Нет необходимости в файловых дескрипторах на диске
|
||
|
||
**Недостатки:**
|
||
- Работает только между родственными процессами
|
||
- Ограниченный размер буфера канала
|
||
|
||
### 2. Решение с именованными каналами (FIFO)
|
||
|
||
**Файлы:**
|
||
- `fifo_server.c` - серверная программа
|
||
- `fifo_client.c` - клиентская программа
|
||
|
||
**Принцип работы:**
|
||
1. Сервер создает два именованных канала:
|
||
- `/tmp/fifo_request` - для получения запросов
|
||
- `/tmp/fifo_response` - для отправки ответов
|
||
|
||
2. Клиент:
|
||
- Читает данные из входного файла
|
||
- Отправляет данные серверу через `fifo_request`
|
||
- Получает обработанные данные через `fifo_response`
|
||
- Записывает результат в выходной файл
|
||
|
||
3. Сервер:
|
||
- Ожидает запросы от клиентов
|
||
- Обрабатывает данные согласно варианту 12
|
||
- Отправляет результат обратно клиенту
|
||
|
||
**Преимущества:**
|
||
- Работает между неродственными процессами
|
||
- Клиент-серверная архитектура
|
||
- Возможность обработки запросов от нескольких клиентов
|
||
|
||
**Недостатки:**
|
||
- Более сложная реализация
|
||
- Требуется управление файлами в файловой системе
|
||
- Необходима синхронизация между клиентом и сервером
|
||
|
||
## Компиляция и запуск
|
||
|
||
### Компиляция всех программ
|
||
```bash
|
||
make -f Makefile_lab4 all
|
||
```
|
||
|
||
### Тестирование с неименованными каналами
|
||
```bash
|
||
make -f Makefile_lab4 test_pipes
|
||
```
|
||
|
||
### Тестирование с именованными каналами
|
||
|
||
**Вариант 1: Автоматический тест**
|
||
```bash
|
||
make -f Makefile_lab4 test_fifo_auto
|
||
```
|
||
|
||
**Вариант 2: Ручной запуск в двух терминалах**
|
||
|
||
Терминал 1 (сервер):
|
||
```bash
|
||
make -f Makefile_lab4 test_fifo_server
|
||
```
|
||
|
||
Терминал 2 (клиент):
|
||
```bash
|
||
make -f Makefile_lab4 test_fifo_client
|
||
```
|
||
|
||
### Сравнение с оригинальной версией
|
||
```bash
|
||
make -f Makefile_lab4 test_compare
|
||
```
|
||
|
||
### Запуск всех тестов
|
||
```bash
|
||
make -f Makefile_lab4 test_all
|
||
```
|
||
|
||
## Примеры использования
|
||
|
||
### Неименованные каналы
|
||
```bash
|
||
./parent_pipe ./child_pipe 10 input1.txt output1.txt input2.txt output2.txt
|
||
```
|
||
|
||
### Именованные каналы
|
||
|
||
Запустить сервер:
|
||
```bash
|
||
./fifo_server 10
|
||
```
|
||
|
||
В другом терминале запустить клиент:
|
||
```bash
|
||
./fifo_client input1.txt output1.txt
|
||
./fifo_client input2.txt output2.txt
|
||
```
|
||
|
||
## Обработка исключительных ситуаций
|
||
|
||
Программы предусматривают обработку следующих ошибок:
|
||
- Отсутствие или неверное количество входных параметров
|
||
- Ошибки открытия входного и/или выходного файла
|
||
- Ошибки создания каналов
|
||
- Ошибки создания дочерних процессов
|
||
- Ошибки чтения и записи через каналы
|
||
|
||
## Технические детали
|
||
|
||
### Используемые системные вызовы
|
||
|
||
**Неименованные каналы:**
|
||
- `pipe()` - создание канала
|
||
- `fork()` - создание дочернего процесса
|
||
- `dup2()` - дублирование файлового дескриптора
|
||
- `read()` / `write()` - чтение/запись данных
|
||
- `close()` - закрытие файлового дескриптора
|
||
- `waitpid()` - ожидание завершения дочернего процесса
|
||
- `execl()` - запуск новой программы
|
||
|
||
**Именованные каналы:**
|
||
- `mkfifo()` - создание именованного канала
|
||
- `open()` - открытие FIFO
|
||
- `read()` / `write()` - чтение/запись данных
|
||
- `close()` - закрытие FIFO
|
||
- `unlink()` - удаление 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)
|
||
|
||
1. **Что такое канал (pipe)?**
|
||
- Канал - это механизм межпроцессного взаимодействия (IPC), представляющий собой однонаправленный канал связи между процессами.
|
||
|
||
2. **В чем разница между именованными и неименованными каналами?**
|
||
- Неименованные каналы существуют только в памяти и доступны только родственным процессам
|
||
- Именованные каналы (FIFO) создаются в файловой системе и доступны любым процессам
|
||
|
||
3. **Как создать канал?**
|
||
- Неименованный: `int pipe(int fd[2])`
|
||
- Именованный: `int mkfifo(const char *pathname, mode_t mode)`
|
||
|
||
4. **Что происходит при чтении из пустого канала?**
|
||
- Процесс блокируется до тех пор, пока в канал не будут записаны данные
|
||
|
||
5. **Что происходит при записи в заполненный канал?**
|
||
- Процесс блокируется до тех пор, пока в канале не освободится место
|
||
|
||
6. **Как передать данные через канал?**
|
||
- Используя системные вызовы `write()` для записи и `read()` для чтения
|
||
|
||
7. **Зачем нужно закрывать неиспользуемые концы канала?**
|
||
- Для корректного определения EOF при чтении
|
||
- Для освобождения ресурсов
|
||
- Для предотвращения deadlock
|
||
|
||
## Автор
|
||
Лабораторная работа выполнена в рамках курса "Системное программирование в среде Linux"
|