// client.c // Клиент POSIX IPC: подключается к существующей разделяемой памяти // и именованным семафорам, передаёт строку серверу и получает результат. [web:8] #include // printf, fprintf, perror, fgets #include // exit, EXIT_FAILURE #include // memset, strncpy, strlen #include // errno #include // O_RDWR #include // shm_open, mmap, munmap #include // mode_t #include // sem_t, sem_open, sem_close, sem_wait, sem_post #include // close // Максимальная длина строки для обмена (должна совпадать с сервером). #define SHM_BUFFER_SIZE 1024 // Структура данных в разделяемой памяти, та же, что и у сервера. typedef struct { int has_data; int result_code; char buffer[SHM_BUFFER_SIZE]; } shared_block_t; // Основная функция клиента. int main(int argc, char *argv[]) { // Ожидаем минимум три аргумента: // argv[1] - имя объекта shared memory (должно совпадать с сервером). // argv[2] - имя семафора клиента. // argv[3] - имя семафора сервера. if (argc < 4) { fprintf(stderr, "Usage: %s \n", argv[0]); return -1; } const char *shm_name = argv[1]; const char *sem_client_name = argv[2]; const char *sem_server_name = argv[3]; // Открываем уже существующий объект разделяемой памяти. [web:8] int shm_fd = shm_open(shm_name, O_RDWR, 0); if (shm_fd == -1) { perror("shm_open"); return -1; } // Отображаем его в адресное пространство процесса. [web:8] shared_block_t *shm_ptr = mmap(NULL, sizeof(shared_block_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); if (shm_ptr == MAP_FAILED) { perror("mmap"); close(shm_fd); return -1; } // Дескриптор больше не нужен после mmap. if (close(shm_fd) == -1) { perror("close"); } // Открываем существующие именованные семафоры. [web:16] sem_t *sem_client = sem_open(sem_client_name, 0); if (sem_client == SEM_FAILED) { perror("sem_open(sem_client)"); munmap(shm_ptr, sizeof(shared_block_t)); return -1; } sem_t *sem_server = sem_open(sem_server_name, 0); if (sem_server == SEM_FAILED) { perror("sem_open(sem_server)"); sem_close(sem_client); munmap(shm_ptr, sizeof(shared_block_t)); return -1; } // Читаем строку из stdin. char input[SHM_BUFFER_SIZE]; if (fgets(input, sizeof(input), stdin) == NULL) { // Ошибка чтения из stdin или EOF. fprintf(stderr, "No input line provided\n"); sem_close(sem_client); sem_close(sem_server); munmap(shm_ptr, sizeof(shared_block_t)); return -1; } // Удаляем перевод строки в конце, если он есть. size_t len = strlen(input); if (len > 0 && input[len - 1] == '\n') { input[len - 1] = '\0'; } // Записываем строку в разделяемую память. // Сначала очищаем буфер. memset(shm_ptr->buffer, 0, sizeof(shm_ptr->buffer)); // Копируем строку, гарантируя наличие '\0'. strncpy(shm_ptr->buffer, input, SHM_BUFFER_SIZE - 1); shm_ptr->buffer[SHM_BUFFER_SIZE - 1] = '\0'; // Устанавливаем флаг наличия данных. shm_ptr->has_data = 1; // Передаём управление серверу: sem_post(sem_client). [web:16] if (sem_post(sem_client) == -1) { perror("sem_post(sem_client)"); sem_close(sem_client); sem_close(sem_server); munmap(shm_ptr, sizeof(shared_block_t)); return -1; } // Ждём завершения обработки: sem_wait(sem_server). [web:16] if (sem_wait(sem_server) == -1) { perror("sem_wait(sem_server)"); sem_close(sem_client); sem_close(sem_server); munmap(shm_ptr, sizeof(shared_block_t)); return -1; } // Проверяем код результата, установленный сервером. if (shm_ptr->result_code != 0) { fprintf(stderr, "Server reported error, result_code = %d\n", shm_ptr->result_code); sem_close(sem_client); sem_close(sem_server); munmap(shm_ptr, sizeof(shared_block_t)); return -1; } // Выводим обработанную строку на stdout. printf("%s\n", shm_ptr->buffer); // Закрываем семафоры и отсоединяемся от разделяемой памяти. [web:8] if (sem_close(sem_client) == -1) { perror("sem_close(sem_client)"); } if (sem_close(sem_server) == -1) { perror("sem_close(sem_server)"); } if (munmap(shm_ptr, sizeof(shared_block_t)) == -1) { perror("munmap"); } return 0; }