#include // printf, fprintf #include // malloc, free, exit #include // strlen, strerror, strstr, sscanf #include // read, write, close, getpid #include // open, O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC #include // типы для системных вызовов #include // константы прав доступа (S_IRUSR и т.п.) #include // errno и коды ошибок [web:17] #define FIFO_REQUEST "/tmp/fifo_request" // путь к FIFO для запроса клиент→сервер #define FIFO_RESPONSE "/tmp/fifo_response" // путь к FIFO для ответа сервер→клиент #define BUFFER_SIZE 4096 // размер буфера для обмена данными // Печать подсказки по использованию программы void print_usage(const char *progname) { fprintf(stderr, "Usage: %s \n", progname); fprintf(stderr, "Example: %s input.txt output.txt\n", progname); } int main(int argc, char *argv[]) { // Проверка числа аргументов командной строки if (argc != 3) { fprintf(stderr, "ERROR: Неверное количество аргументов\n"); print_usage(argv[0]); return 1; } // Имена входного и выходного файлов берём из аргументов const char *input_file = argv[1]; const char *output_file = argv[2]; // Информационное сообщение о запуске клиента printf("=== FIFO Client ===\n"); printf("Client PID: %d\n", getpid()); printf("Входной файл: %s\n", input_file); printf("Выходной файл: %s\n", output_file); // Открываем входной файл для чтения int in_fd = open(input_file, O_RDONLY); if (in_fd < 0) { fprintf(stderr, "ERROR: Не удалось открыть входной файл %s: %s\n", input_file, strerror(errno)); return 1; } // Выделяем буфер под содержимое файла и обмен с сервером char *buffer = malloc(BUFFER_SIZE); if (!buffer) { fprintf(stderr, "ERROR: Не удалось выделить память\n"); close(in_fd); return 1; } // Читаем данные из входного файла (не более BUFFER_SIZE-1, оставляем место под '\0') ssize_t bytes_read = read(in_fd, buffer, BUFFER_SIZE - 1); close(in_fd); if (bytes_read < 0) { fprintf(stderr, "ERROR: Не удалось прочитать файл: %s\n", strerror(errno)); free(buffer); return 1; } // Делаем буфер временно C-строкой для отладочного вывода buffer[bytes_read] = '\0'; printf("Прочитано байт из файла: %zd\n", bytes_read); // Открываем FIFO запроса на запись (ожидается, что сервер уже создал FIFO и слушает) printf("Отправка запроса серверу...\n"); int fd_req = open(FIFO_REQUEST, O_WRONLY); if (fd_req == -1) { fprintf(stderr, "ERROR: Не удалось открыть FIFO запроса: %s\n", strerror(errno)); fprintf(stderr, "Убедитесь, что сервер запущен!\n"); free(buffer); return 1; } // Отправляем прочитанные из файла данные серверу по FIFO запроса ssize_t bytes_written = write(fd_req, buffer, bytes_read); close(fd_req); if (bytes_written != bytes_read) { fprintf(stderr, "ERROR: Ошибка отправки данных\n"); free(buffer); return 1; } printf("Отправлено байт: %zd\n", bytes_written); // Открываем FIFO ответа на чтение, чтобы получить обработанные данные от сервера printf("Ожидание ответа от сервера...\n"); int fd_resp = open(FIFO_RESPONSE, O_RDONLY); if (fd_resp == -1) { fprintf(stderr, "ERROR: Не удалось открыть FIFO ответа: %s\n", strerror(errno)); free(buffer); return 1; } // Читаем ответ сервера в тот же буфер ssize_t response_bytes = read(fd_resp, buffer, BUFFER_SIZE - 1); close(fd_resp); if (response_bytes < 0) { fprintf(stderr, "ERROR: Ошибка чтения ответа\n"); free(buffer); return 1; } // Делает ответ строкой для поиска служебной части с количеством замен buffer[response_bytes] = '\0'; printf("Получено байт от сервера: %zd\n", response_bytes); // В протоколе ответа сервер дописывает в конец строку вида "\nREPLACEMENTS:<число>" // Ищем начало этой служебной информации char *replacements_info = strstr(buffer, "\nREPLACEMENTS:"); long long replacements = 0; if (replacements_info) { // Считываем количество замен из служебной части sscanf(replacements_info, "\nREPLACEMENTS:%lld", &replacements); // Обрезаем строку в месте начала служебной части, оставляя только полезные данные *replacements_info = '\0'; // Пересчитываем длину полезных данных как количество байт до служебного блока response_bytes = replacements_info - buffer; } // Открываем (или создаём) выходной файл с правами rw-rw-rw- int out_fd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (out_fd < 0) { fprintf(stderr, "ERROR: Не удалось открыть выходной файл %s: %s\n", output_file, strerror(errno)); free(buffer); return 1; } // Записываем в выходной файл только содержимое (без служебной части REPLACEMENTS) ssize_t written = write(out_fd, buffer, response_bytes); close(out_fd); if (written != response_bytes) { fprintf(stderr, "ERROR: Ошибка записи в выходной файл\n"); free(buffer); return 1; } // Информационные сообщения об успешной обработке printf("Записано байт в выходной файл: %zd\n", written); printf("Количество выполненных замен: %lld\n", replacements); printf("\nОбработка завершена успешно!\n"); // Освобождение выделенной памяти и нормальное завершение free(buffer); return 0; }