Files
CS-LABS/lab_4/README_lab4.md
2025-10-28 17:00:14 +07:00

239 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Лабораторная работа №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"