should be the final version of 4

This commit is contained in:
2025-11-26 16:09:00 +07:00
parent 752615f96c
commit a3090c6767
6 changed files with 13 additions and 687 deletions

Binary file not shown.

View File

@@ -16,7 +16,7 @@ fifo_client: fifo_client.c
$(CC) $(CFLAGS) -o $@ $<
# ===== Test files =====
test_files:
files:
@echo "Создание тестовых файлов..."
echo "abbaabbaabbaabbaabbaabbaabbaabba" > input1.txt
echo "xyzxyzxyzxyzxyzxyzxyzxyz" >> input1.txt
@@ -27,17 +27,18 @@ test_files:
echo "ppppython" >> input3.txt
# ===== FIFO tests =====
test_fifo_server: fifo test_files
test_server: fifo files
@echo "=== Запуск FIFO сервера ==="
@echo "В другом терминале выполните: make test_fifo_client"
@echo "\n\n"
./fifo_server 10
test_fifo_client: fifo test_files
@echo "=== Запуск FIFO клиента ===" & \
test_client: fifo files
@echo "=== Запуск FIFO клиента ===\n\n" & \
./fifo_client input1.txt output1_fifo.txt; \
./fifo_client input2.txt output2_fifo.txt; \
./fifo_client input3.txt output3_fifo.txt;
@echo "\n=== Результаты FIFO ==="
@echo "\n=== Результаты FIFO ===\n"
@echo "--- output1_fifo.txt ---"
@cat output1_fifo.txt || true
@echo "\n--- output2_fifo.txt ---"
@@ -45,35 +46,6 @@ test_fifo_client: fifo test_files
@echo "\n--- output3_fifo.txt ---"
@cat output3_fifo.txt || true
# Automatic FIFO test (server in background)
test_all: fifo test_files
@echo "=== Автоматический тест FIFO ==="
@./fifo_server 10 & \
SERVER_PID=$$!; \
sleep 1; \
./fifo_client input1.txt output1_fifo.txt; \
./fifo_client input2.txt output2_fifo.txt; \
./fifo_client input3.txt output3_fifo.txt; \
kill $$SERVER_PID 2>/dev/null || true; \
wait $$SERVER_PID 2>/dev/null || true
@echo "\n=== Результаты FIFO ==="
@echo "--- output1_fifo.txt ---"
@cat output1_fifo.txt || true
@echo "\n--- output2_fifo.txt ---"
@cat output2_fifo.txt || true
@echo "\n--- output3_fifo.txt ---"
@cat output3_fifo.txt || true
# Error handling test for FIFO
test_error: fifo
@echo "\n=== Тест обработки ошибки (несуществующий файл) - FIFO ==="
@./fifo_server 5 & \
SERVER_PID=$$!; \
sleep 1; \
./fifo_client nonexistent.txt output_error.txt || true; \
kill $$SERVER_PID 2>/dev/null || true; \
wait $$SERVER_PID 2>/dev/null || true
# Cleanup
clean:
@echo "Очистка..."
@@ -85,15 +57,11 @@ clean:
# Help
help:
@echo "Available targets:"
@echo " all - Build FIFO programs"
@echo " fifo - Compile fifo_server and fifo_client"
@echo " test_files - Create test input files"
@echo " test_fifo_server - Run FIFO server (use client in another terminal)"
@echo " test_fifo_client - Run FIFO client and show results"
@echo " test_all - Automatic FIFO test (server in background)"
@echo " test_error - Error handling test (nonexistent file)"
@echo " clean - Remove built files and test files"
@echo " help - Show this help"
@echo " fifo - Compile fifo_server and fifo_client"
@echo " files - Create test input files"
@echo " test_server - Run FIFO server (use client in another terminal)"
@echo " test_client - Run FIFO client and show results
@echo " clean - Remove built files and test files"
@echo " help - Show this help"
.PHONY: all fifo test_files test_fifo_server test_fifo_client test_all \
test_error clean help
.PHONY: all fifo files test_server test_client clean help

View File

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

View File

@@ -1,5 +1,3 @@
// fifo_client.c - Клиентская программа с использованием именованных каналов (FIFO)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

View File

@@ -1,6 +1,3 @@
// fifo_server.c - Серверная программа с использованием именованных каналов (FIFO)
// Вариант повышенной сложности для Lab 4
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

View File

@@ -1,399 +0,0 @@
# Инструкция по запуску Лабораторной работы №4
## Быстрый старт
### 1. Подготовка файлов
Создайте рабочую директорию и поместите в неё следующие файлы:
- `parent_pipe.c` - родительская программа (pipes)
- `child_pipe.c` - дочерняя программа (pipes)
- `fifo_server.c` - серверная программа (FIFO)
- `fifo_client.c` - клиентская программа (FIFO)
- `Makefile_lab4` - Makefile для компиляции
- Оригинальные файлы: `parent.c`, `lab1_var12.c`, `Makefile` (для сравнения)
### 2. Компиляция
```bash
# Компилировать все программы
make -f Makefile_lab4 all
# Или компилировать отдельно:
make -f Makefile_lab4 pipes # Только pipes
make -f Makefile_lab4 fifo # Только FIFO
make -f Makefile_lab4 original # Оригинальная версия
```
### 3. Автоматическое тестирование
```bash
# Тест с неименованными каналами (pipes)
make -f Makefile_lab4 test_pipes
# Автоматический тест с именованными каналами (FIFO)
make -f Makefile_lab4 test_fifo_auto
# Сравнение с оригинальной версией
make -f Makefile_lab4 test_compare
# Запустить все тесты
make -f Makefile_lab4 test_all
```
## Подробные инструкции
### Вариант 1: Неименованные каналы (Pipes)
#### Компиляция
```bash
gcc -Wall -Wextra -std=c99 -g -o parent_pipe parent_pipe.c
gcc -Wall -Wextra -std=c99 -g -o child_pipe child_pipe.c
```
#### Создание тестовых файлов
```bash
echo "abbaabbaabbaabbaabbaabbaabbaabba" > input1.txt
echo "xyzxyzxyzxyzxyzxyzxyzxyz" >> input1.txt
echo "hello world hello" >> input1.txt
echo "testtest" > input2.txt
echo "aaaaaaa" >> input2.txt
echo "programming" > input3.txt
echo "ppppython" >> input3.txt
```
#### Запуск
```bash
# Формат: ./parent_pipe <child_program> <max_replacements> <in1> <out1> [<in2> <out2> ...]
# Обработка одного файла
./parent_pipe ./child_pipe 10 input1.txt output1.txt
# Обработка нескольких файлов параллельно
./parent_pipe ./child_pipe 10 input1.txt output1.txt input2.txt output2.txt input3.txt output3.txt
# Разные лимиты замен
./parent_pipe ./child_pipe 5 input1.txt output1_5.txt
./parent_pipe ./child_pipe 20 input1.txt output1_20.txt
```
#### Просмотр результатов
```bash
cat output1.txt
cat output2.txt
cat output3.txt
```
### Вариант 2: Именованные каналы (FIFO)
#### Компиляция
```bash
gcc -Wall -Wextra -std=c99 -g -o fifo_server fifo_server.c
gcc -Wall -Wextra -std=c99 -g -o fifo_client fifo_client.c
```
#### Вариант 2.1: Запуск в двух терминалах
**Терминал 1 (Сервер):**
```bash
./fifo_server 10
```
Сервер запустится и будет ожидать подключения клиентов.
**Терминал 2 (Клиент):**
```bash
# Формат: ./fifo_client <input_file> <output_file>
./fifo_client input1.txt output1_fifo.txt
./fifo_client input2.txt output2_fifo.txt
./fifo_client input3.txt output3_fifo.txt
```
После обработки всех файлов остановите сервер: Ctrl+C в терминале 1.
#### Вариант 2.2: Автоматический запуск (одна команда)
```bash
# Сервер запустится в фоне, обработает запросы и автоматически остановится
make -f Makefile_lab4 test_fifo_auto
```
#### Вариант 2.3: Ручной запуск в фоне
```bash
# Запустить сервер в фоне
./fifo_server 10 &
SERVER_PID=$!
# Подождать запуска сервера
sleep 1
# Отправить запросы
./fifo_client input1.txt output1_fifo.txt
./fifo_client input2.txt output2_fifo.txt
./fifo_client input3.txt output3_fifo.txt
# Остановить сервер
kill $SERVER_PID
```
## Тестирование обработки ошибок
### Несуществующий входной файл
```bash
# Pipes
./parent_pipe ./child_pipe 5 nonexistent.txt output.txt
# FIFO
./fifo_server 5 &
sleep 1
./fifo_client nonexistent.txt output.txt
killall fifo_server
```
### Неверное количество аргументов
```bash
# Недостаточно аргументов
./parent_pipe ./child_pipe 5
# Нечетное количество файлов
./parent_pipe ./child_pipe 5 input1.txt
```
### Клиент без сервера (FIFO)
```bash
# Попытка подключиться при выключенном сервере
./fifo_client input1.txt output1.txt
# Ожидается: "ERROR: Не удалось открыть FIFO запроса"
```
## Сравнение результатов
### Сравнение pipes vs original
```bash
# Запустить обе версии
./parent_pipe ./child_pipe 10 input1.txt output1_pipe.txt
./parent ./lab1_var12 10 input1.txt output1_orig.txt
# Сравнить результаты
diff output1_pipe.txt output1_orig.txt
# Если различий нет - программа работает корректно
```
### Сравнение FIFO vs pipes
```bash
# Pipes
./parent_pipe ./child_pipe 10 input1.txt output1_pipe.txt
# FIFO
./fifo_server 10 &
sleep 1
./fifo_client input1.txt output1_fifo.txt
killall fifo_server
# Сравнение
diff output1_pipe.txt output1_fifo.txt
```
## Анализ работы программ
### Просмотр процессов
```bash
# Во время работы parent_pipe в другом терминале:
ps aux | grep child_pipe
ps aux | grep parent_pipe
# Просмотр открытых файловых дескрипторов
lsof -c parent_pipe
lsof -c child_pipe
```
### Просмотр FIFO файлов
```bash
# Во время работы сервера:
ls -la /tmp/fifo_*
# Информация о типе файла
file /tmp/fifo_request
file /tmp/fifo_response
```
### Трассировка системных вызовов
```bash
# Трассировка работы с каналами
strace -e trace=pipe,read,write,fork,execl ./parent_pipe ./child_pipe 10 input1.txt output1.txt
# Трассировка FIFO операций
strace -e trace=open,read,write,mkfifo ./fifo_server 10
```
## Очистка
```bash
# Удалить скомпилированные программы и тестовые файлы
make -f Makefile_lab4 clean
# Или вручную:
rm -f parent_pipe child_pipe fifo_server fifo_client
rm -f parent lab1_var12
rm -f input*.txt output*.txt
rm -f /tmp/fifo_request /tmp/fifo_response
```
## Типичные проблемы и решения
### Проблема 1: "Permission denied" при запуске
**Решение:**
```bash
chmod +x parent_pipe child_pipe fifo_server fifo_client
```
### Проблема 2: FIFO клиент зависает
**Причина:** Сервер не запущен.
**Решение:** Убедитесь, что сервер запущен:
```bash
ps aux | grep fifo_server
```
### Проблема 3: "Address already in use" для FIFO
**Причина:** FIFO файлы остались после некорректного завершения.
**Решение:**
```bash
rm -f /tmp/fifo_request /tmp/fifo_response
```
### Проблема 4: Зомби-процессы
**Причина:** Родительский процесс не вызвал wait() для дочерних.
**Решение:** В коде уже реализован waitpid(), но если проблема возникла:
```bash
# Просмотр зомби
ps aux | grep defunct
# Завершить родительский процесс
killall parent_pipe
```
### Проблема 5: Broken pipe
**Причина:** Попытка записи в канал, у которого закрыт конец для чтения.
**Решение:** Убедитесь, что оба конца канала правильно настроены и дочерний процесс не завершился преждевременно.
## Дополнительные команды
### Справка по использованию
```bash
# Показать все доступные команды Makefile
make -f Makefile_lab4 help
```
### Компиляция с отладочной информацией
```bash
# Уже включено флагом -g, запуск с gdb:
gdb ./parent_pipe
(gdb) run ./child_pipe 10 input1.txt output1.txt
```
### Проверка утечек памяти
```bash
# Для pipes
valgrind --leak-check=full ./parent_pipe ./child_pipe 10 input1.txt output1.txt
# Для FIFO сервера
valgrind --leak-check=full ./fifo_server 10
```
## Примеры вывода
### Успешное выполнение pipes
```
=== Запуск родительского процесса с каналами ===
Родительский PID: 12345
Программа для запуска: ./child_pipe
Максимум замен: 10
Количество файловых пар: 2
Создание процесса 1 для файлов: input1.txt -> output1.txt
Создание процесса 2 для файлов: input2.txt -> output2.txt
=== Обработка файлов через каналы ===
Обработка процесса PID=12346 (input1.txt -> output1.txt)
Отправлено байт: 87
Получено байт: 87
Количество замен: 10
Статус: SUCCESS
Обработка процесса PID=12347 (input2.txt -> output2.txt)
Отправлено байт: 17
Получено байт: 17
Количество замен: 6
Статус: SUCCESS
=== Итоговая статистика ===
Всего запущено процессов: 2
Успешно завершено: 2
Завершено с ошибкой: 0
ОБЩИЙ СТАТУС: Все процессы завершены успешно
```
### Успешное выполнение FIFO
```
=== FIFO Server запущен ===
Server PID: 12350
Максимум замен: 10
FIFO каналы созданы:
Request: /tmp/fifo_request
Response: /tmp/fifo_response
Ожидание запросов от клиентов...
Получен запрос: 87 байт
Выполнено замен: 10
Отправлен ответ: 87 байт
```
```
=== FIFO Client ===
Client PID: 12351
Входной файл: input1.txt
Выходной файл: output1.txt
Прочитано байт из файла: 87
Отправка запроса серверу...
Отправлено байт: 87
Ожидание ответа от сервера...
Получено байт от сервера: 100
Записано байт в выходной файл: 87
Количество выполненных замен: 10
Обработка завершена успешно!
```
## Контакты и поддержка
При возникновении вопросов обратитесь к:
- Отчету лабораторной работы (PDF)
- Комментариям в исходном коде
- Документации Linux man pages: `man pipe`, `man mkfifo`, `man fork`, `man dup2`