6-mie commented

This commit is contained in:
2025-12-11 09:11:32 +07:00
parent 6cd4088087
commit 71dfd554f8
2 changed files with 96 additions and 141 deletions

View File

@@ -1,36 +1,34 @@
// client.c
// Клиент POSIX IPC: читает строки из input.txt, передаёт их серверу через // Клиент POSIX IPC: читает строки из input.txt, передаёт их серверу через
// разделяемую память и выводит обработанные строки на stdout. [file:21][web:57] // POSIX shared memory и синхронизируется с сервером через именованные семафоры.
#include <stdio.h> // printf, fprintf, perror, FILE, fopen, fclose, fgets [web:60] #include <stdio.h>
#include <stdlib.h> // exit, EXIT_FAILURE #include <stdlib.h>
#include <string.h> // memset, strncpy, strlen #include <string.h>
#include <errno.h> // errno #include <errno.h>
#include <fcntl.h> // O_RDWR [web:29] #include <fcntl.h>
#include <sys/mman.h> // shm_open, mmap, munmap [web:47] #include <sys/mman.h> // shm_open, mmap, munmap — POSIX разделяемая память
#include <sys/stat.h> // mode_t #include <sys/stat.h>
#include <semaphore.h> // sem_t, sem_open, sem_close, sem_wait, sem_post [file:21] #include <semaphore.h> // sem_open, sem_close, sem_wait, sem_post — POSIX семафоры
#include <unistd.h> // close #include <unistd.h>
// Размер буфера обмена (должен совпадать с server.c). [file:21] // Размер буфера обмена (должен совпадать с server.c).
#define SHM_BUFFER_SIZE 1024 #define SHM_BUFFER_SIZE 1024
// Та же структура, что и у сервера. [file:21] // Структура, находящаяся в POSIX shared memory.
typedef struct { typedef struct {
int has_data; // Флаг наличия данных от клиента. [file:21] int has_data;
int result_code; // Код результата обработки. [file:21] int result_code;
char buffer[SHM_BUFFER_SIZE]; // Буфер строки. [file:21] char buffer[SHM_BUFFER_SIZE];
} shared_block_t; } shared_block_t;
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// Ожидаемые аргументы: // argv[1] - имя POSIX shared memory (должно совпадать с сервером).
// argv[1] - имя shared memory (должно совпадать с сервером). [file:21] // argv[2] - имя именованного семафора клиента.
// argv[2] - имя семафора клиента. [file:21] // argv[3] - имя именованного семафора сервера.
// argv[3] - имя семафора сервера. [file:21]
if (argc < 4) { if (argc < 4) {
fprintf(stderr, fprintf(stderr,
"Usage: %s <shm_name> <sem_client_name> <sem_server_name>\n", "Usage: %s <shm_name> <sem_client_name> <sem_server_name>\n",
argv[0]); // Сообщаем о правильном формате запуска. [file:22] argv[0]);
return -1; return -1;
} }
@@ -38,14 +36,14 @@ int main(int argc, char *argv[]) {
const char *sem_client_name = argv[2]; const char *sem_client_name = argv[2];
const char *sem_server_name = argv[3]; 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); int shm_fd = shm_open(shm_name, O_RDWR, 0);
if (shm_fd == -1) { if (shm_fd == -1) {
perror("shm_open"); perror("shm_open");
return -1; return -1;
} }
// Отображаем shared memory в адресное пространство клиента. [web:47] // Отображаем POSIX shared memory в адресное пространство клиента (mmap с MAP_SHARED).
shared_block_t *shm_ptr = mmap(NULL, shared_block_t *shm_ptr = mmap(NULL,
sizeof(shared_block_t), sizeof(shared_block_t),
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
@@ -58,12 +56,12 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
// Дескриптор можно закрыть, mmap продолжает работать. [file:21] // После успешного mmap файловый дескриптор POSIX shared memory можно закрыть.
if (close(shm_fd) == -1) { if (close(shm_fd) == -1) {
perror("close"); perror("close");
} }
// Открываем именованные семафоры, которые создал сервер. [file:21][web:40] // Открываем именованные POSIX семафоры, которые создал сервер (sem_open).
sem_t *sem_client = sem_open(sem_client_name, 0); sem_t *sem_client = sem_open(sem_client_name, 0);
if (sem_client == SEM_FAILED) { if (sem_client == SEM_FAILED) {
perror("sem_open(sem_client)"); perror("sem_open(sem_client)");
@@ -79,7 +77,6 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
// Открываем файл input.txt для чтения исходных строк. [web:57]
FILE *fin = fopen("input.txt", "r"); FILE *fin = fopen("input.txt", "r");
if (!fin) { if (!fin) {
perror("fopen(input.txt)"); perror("fopen(input.txt)");
@@ -89,28 +86,22 @@ int main(int argc, char *argv[]) {
return -1; 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) { 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') { if (len > 0 && input[len - 1] == '\n') {
input[len - 1] = '\0'; input[len - 1] = '\0';
} }
// Очищаем буфер в shared memory перед записью новой строки. [file:21]
memset(shm_ptr->buffer, 0, sizeof(shm_ptr->buffer)); memset(shm_ptr->buffer, 0, sizeof(shm_ptr->buffer));
// Копируем строку из локального буфера в shared memory. [file:21]
strncpy(shm_ptr->buffer, input, SHM_BUFFER_SIZE - 1); strncpy(shm_ptr->buffer, input, SHM_BUFFER_SIZE - 1);
shm_ptr->buffer[SHM_BUFFER_SIZE - 1] = '\0'; shm_ptr->buffer[SHM_BUFFER_SIZE - 1] = '\0';
// Устанавливаем флаг наличия данных для сервера. [file:21]
shm_ptr->has_data = 1; shm_ptr->has_data = 1;
// Поднимаем семафор клиента, уведомляя сервер. [file:21][web:40] // Клиент увеличивает семафор клиента (sem_post), разблокируя сервер (sem_wait).
if (sem_post(sem_client) == -1) { if (sem_post(sem_client) == -1) {
perror("sem_post(sem_client)"); perror("sem_post(sem_client)");
fclose(fin); fclose(fin);
@@ -120,7 +111,7 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
// Ждём, пока сервер обработает строку. [file:21][web:40] // Клиент блокируется на семафоре сервера (sem_wait), пока сервер не закончит обработку.
if (sem_wait(sem_server) == -1) { if (sem_wait(sem_server) == -1) {
perror("sem_wait(sem_server)"); perror("sem_wait(sem_server)");
fclose(fin); fclose(fin);
@@ -130,7 +121,6 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
// Проверяем код результата, выставленный сервером. [file:21]
if (shm_ptr->result_code != 0) { if (shm_ptr->result_code != 0) {
fprintf(stderr, fprintf(stderr,
"Server reported error, result_code = %d\n", "Server reported error, result_code = %d\n",
@@ -142,16 +132,14 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
// Выводим обработанную строку на стандартный вывод. [file:22]
printf("%s\n", shm_ptr->buffer); printf("%s\n", shm_ptr->buffer);
} }
// Закрываем input.txt после окончания чтения. [web:57]
if (fclose(fin) == EOF) { if (fclose(fin) == EOF) {
perror("fclose(input.txt)"); perror("fclose(input.txt)");
} }
// Закрываем семафоры. [file:21] // Закрываем дескрипторы POSIX семафоров в процессе клиента (sem_close).
if (sem_close(sem_client) == -1) { if (sem_close(sem_client) == -1) {
perror("sem_close(sem_client)"); perror("sem_close(sem_client)");
} }
@@ -159,10 +147,10 @@ int main(int argc, char *argv[]) {
perror("sem_close(sem_server)"); perror("sem_close(sem_server)");
} }
// Отсоединяем shared memory. [web:47] // Отсоединяем отображённую область POSIX shared memory (munmap).
if (munmap(shm_ptr, sizeof(shared_block_t)) == -1) { if (munmap(shm_ptr, sizeof(shared_block_t)) == -1) {
perror("munmap"); perror("munmap");
} }
return 0; // Нормальное завершение клиента. [file:22] return 0;
} }

View File

@@ -1,114 +1,101 @@
// server.c // Сервер POSIX IPC: использует POSIX shared memory (shm_open + mmap)
// Сервер POSIX IPC: разделяемая память + именованные семафоры. [file:21] // и именованные POSIX семафоры (sem_open, sem_wait, sem_post) для обмена с клиентом.
// - Сам удаляет "висячие" объекты (shm и семафоры) при старте. [file:21]
// - Создаёт новую shared memory и новые именованные семафоры. [web:47][web:40]
// - Обрабатывает строки по варианту 12 и пишет результат в shared memory и output.txt. [file:22]
#include <stdio.h> // printf, fprintf, perror, FILE, fopen, fclose, fprintf [web:60] #include <stdio.h>
#include <stdlib.h> // exit, EXIT_FAILURE, strtoul #include <stdlib.h>
#include <string.h> // memset, strncpy, strlen #include <string.h>
#include <errno.h> // errno #include <errno.h>
#include <fcntl.h> // O_CREAT, O_EXCL, O_RDWR [web:29] #include <fcntl.h> // O_CREAT, O_EXCL, O_RDWR для shm_open
#include <sys/mman.h> // shm_open, mmap, munmap [web:47] #include <sys/mman.h> // shm_open, mmap, munmap — POSIX разделяемая память
#include <sys/stat.h> // mode_t, S_IRUSR, S_IWUSR [web:39] #include <sys/stat.h> // Права доступа к объектам POSIX shared memory и семафорам
#include <semaphore.h> // sem_t, sem_open, sem_close, sem_unlink, sem_wait, sem_post [file:21] #include <semaphore.h> // POSIX именованные семафоры: sem_open, sem_close, sem_unlink, sem_wait, sem_post
#include <unistd.h> // ftruncate, close [file:21] #include <unistd.h> // ftruncate, close
#include <signal.h> // signal, SIGINT, SIGTERM #include <signal.h>
// Максимальная длина строки (включая '\0') для обмена через shared memory. [file:21] // Максимальная длина строки (включая '\0') для обмена через shared memory.
#define SHM_BUFFER_SIZE 1024 #define SHM_BUFFER_SIZE 1024
// Структура в разделяемой памяти. [file:21] // Структура расположена целиком в POSIX shared memory и разделяется сервером и клиентом.
typedef struct { typedef struct {
int has_data; // 0 - нет данных, 1 - клиент записал строку. [file:21] int has_data;
int result_code; // 0 - успех, -1 - ошибка обработки. [file:21] int result_code;
char buffer[SHM_BUFFER_SIZE]; // Буфер, в который клиент пишет, а сервер изменяет. [file:21] char buffer[SHM_BUFFER_SIZE];
} shared_block_t; } shared_block_t;
// Глобальные указатели/имена для корректной очистки в обработчике сигналов. [file:21] // Глобальные объекты, связанные с POSIX shared memory и семафорами.
static shared_block_t *g_shm_ptr = NULL; // Указатель на mmap(shared memory). [web:47] static shared_block_t *g_shm_ptr = NULL; // Указатель на mmap(shared memory).
static char g_shm_name[256] = ""; // Имя объекта shared memory. [file:21] static char g_shm_name[256] = ""; // Имя объекта POSIX shared memory (для shm_unlink).
static char g_sem_client_name[256] = ""; // Имя семафора клиента. [file:21] static char g_sem_client_name[256] = ""; // Имя именованного семафора клиента (sem_open/sem_unlink).
static char g_sem_server_name[256] = ""; // Имя семафора сервера. [file:21] static char g_sem_server_name[256] = ""; // Имя именованного семафора сервера (sem_open/sem_unlink).
static sem_t *g_sem_client = NULL; // Дескриптор семафора клиента. [file:21] static sem_t *g_sem_client = NULL; // Дескриптор POSIX семафора клиента.
static sem_t *g_sem_server = NULL; // Дескриптор семафора сервера. [file:21] static sem_t *g_sem_server = NULL; // Дескриптор POSIX семафора сервера.
static FILE *g_fout = NULL; // Файл output.txt. [web:57] static FILE *g_fout = NULL;
// Обработчик сигналов для аккуратного завершения (Ctrl+C, kill). [file:21] // Обработчик сигналов завершения: корректно удаляет POSIX shared memory и семафоры.
static void handle_signal(int signo) { static void handle_signal(int signo) {
(void) signo; // Неиспользуемый параметр, подавляем предупреждения. [file:21] (void) signo;
// Пытаемся корректно закрыть семафоры, если они открыты. [file:21]
if (g_sem_client) { if (g_sem_client) {
sem_close(g_sem_client); // Закрываем дескриптор семафора клиента. [file:21] sem_close(g_sem_client);
g_sem_client = NULL; g_sem_client = NULL;
} }
if (g_sem_server) { if (g_sem_server) {
sem_close(g_sem_server); // Закрываем дескриптор семафора сервера. [file:21] sem_close(g_sem_server);
g_sem_server = NULL; g_sem_server = NULL;
} }
// Удаляем именованные семафоры по их именам, если они заданы. [file:21][web:40] // sem_unlink удаляет именованные POSIX семафоры из системы.
if (g_sem_client_name[0] != '\0') { 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') { 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) { 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; g_shm_ptr = NULL;
} }
// Удаляем объект shared memory, если имя известно. [web:47] // shm_unlink удаляет объект POSIX shared memory.
if (g_shm_name[0] != '\0') { 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) { if (g_fout) {
fclose(g_fout); // Закрываем output.txt. [web:57] fclose(g_fout);
g_fout = NULL; g_fout = NULL;
} }
// Завершаем процесс. [file:21]
_exit(0); _exit(0);
} }
// Обработка строки по варианту 12. [file:22]
static void process_line(char *s) { static void process_line(char *s) {
if (s == NULL || s[0] == '\0') { if (s == NULL || s[0] == '\0') {
// Пустой буфер или пустая строка не обрабатываем. [file:21]
return; return;
} }
char first = s[0]; // Сохраняем первый символ. [file:22] char first = s[0];
// Проходим по строке начиная со второго символа. [file:22]
for (size_t i = 1; s[i] != '\0'; ++i) { for (size_t i = 1; s[i] != '\0'; ++i) {
if (s[i] == first) { if (s[i] == first) {
// Если символ совпадает с первым, заменяем его на пробел. [file:22]
s[i] = ' '; s[i] = ' ';
} }
} }
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// Ожидаемые аргументы: // argv[1] - имя POSIX shared memory (например, "/myshm").
// argv[1] - имя shared memory (например, "/myshm"). [file:21] // argv[2] - имя именованного семафора клиента (например, "/sem_client").
// argv[2] - имя семафора клиента (например, "/sem_client"). [file:21] // argv[3] - имя именованного семафора сервера (например, "/sem_server").
// argv[3] - имя семафора сервера (например, "/sem_server"). [file:21]
// argv[4] - (опционально) число обрабатываемых строк. [file:22]
if (argc < 4) { if (argc < 4) {
fprintf(stderr, fprintf(stderr,
"Usage: %s <shm_name> <sem_client_name> <sem_server_name> [iterations]\n", "Usage: %s <shm_name> <sem_client_name> <sem_server_name> [iterations]\n",
argv[0]); // Выводим подсказку по использованию. [file:22] argv[0]);
return -1; // По заданию -1 при ошибке. [file:22] return -1;
} }
// Сохраняем имена в глобальные переменные для очистки в сигналах. [file:21]
strncpy(g_shm_name, argv[1], sizeof(g_shm_name) - 1); 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_client_name, argv[2], sizeof(g_sem_client_name) - 1);
strncpy(g_sem_server_name, argv[3], sizeof(g_sem_server_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_client_name[sizeof(g_sem_client_name) - 1] = '\0';
g_sem_server_name[sizeof(g_sem_server_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_client_name = g_sem_client_name;
const char *sem_server_name = g_sem_server_name; const char *sem_server_name = g_sem_server_name;
// Разбираем количество итераций (строк), если указано. [file:22] int iterations = -1;
int iterations = -1; // -1 означает "работать до сигнала". [file:22]
if (argc >= 5) { if (argc >= 5) {
char *endptr = NULL; char *endptr = NULL;
unsigned long tmp = strtoul(argv[4], &endptr, 10); unsigned long tmp = strtoul(argv[4], &endptr, 10);
@@ -132,16 +118,15 @@ int main(int argc, char *argv[]) {
iterations = (int) tmp; iterations = (int) tmp;
} }
// Настраиваем обработчики сигналов для аккуратного завершения. [file:21] signal(SIGINT, handle_signal);
signal(SIGINT, handle_signal); // Обработка Ctrl+C. [file:21] signal(SIGTERM, handle_signal);
signal(SIGTERM, handle_signal); // Обработка внешнего kill. [file:21]
// Пытаемся удалить старые IPC-объекты, если они остались от прошлых запусков. [file:21] // Удаляем старые объекты POSIX shared memory и семафоров, если они остались от прошлых запусков.
shm_unlink(shm_name); // Игнорируем ошибку, если не существует. [web:47] shm_unlink(shm_name);
sem_unlink(sem_client_name); // То же для семафоров. [web:40] sem_unlink(sem_client_name);
sem_unlink(sem_server_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, int shm_fd = shm_open(shm_name,
O_CREAT | O_EXCL | O_RDWR, O_CREAT | O_EXCL | O_RDWR,
S_IRUSR | S_IWUSR); S_IRUSR | S_IWUSR);
@@ -150,7 +135,7 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
// Устанавливаем размер shared memory под нашу структуру. [file:21] // ftruncate задаёт размер объекта POSIX shared memory под нашу структуру.
if (ftruncate(shm_fd, sizeof(shared_block_t)) == -1) { if (ftruncate(shm_fd, sizeof(shared_block_t)) == -1) {
perror("ftruncate"); perror("ftruncate");
close(shm_fd); close(shm_fd);
@@ -158,7 +143,7 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
// Отображаем shared memory в адресное пространство сервера. [web:47] // Отображаем POSIX shared memory в адресное пространство сервера (mmap с MAP_SHARED).
g_shm_ptr = mmap(NULL, g_shm_ptr = mmap(NULL,
sizeof(shared_block_t), sizeof(shared_block_t),
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
@@ -173,22 +158,20 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
// Закрываем файловый дескриптор, оставляем только mmap. [file:21] // После успешного mmap файловый дескриптор POSIX shared memory можно закрыть.
if (close(shm_fd) == -1) { if (close(shm_fd) == -1) {
perror("close"); perror("close");
// Продолжаем работу, так как mmap уже есть. [file:21]
} }
// Инициализируем структуру в shared memory. [file:21]
g_shm_ptr->has_data = 0; g_shm_ptr->has_data = 0;
g_shm_ptr->result_code = 0; g_shm_ptr->result_code = 0;
memset(g_shm_ptr->buffer, 0, sizeof(g_shm_ptr->buffer)); 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, g_sem_client = sem_open(sem_client_name,
O_CREAT | O_EXCL, O_CREAT | O_EXCL,
S_IRUSR | S_IWUSR, S_IRUSR | S_IWUSR,
0); // Начальное значение 0. [file:21] 0); // начальное значение 0, сервер сразу блокируется на sem_wait.
if (g_sem_client == SEM_FAILED) { if (g_sem_client == SEM_FAILED) {
perror("sem_open(sem_client)"); perror("sem_open(sem_client)");
g_sem_client = NULL; g_sem_client = NULL;
@@ -198,11 +181,11 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
// Создаём именованный семафор сервера (сервер post, клиент wait). [file:21][web:40] // Создаём именованный семафор сервера: сервер делает sem_post, клиент — sem_wait.
g_sem_server = sem_open(sem_server_name, g_sem_server = sem_open(sem_server_name,
O_CREAT | O_EXCL, O_CREAT | O_EXCL,
S_IRUSR | S_IWUSR, S_IRUSR | S_IWUSR,
0); // Начальное значение 0. [file:21] 0);
if (g_sem_server == SEM_FAILED) { if (g_sem_server == SEM_FAILED) {
perror("sem_open(sem_server)"); perror("sem_open(sem_server)");
sem_close(g_sem_client); sem_close(g_sem_client);
@@ -214,50 +197,41 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
// Открываем файл вывода для записи всех обработанных строк. [web:57]
g_fout = fopen("output.txt", "w"); g_fout = fopen("output.txt", "w");
if (!g_fout) { if (!g_fout) {
perror("fopen(output.txt)"); 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) { while (iterations < 0 || processed_count < iterations) {
// Ждём, пока клиент поднимет семафор клиента. [file:21][web:40] // Сервер блокируется на семафоре клиента (sem_wait), ожидая данных в shared memory.
if (sem_wait(g_sem_client) == -1) { if (sem_wait(g_sem_client) == -1) {
perror("sem_wait(sem_client)"); perror("sem_wait(sem_client)");
processed_count = -1; processed_count = -1;
break; break;
} }
// Проверяем, что клиент установил флаг has_data. [file:21]
if (!g_shm_ptr->has_data) { if (!g_shm_ptr->has_data) {
fprintf(stderr, fprintf(stderr,
"Warning: sem_client posted, but has_data == 0\n"); "Warning: sem_client posted, but has_data == 0\n");
g_shm_ptr->result_code = -1; g_shm_ptr->result_code = -1;
} else { } else {
// Обрабатываем строку по варианту 12. [file:22]
process_line(g_shm_ptr->buffer); process_line(g_shm_ptr->buffer);
// Сохраняем код успешной обработки. [file:21]
g_shm_ptr->result_code = 0; g_shm_ptr->result_code = 0;
// Если файл открыт, дублируем результат в output.txt. [web:57]
if (g_fout) { if (g_fout) {
fprintf(g_fout, "%s\n", g_shm_ptr->buffer); fprintf(g_fout, "%s\n", g_shm_ptr->buffer);
fflush(g_fout); fflush(g_fout);
} }
// Сбрасываем флаг наличия данных. [file:21]
g_shm_ptr->has_data = 0; g_shm_ptr->has_data = 0;
// Увеличиваем счётчик обработанных строк. [file:22]
processed_count++; processed_count++;
} }
// Сигнализируем клиенту, что результат готов. [file:21][web:40] // Сервер увеличивает семафор сервера (sem_post), разблокируя клиента (sem_wait).
if (sem_post(g_sem_server) == -1) { if (sem_post(g_sem_server) == -1) {
perror("sem_post(sem_server)"); perror("sem_post(sem_server)");
processed_count = -1; processed_count = -1;
@@ -265,7 +239,6 @@ int main(int argc, char *argv[]) {
} }
} }
// Если файл вывода был открыт, закрываем его. [web:57]
if (g_fout) { if (g_fout) {
if (fclose(g_fout) == EOF) { if (fclose(g_fout) == EOF) {
perror("fclose(output.txt)"); perror("fclose(output.txt)");
@@ -273,14 +246,9 @@ int main(int argc, char *argv[]) {
g_fout = NULL; g_fout = NULL;
} }
// Выводим количество выполненных операций или -1 при ошибке. [file:22] printf("%d\n", processed_count >= 0 ? processed_count : -1);
if (processed_count >= 0) {
printf("%d\n", processed_count);
} else {
printf("-1\n");
}
// Корректно закрываем семафоры. [file:21] // Закрываем дескрипторы POSIX семафоров в процессе сервера.
if (g_sem_client) { if (g_sem_client) {
if (sem_close(g_sem_client) == -1) { if (sem_close(g_sem_client) == -1) {
perror("sem_close(sem_client)"); perror("sem_close(sem_client)");
@@ -294,7 +262,7 @@ int main(int argc, char *argv[]) {
g_sem_server = NULL; g_sem_server = NULL;
} }
// Удаляем именованные семафоры. [file:21][web:40] // sem_unlink полностью удаляет именованные семафоры из системы.
if (sem_unlink(sem_client_name) == -1) { if (sem_unlink(sem_client_name) == -1) {
perror("sem_unlink(sem_client)"); perror("sem_unlink(sem_client)");
} }
@@ -302,7 +270,7 @@ int main(int argc, char *argv[]) {
perror("sem_unlink(sem_server)"); perror("sem_unlink(sem_server)");
} }
// Отсоединяем shared memory. [web:47] // Отсоединяем область POSIX shared memory и удаляем сам объект.
if (g_shm_ptr) { if (g_shm_ptr) {
if (munmap(g_shm_ptr, sizeof(shared_block_t)) == -1) { if (munmap(g_shm_ptr, sizeof(shared_block_t)) == -1) {
perror("munmap"); perror("munmap");
@@ -310,10 +278,9 @@ int main(int argc, char *argv[]) {
g_shm_ptr = NULL; g_shm_ptr = NULL;
} }
// Удаляем объект shared memory. [web:47]
if (shm_unlink(shm_name) == -1) { if (shm_unlink(shm_name) == -1) {
perror("shm_unlink"); perror("shm_unlink");
} }
return 0; // Нормальное завершение сервера. [file:22] return 0;
} }