// client.c // Клиент POSIX IPC: читает строки из input.txt, передаёт их серверу через // разделяемую память и выводит обработанные строки на stdout. [file:21][web:57] #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 // Размер буфера обмена (должен совпадать с server.c). [file:21] #define SHM_BUFFER_SIZE 1024 // Та же структура, что и у сервера. [file:21] typedef struct { int has_data; // Флаг наличия данных от клиента. [file:21] int result_code; // Код результата обработки. [file:21] char buffer[SHM_BUFFER_SIZE]; // Буфер строки. [file:21] } shared_block_t; int main(int argc, char *argv[]) { // Ожидаемые аргументы: // argv[1] - имя shared memory (должно совпадать с сервером). [file:21] // argv[2] - имя семафора клиента. [file:21] // argv[3] - имя семафора сервера. [file:21] if (argc < 4) { fprintf(stderr, "Usage: %s \n", argv[0]); // Сообщаем о правильном формате запуска. [file:22] return -1; } const char *shm_name = argv[1]; const char *sem_client_name = argv[2]; const char *sem_server_name = argv[3]; // Открываем существующий объект shared memory, созданный сервером. [web:47] int shm_fd = shm_open(shm_name, O_RDWR, 0); if (shm_fd == -1) { perror("shm_open"); return -1; } // Отображаем shared memory в адресное пространство клиента. [web:47] 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 продолжает работать. [file:21] if (close(shm_fd) == -1) { perror("close"); } // Открываем именованные семафоры, которые создал сервер. [file:21][web:40] 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; } // Открываем файл input.txt для чтения исходных строк. [web:57] FILE *fin = fopen("input.txt", "r"); if (!fin) { perror("fopen(input.txt)"); sem_close(sem_client); sem_close(sem_server); munmap(shm_ptr, sizeof(shared_block_t)); return -1; } char input[SHM_BUFFER_SIZE]; // Локальный буфер для чтения строки. [file:21] // Читаем input.txt построчно до конца файла. [web:51] while (fgets(input, sizeof(input), fin) != NULL) { size_t len = strlen(input); // Длина считанной строки. [web:54] // Удаляем конечный '\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] if (sem_post(sem_client) == -1) { perror("sem_post(sem_client)"); fclose(fin); sem_close(sem_client); sem_close(sem_server); munmap(shm_ptr, sizeof(shared_block_t)); return -1; } // Ждём, пока сервер обработает строку. [file:21][web:40] if (sem_wait(sem_server) == -1) { perror("sem_wait(sem_server)"); fclose(fin); sem_close(sem_client); sem_close(sem_server); munmap(shm_ptr, sizeof(shared_block_t)); return -1; } // Проверяем код результата, выставленный сервером. [file:21] if (shm_ptr->result_code != 0) { fprintf(stderr, "Server reported error, result_code = %d\n", shm_ptr->result_code); fclose(fin); sem_close(sem_client); sem_close(sem_server); munmap(shm_ptr, sizeof(shared_block_t)); return -1; } // Выводим обработанную строку на стандартный вывод. [file:22] printf("%s\n", shm_ptr->buffer); } // Закрываем input.txt после окончания чтения. [web:57] if (fclose(fin) == EOF) { perror("fclose(input.txt)"); } // Закрываем семафоры. [file:21] if (sem_close(sem_client) == -1) { perror("sem_close(sem_client)"); } if (sem_close(sem_server) == -1) { perror("sem_close(sem_server)"); } // Отсоединяем shared memory. [web:47] if (munmap(shm_ptr, sizeof(shared_block_t)) == -1) { perror("munmap"); } return 0; // Нормальное завершение клиента. [file:22] }