// Сервер POSIX IPC: использует POSIX shared memory (shm_open + mmap) // и именованные POSIX семафоры (sem_open, sem_wait, sem_post) для обмена с клиентом. #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. #define SHM_BUFFER_SIZE 1024 // Структура расположена целиком в POSIX shared memory и разделяется сервером и клиентом. typedef struct { int has_data; int result_code; char buffer[SHM_BUFFER_SIZE]; } shared_block_t; // Глобальные объекты, связанные с 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; // Обработчик сигналов завершения: корректно удаляет POSIX shared memory и семафоры. static void handle_signal(int signo) { (void) signo; if (g_sem_client) { sem_close(g_sem_client); g_sem_client = NULL; } if (g_sem_server) { sem_close(g_sem_server); g_sem_server = NULL; } // sem_unlink удаляет именованные POSIX семафоры из системы. if (g_sem_client_name[0] != '\0') { sem_unlink(g_sem_client_name); } if (g_sem_server_name[0] != '\0') { sem_unlink(g_sem_server_name); } // munmap отсоединяет область POSIX shared memory из адресного пространства процесса. if (g_shm_ptr) { munmap(g_shm_ptr, sizeof(shared_block_t)); g_shm_ptr = NULL; } // shm_unlink удаляет объект POSIX shared memory. if (g_shm_name[0] != '\0') { shm_unlink(g_shm_name); } if (g_fout) { fclose(g_fout); g_fout = NULL; } _exit(0); } static void process_line(char *s) { if (s == NULL || s[0] == '\0') { return; } char first = s[0]; for (size_t i = 1; s[i] != '\0'; ++i) { if (s[i] == first) { s[i] = ' '; } } } int main(int argc, char *argv[]) { // 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]); return -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_server_name, argv[3], sizeof(g_sem_server_name) - 1); g_shm_name[sizeof(g_shm_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'; 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; int iterations = -1; if (argc >= 5) { char *endptr = NULL; unsigned long tmp = strtoul(argv[4], &endptr, 10); if (endptr == argv[4] || *endptr != '\0') { fprintf(stderr, "Invalid iterations value: '%s'\n", argv[4]); return -1; } iterations = (int) tmp; } signal(SIGINT, handle_signal); signal(SIGTERM, handle_signal); // Удаляем старые объекты POSIX shared memory и семафоров, если они остались от прошлых запусков. shm_unlink(shm_name); sem_unlink(sem_client_name); sem_unlink(sem_server_name); // Создаём новый объект 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); if (shm_fd == -1) { perror("shm_open"); return -1; } // ftruncate задаёт размер объекта POSIX shared memory под нашу структуру. if (ftruncate(shm_fd, sizeof(shared_block_t)) == -1) { perror("ftruncate"); close(shm_fd); shm_unlink(shm_name); return -1; } // Отображаем POSIX shared memory в адресное пространство сервера (mmap с MAP_SHARED). g_shm_ptr = mmap(NULL, sizeof(shared_block_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); if (g_shm_ptr == MAP_FAILED) { perror("mmap"); g_shm_ptr = NULL; close(shm_fd); shm_unlink(shm_name); return -1; } // После успешного mmap файловый дескриптор POSIX shared memory можно закрыть. if (close(shm_fd) == -1) { perror("close"); } g_shm_ptr->has_data = 0; g_shm_ptr->result_code = 0; memset(g_shm_ptr->buffer, 0, sizeof(g_shm_ptr->buffer)); // Создаём именованный семафор клиента: клиент будет делать sem_post, сервер — sem_wait. g_sem_client = sem_open(sem_client_name, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 0); // начальное значение 0, сервер сразу блокируется на sem_wait. if (g_sem_client == SEM_FAILED) { perror("sem_open(sem_client)"); g_sem_client = NULL; munmap(g_shm_ptr, sizeof(shared_block_t)); g_shm_ptr = NULL; shm_unlink(shm_name); return -1; } // Создаём именованный семафор сервера: сервер делает sem_post, клиент — sem_wait. g_sem_server = sem_open(sem_server_name, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 0); if (g_sem_server == SEM_FAILED) { perror("sem_open(sem_server)"); sem_close(g_sem_client); sem_unlink(sem_client_name); g_sem_client = NULL; munmap(g_shm_ptr, sizeof(shared_block_t)); g_shm_ptr = NULL; shm_unlink(shm_name); return -1; } g_fout = fopen("output.txt", "w"); if (!g_fout) { perror("fopen(output.txt)"); } int processed_count = 0; while (iterations < 0 || processed_count < iterations) { // Сервер блокируется на семафоре клиента (sem_wait), ожидая данных в shared memory. if (sem_wait(g_sem_client) == -1) { perror("sem_wait(sem_client)"); processed_count = -1; break; } if (!g_shm_ptr->has_data) { fprintf(stderr, "Warning: sem_client posted, but has_data == 0\n"); g_shm_ptr->result_code = -1; } else { process_line(g_shm_ptr->buffer); g_shm_ptr->result_code = 0; if (g_fout) { fprintf(g_fout, "%s\n", g_shm_ptr->buffer); fflush(g_fout); } g_shm_ptr->has_data = 0; processed_count++; } // Сервер увеличивает семафор сервера (sem_post), разблокируя клиента (sem_wait). if (sem_post(g_sem_server) == -1) { perror("sem_post(sem_server)"); processed_count = -1; break; } } if (g_fout) { if (fclose(g_fout) == EOF) { perror("fclose(output.txt)"); } g_fout = NULL; } printf("%d\n", processed_count >= 0 ? processed_count : -1); // Закрываем дескрипторы POSIX семафоров в процессе сервера. if (g_sem_client) { if (sem_close(g_sem_client) == -1) { perror("sem_close(sem_client)"); } g_sem_client = NULL; } if (g_sem_server) { if (sem_close(g_sem_server) == -1) { perror("sem_close(sem_server)"); } g_sem_server = NULL; } // sem_unlink полностью удаляет именованные семафоры из системы. if (sem_unlink(sem_client_name) == -1) { perror("sem_unlink(sem_client)"); } if (sem_unlink(sem_server_name) == -1) { perror("sem_unlink(sem_server)"); } // Отсоединяем область POSIX shared memory и удаляем сам объект. if (g_shm_ptr) { if (munmap(g_shm_ptr, sizeof(shared_block_t)) == -1) { perror("munmap"); } g_shm_ptr = NULL; } if (shm_unlink(shm_name) == -1) { perror("shm_unlink"); } return 0; }