From 71dfd554f85fe285171caea65405412c029e4364 Mon Sep 17 00:00:00 2001 From: pajjilykk Date: Thu, 11 Dec 2025 09:11:32 +0700 Subject: [PATCH] 6-mie commented --- mine/lab_6/client.c | 72 ++++++++----------- mine/lab_6/server.c | 165 ++++++++++++++++++-------------------------- 2 files changed, 96 insertions(+), 141 deletions(-) diff --git a/mine/lab_6/client.c b/mine/lab_6/client.c index f5f219b..79277b8 100644 --- a/mine/lab_6/client.c +++ b/mine/lab_6/client.c @@ -1,36 +1,34 @@ -// client.c // Клиент POSIX IPC: читает строки из input.txt, передаёт их серверу через -// разделяемую память и выводит обработанные строки на stdout. [file:21][web:57] +// POSIX shared memory и синхронизируется с сервером через именованные семафоры. -#include // printf, fprintf, perror, FILE, fopen, fclose, fgets [web:60] -#include // exit, EXIT_FAILURE -#include // memset, strncpy, strlen -#include // errno -#include // O_RDWR [web:29] -#include // shm_open, mmap, munmap [web:47] -#include // mode_t -#include // sem_t, sem_open, sem_close, sem_wait, sem_post [file:21] -#include // close +#include +#include +#include +#include +#include +#include // shm_open, mmap, munmap — POSIX разделяемая память +#include +#include // sem_open, sem_close, sem_wait, sem_post — POSIX семафоры +#include -// Размер буфера обмена (должен совпадать с server.c). [file:21] +// Размер буфера обмена (должен совпадать с server.c). #define SHM_BUFFER_SIZE 1024 -// Та же структура, что и у сервера. [file:21] +// Структура, находящаяся в POSIX shared memory. typedef struct { - int has_data; // Флаг наличия данных от клиента. [file:21] - int result_code; // Код результата обработки. [file:21] - char buffer[SHM_BUFFER_SIZE]; // Буфер строки. [file:21] + int has_data; + int result_code; + char buffer[SHM_BUFFER_SIZE]; } shared_block_t; int main(int argc, char *argv[]) { - // Ожидаемые аргументы: - // argv[1] - имя shared memory (должно совпадать с сервером). [file:21] - // argv[2] - имя семафора клиента. [file:21] - // argv[3] - имя семафора сервера. [file:21] + // argv[1] - имя POSIX shared memory (должно совпадать с сервером). + // argv[2] - имя именованного семафора клиента. + // argv[3] - имя именованного семафора сервера. if (argc < 4) { fprintf(stderr, "Usage: %s \n", - argv[0]); // Сообщаем о правильном формате запуска. [file:22] + argv[0]); return -1; } @@ -38,14 +36,14 @@ int main(int argc, char *argv[]) { const char *sem_client_name = argv[2]; const char *sem_server_name = argv[3]; - // Открываем существующий объект shared memory, созданный сервером. [web:47] + // Открываем существующий объект POSIX shared memory, созданный сервером (shm_open). int shm_fd = shm_open(shm_name, O_RDWR, 0); if (shm_fd == -1) { perror("shm_open"); return -1; } - // Отображаем shared memory в адресное пространство клиента. [web:47] + // Отображаем POSIX shared memory в адресное пространство клиента (mmap с MAP_SHARED). shared_block_t *shm_ptr = mmap(NULL, sizeof(shared_block_t), PROT_READ | PROT_WRITE, @@ -58,12 +56,12 @@ int main(int argc, char *argv[]) { return -1; } - // Дескриптор можно закрыть, mmap продолжает работать. [file:21] + // После успешного mmap файловый дескриптор POSIX shared memory можно закрыть. if (close(shm_fd) == -1) { perror("close"); } - // Открываем именованные семафоры, которые создал сервер. [file:21][web:40] + // Открываем именованные POSIX семафоры, которые создал сервер (sem_open). sem_t *sem_client = sem_open(sem_client_name, 0); if (sem_client == SEM_FAILED) { perror("sem_open(sem_client)"); @@ -79,7 +77,6 @@ int main(int argc, char *argv[]) { return -1; } - // Открываем файл input.txt для чтения исходных строк. [web:57] FILE *fin = fopen("input.txt", "r"); if (!fin) { perror("fopen(input.txt)"); @@ -89,28 +86,22 @@ int main(int argc, char *argv[]) { return -1; } - char input[SHM_BUFFER_SIZE]; // Локальный буфер для чтения строки. [file:21] + char input[SHM_BUFFER_SIZE]; - // Читаем input.txt построчно до конца файла. [web:51] while (fgets(input, sizeof(input), fin) != NULL) { - size_t len = strlen(input); // Длина считанной строки. [web:54] + size_t len = strlen(input); - // Удаляем конечный '\n', если он есть. [web:54] if (len > 0 && input[len - 1] == '\n') { input[len - 1] = '\0'; } - // Очищаем буфер в shared memory перед записью новой строки. [file:21] memset(shm_ptr->buffer, 0, sizeof(shm_ptr->buffer)); - - // Копируем строку из локального буфера в shared memory. [file:21] strncpy(shm_ptr->buffer, input, SHM_BUFFER_SIZE - 1); shm_ptr->buffer[SHM_BUFFER_SIZE - 1] = '\0'; - // Устанавливаем флаг наличия данных для сервера. [file:21] shm_ptr->has_data = 1; - // Поднимаем семафор клиента, уведомляя сервер. [file:21][web:40] + // Клиент увеличивает семафор клиента (sem_post), разблокируя сервер (sem_wait). if (sem_post(sem_client) == -1) { perror("sem_post(sem_client)"); fclose(fin); @@ -120,7 +111,7 @@ int main(int argc, char *argv[]) { return -1; } - // Ждём, пока сервер обработает строку. [file:21][web:40] + // Клиент блокируется на семафоре сервера (sem_wait), пока сервер не закончит обработку. if (sem_wait(sem_server) == -1) { perror("sem_wait(sem_server)"); fclose(fin); @@ -130,7 +121,6 @@ int main(int argc, char *argv[]) { return -1; } - // Проверяем код результата, выставленный сервером. [file:21] if (shm_ptr->result_code != 0) { fprintf(stderr, "Server reported error, result_code = %d\n", @@ -142,16 +132,14 @@ int main(int argc, char *argv[]) { return -1; } - // Выводим обработанную строку на стандартный вывод. [file:22] printf("%s\n", shm_ptr->buffer); } - // Закрываем input.txt после окончания чтения. [web:57] if (fclose(fin) == EOF) { perror("fclose(input.txt)"); } - // Закрываем семафоры. [file:21] + // Закрываем дескрипторы POSIX семафоров в процессе клиента (sem_close). if (sem_close(sem_client) == -1) { perror("sem_close(sem_client)"); } @@ -159,10 +147,10 @@ int main(int argc, char *argv[]) { perror("sem_close(sem_server)"); } - // Отсоединяем shared memory. [web:47] + // Отсоединяем отображённую область POSIX shared memory (munmap). if (munmap(shm_ptr, sizeof(shared_block_t)) == -1) { perror("munmap"); } - return 0; // Нормальное завершение клиента. [file:22] + return 0; } diff --git a/mine/lab_6/server.c b/mine/lab_6/server.c index 274bf43..7269c97 100644 --- a/mine/lab_6/server.c +++ b/mine/lab_6/server.c @@ -1,114 +1,101 @@ -// server.c -// Сервер POSIX IPC: разделяемая память + именованные семафоры. [file:21] -// - Сам удаляет "висячие" объекты (shm и семафоры) при старте. [file:21] -// - Создаёт новую shared memory и новые именованные семафоры. [web:47][web:40] -// - Обрабатывает строки по варианту 12 и пишет результат в shared memory и output.txt. [file:22] +// Сервер POSIX IPC: использует POSIX shared memory (shm_open + mmap) +// и именованные POSIX семафоры (sem_open, sem_wait, sem_post) для обмена с клиентом. -#include // printf, fprintf, perror, FILE, fopen, fclose, fprintf [web:60] -#include // exit, EXIT_FAILURE, strtoul -#include // memset, strncpy, strlen -#include // errno -#include // O_CREAT, O_EXCL, O_RDWR [web:29] -#include // shm_open, mmap, munmap [web:47] -#include // mode_t, S_IRUSR, S_IWUSR [web:39] -#include // sem_t, sem_open, sem_close, sem_unlink, sem_wait, sem_post [file:21] -#include // ftruncate, close [file:21] -#include // signal, SIGINT, SIGTERM +#include +#include +#include +#include +#include // O_CREAT, O_EXCL, O_RDWR для shm_open +#include // shm_open, mmap, munmap — POSIX разделяемая память +#include // Права доступа к объектам POSIX shared memory и семафорам +#include // POSIX именованные семафоры: sem_open, sem_close, sem_unlink, sem_wait, sem_post +#include // ftruncate, close +#include -// Максимальная длина строки (включая '\0') для обмена через shared memory. [file:21] +// Максимальная длина строки (включая '\0') для обмена через shared memory. #define SHM_BUFFER_SIZE 1024 -// Структура в разделяемой памяти. [file:21] +// Структура расположена целиком в POSIX shared memory и разделяется сервером и клиентом. typedef struct { - int has_data; // 0 - нет данных, 1 - клиент записал строку. [file:21] - int result_code; // 0 - успех, -1 - ошибка обработки. [file:21] - char buffer[SHM_BUFFER_SIZE]; // Буфер, в который клиент пишет, а сервер изменяет. [file:21] + int has_data; + int result_code; + char buffer[SHM_BUFFER_SIZE]; } shared_block_t; -// Глобальные указатели/имена для корректной очистки в обработчике сигналов. [file:21] -static shared_block_t *g_shm_ptr = NULL; // Указатель на mmap(shared memory). [web:47] -static char g_shm_name[256] = ""; // Имя объекта shared memory. [file:21] -static char g_sem_client_name[256] = ""; // Имя семафора клиента. [file:21] -static char g_sem_server_name[256] = ""; // Имя семафора сервера. [file:21] -static sem_t *g_sem_client = NULL; // Дескриптор семафора клиента. [file:21] -static sem_t *g_sem_server = NULL; // Дескриптор семафора сервера. [file:21] -static FILE *g_fout = NULL; // Файл output.txt. [web:57] +// Глобальные объекты, связанные с POSIX shared memory и семафорами. +static shared_block_t *g_shm_ptr = NULL; // Указатель на mmap(shared memory). +static char g_shm_name[256] = ""; // Имя объекта POSIX shared memory (для shm_unlink). +static char g_sem_client_name[256] = ""; // Имя именованного семафора клиента (sem_open/sem_unlink). +static char g_sem_server_name[256] = ""; // Имя именованного семафора сервера (sem_open/sem_unlink). +static sem_t *g_sem_client = NULL; // Дескриптор POSIX семафора клиента. +static sem_t *g_sem_server = NULL; // Дескриптор POSIX семафора сервера. +static FILE *g_fout = NULL; -// Обработчик сигналов для аккуратного завершения (Ctrl+C, kill). [file:21] +// Обработчик сигналов завершения: корректно удаляет POSIX shared memory и семафоры. static void handle_signal(int signo) { - (void) signo; // Неиспользуемый параметр, подавляем предупреждения. [file:21] + (void) signo; - // Пытаемся корректно закрыть семафоры, если они открыты. [file:21] if (g_sem_client) { - sem_close(g_sem_client); // Закрываем дескриптор семафора клиента. [file:21] + sem_close(g_sem_client); g_sem_client = NULL; } if (g_sem_server) { - sem_close(g_sem_server); // Закрываем дескриптор семафора сервера. [file:21] + sem_close(g_sem_server); g_sem_server = NULL; } - // Удаляем именованные семафоры по их именам, если они заданы. [file:21][web:40] + // sem_unlink удаляет именованные POSIX семафоры из системы. if (g_sem_client_name[0] != '\0') { - sem_unlink(g_sem_client_name); // Удаляем именованный семафор клиента. [web:40] + sem_unlink(g_sem_client_name); } if (g_sem_server_name[0] != '\0') { - sem_unlink(g_sem_server_name); // Удаляем именованный семафор сервера. [web:40] + sem_unlink(g_sem_server_name); } - // Если есть активное отображение shared memory, отсоединяем его. [web:47] + // munmap отсоединяет область POSIX shared memory из адресного пространства процесса. if (g_shm_ptr) { - munmap(g_shm_ptr, sizeof(shared_block_t)); // Освобождаем виртуальную память. [web:47] + munmap(g_shm_ptr, sizeof(shared_block_t)); g_shm_ptr = NULL; } - // Удаляем объект shared memory, если имя известно. [web:47] + // shm_unlink удаляет объект POSIX shared memory. if (g_shm_name[0] != '\0') { - shm_unlink(g_shm_name); // Удаляем объект POSIX shared memory. [web:47] + shm_unlink(g_shm_name); } - // Закрываем файл вывода, если он открыт. [web:57] if (g_fout) { - fclose(g_fout); // Закрываем output.txt. [web:57] + fclose(g_fout); g_fout = NULL; } - // Завершаем процесс. [file:21] _exit(0); } -// Обработка строки по варианту 12. [file:22] static void process_line(char *s) { if (s == NULL || s[0] == '\0') { - // Пустой буфер или пустая строка не обрабатываем. [file:21] return; } - char first = s[0]; // Сохраняем первый символ. [file:22] + char first = s[0]; - // Проходим по строке начиная со второго символа. [file:22] for (size_t i = 1; s[i] != '\0'; ++i) { if (s[i] == first) { - // Если символ совпадает с первым, заменяем его на пробел. [file:22] s[i] = ' '; } } } int main(int argc, char *argv[]) { - // Ожидаемые аргументы: - // argv[1] - имя shared memory (например, "/myshm"). [file:21] - // argv[2] - имя семафора клиента (например, "/sem_client"). [file:21] - // argv[3] - имя семафора сервера (например, "/sem_server"). [file:21] - // argv[4] - (опционально) число обрабатываемых строк. [file:22] + // argv[1] - имя POSIX shared memory (например, "/myshm"). + // argv[2] - имя именованного семафора клиента (например, "/sem_client"). + // argv[3] - имя именованного семафора сервера (например, "/sem_server"). if (argc < 4) { fprintf(stderr, "Usage: %s [iterations]\n", - argv[0]); // Выводим подсказку по использованию. [file:22] - return -1; // По заданию -1 при ошибке. [file:22] + argv[0]); + return -1; } - // Сохраняем имена в глобальные переменные для очистки в сигналах. [file:21] strncpy(g_shm_name, argv[1], sizeof(g_shm_name) - 1); strncpy(g_sem_client_name, argv[2], sizeof(g_sem_client_name) - 1); strncpy(g_sem_server_name, argv[3], sizeof(g_sem_server_name) - 1); @@ -116,12 +103,11 @@ int main(int argc, char *argv[]) { g_sem_client_name[sizeof(g_sem_client_name) - 1] = '\0'; g_sem_server_name[sizeof(g_sem_server_name) - 1] = '\0'; - const char *shm_name = g_shm_name; // Удобные локальные псевдонимы. [file:21] + const char *shm_name = g_shm_name; const char *sem_client_name = g_sem_client_name; const char *sem_server_name = g_sem_server_name; - // Разбираем количество итераций (строк), если указано. [file:22] - int iterations = -1; // -1 означает "работать до сигнала". [file:22] + int iterations = -1; if (argc >= 5) { char *endptr = NULL; unsigned long tmp = strtoul(argv[4], &endptr, 10); @@ -132,16 +118,15 @@ int main(int argc, char *argv[]) { iterations = (int) tmp; } - // Настраиваем обработчики сигналов для аккуратного завершения. [file:21] - signal(SIGINT, handle_signal); // Обработка Ctrl+C. [file:21] - signal(SIGTERM, handle_signal); // Обработка внешнего kill. [file:21] + signal(SIGINT, handle_signal); + signal(SIGTERM, handle_signal); - // Пытаемся удалить старые IPC-объекты, если они остались от прошлых запусков. [file:21] - shm_unlink(shm_name); // Игнорируем ошибку, если не существует. [web:47] - sem_unlink(sem_client_name); // То же для семафоров. [web:40] + // Удаляем старые объекты POSIX shared memory и семафоров, если они остались от прошлых запусков. + shm_unlink(shm_name); + sem_unlink(sem_client_name); sem_unlink(sem_server_name); - // Создаём новый объект shared memory. [web:47] + // Создаём новый объект POSIX shared memory (shm_open с O_CREAT | O_EXCL | O_RDWR). int shm_fd = shm_open(shm_name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); @@ -150,7 +135,7 @@ int main(int argc, char *argv[]) { return -1; } - // Устанавливаем размер shared memory под нашу структуру. [file:21] + // ftruncate задаёт размер объекта POSIX shared memory под нашу структуру. if (ftruncate(shm_fd, sizeof(shared_block_t)) == -1) { perror("ftruncate"); close(shm_fd); @@ -158,7 +143,7 @@ int main(int argc, char *argv[]) { return -1; } - // Отображаем shared memory в адресное пространство сервера. [web:47] + // Отображаем POSIX shared memory в адресное пространство сервера (mmap с MAP_SHARED). g_shm_ptr = mmap(NULL, sizeof(shared_block_t), PROT_READ | PROT_WRITE, @@ -173,22 +158,20 @@ int main(int argc, char *argv[]) { return -1; } - // Закрываем файловый дескриптор, оставляем только mmap. [file:21] + // После успешного mmap файловый дескриптор POSIX shared memory можно закрыть. if (close(shm_fd) == -1) { perror("close"); - // Продолжаем работу, так как mmap уже есть. [file:21] } - // Инициализируем структуру в shared memory. [file:21] g_shm_ptr->has_data = 0; g_shm_ptr->result_code = 0; memset(g_shm_ptr->buffer, 0, sizeof(g_shm_ptr->buffer)); - // Создаём именованный семафор клиента (клиент будет делать post, сервер - wait). [file:21][web:40] + // Создаём именованный семафор клиента: клиент будет делать sem_post, сервер — sem_wait. g_sem_client = sem_open(sem_client_name, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, - 0); // Начальное значение 0. [file:21] + 0); // начальное значение 0, сервер сразу блокируется на sem_wait. if (g_sem_client == SEM_FAILED) { perror("sem_open(sem_client)"); g_sem_client = NULL; @@ -198,11 +181,11 @@ int main(int argc, char *argv[]) { return -1; } - // Создаём именованный семафор сервера (сервер post, клиент wait). [file:21][web:40] + // Создаём именованный семафор сервера: сервер делает sem_post, клиент — sem_wait. g_sem_server = sem_open(sem_server_name, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, - 0); // Начальное значение 0. [file:21] + 0); if (g_sem_server == SEM_FAILED) { perror("sem_open(sem_server)"); sem_close(g_sem_client); @@ -214,50 +197,41 @@ int main(int argc, char *argv[]) { return -1; } - // Открываем файл вывода для записи всех обработанных строк. [web:57] g_fout = fopen("output.txt", "w"); if (!g_fout) { perror("fopen(output.txt)"); - // Если файл не открылся, продолжаем работать только через shared memory. [file:21] } - int processed_count = 0; // Счётчик успешно обработанных строк. [file:22] + int processed_count = 0; - // Основной цикл обработки запросов от клиента. [file:22] while (iterations < 0 || processed_count < iterations) { - // Ждём, пока клиент поднимет семафор клиента. [file:21][web:40] + // Сервер блокируется на семафоре клиента (sem_wait), ожидая данных в shared memory. if (sem_wait(g_sem_client) == -1) { perror("sem_wait(sem_client)"); processed_count = -1; break; } - // Проверяем, что клиент установил флаг has_data. [file:21] if (!g_shm_ptr->has_data) { fprintf(stderr, "Warning: sem_client posted, but has_data == 0\n"); g_shm_ptr->result_code = -1; } else { - // Обрабатываем строку по варианту 12. [file:22] process_line(g_shm_ptr->buffer); - // Сохраняем код успешной обработки. [file:21] g_shm_ptr->result_code = 0; - // Если файл открыт, дублируем результат в output.txt. [web:57] if (g_fout) { fprintf(g_fout, "%s\n", g_shm_ptr->buffer); fflush(g_fout); } - // Сбрасываем флаг наличия данных. [file:21] g_shm_ptr->has_data = 0; - // Увеличиваем счётчик обработанных строк. [file:22] processed_count++; } - // Сигнализируем клиенту, что результат готов. [file:21][web:40] + // Сервер увеличивает семафор сервера (sem_post), разблокируя клиента (sem_wait). if (sem_post(g_sem_server) == -1) { perror("sem_post(sem_server)"); processed_count = -1; @@ -265,7 +239,6 @@ int main(int argc, char *argv[]) { } } - // Если файл вывода был открыт, закрываем его. [web:57] if (g_fout) { if (fclose(g_fout) == EOF) { perror("fclose(output.txt)"); @@ -273,14 +246,9 @@ int main(int argc, char *argv[]) { g_fout = NULL; } - // Выводим количество выполненных операций или -1 при ошибке. [file:22] - if (processed_count >= 0) { - printf("%d\n", processed_count); - } else { - printf("-1\n"); - } + printf("%d\n", processed_count >= 0 ? processed_count : -1); - // Корректно закрываем семафоры. [file:21] + // Закрываем дескрипторы POSIX семафоров в процессе сервера. if (g_sem_client) { if (sem_close(g_sem_client) == -1) { perror("sem_close(sem_client)"); @@ -294,7 +262,7 @@ int main(int argc, char *argv[]) { g_sem_server = NULL; } - // Удаляем именованные семафоры. [file:21][web:40] + // sem_unlink полностью удаляет именованные семафоры из системы. if (sem_unlink(sem_client_name) == -1) { perror("sem_unlink(sem_client)"); } @@ -302,7 +270,7 @@ int main(int argc, char *argv[]) { perror("sem_unlink(sem_server)"); } - // Отсоединяем shared memory. [web:47] + // Отсоединяем область POSIX shared memory и удаляем сам объект. if (g_shm_ptr) { if (munmap(g_shm_ptr, sizeof(shared_block_t)) == -1) { perror("munmap"); @@ -310,10 +278,9 @@ int main(int argc, char *argv[]) { g_shm_ptr = NULL; } - // Удаляем объект shared memory. [web:47] if (shm_unlink(shm_name) == -1) { perror("shm_unlink"); } - return 0; // Нормальное завершение сервера. [file:22] + return 0; }