working lab4 mine

This commit is contained in:
2025-10-28 17:00:14 +07:00
parent 3371a1b8de
commit baeb8392e6
6 changed files with 1057 additions and 0 deletions

238
lab_4/README_lab4.md Normal file
View File

@@ -0,0 +1,238 @@
# Лабораторная работа №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"