// server.c // Сервер POSIX IPC: разделяемая память + именованные семафоры. [file:21] // Задача: во всех парах одинаковых соседних символов второй символ заменить на пробел. [file:22] #include // printf, fprintf, perror, FILE, fopen, fclose, fprintf #include // exit, EXIT_FAILURE, strtoul #include // memset, strncpy, strlen #include // errno #include // O_CREAT, O_EXCL, O_RDWR #include // shm_open, mmap, munmap #include // S_IRUSR, S_IWUSR #include // sem_t, sem_open, sem_close, sem_unlink, sem_wait, sem_post #include // ftruncate, close #define SHM_BUFFER_SIZE 1024 // Максимальный размер строки в shared memory. [file:21] // Структура разделяемой памяти. [file:21] typedef struct { int has_data; // 1, если клиент записал строку. [file:21] int result_code; // 0 - успех, -1 - ошибка. [file:21] char buffer[SHM_BUFFER_SIZE]; // Буфер для строки. [file:21] } shared_block_t; // Обработка строки по новому заданию: [file:22] // "Во всех парах одинаковых символов второй символ заменить на пробел". static void process_line(char *s) { if (!s) { return; } for (size_t i = 0; s[i] != '\0'; ++i) { // Идём по всей строке. [file:22] if (s[i] != '\0' && s[i + 1] != '\0' && s[i] == s[i + 1]) { // Если два соседних символа равны, второй заменяем на пробел. [file:22] s[i + 1] = ' '; // Можно сдвинуться дальше, чтобы не склеивать новые пары искусственно. [file:22] // Но по условию достаточно просто заменить второй символ. } } } int main(int argc, char *argv[]) { // argv[1] - имя shm, argv[2] - имя sem_client, argv[3] - имя sem_server, argv[4] - итерации. [file:22] if (argc < 4) { fprintf(stderr, "Usage: %s [iterations]\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]; int iterations = -1; // -1 = работать до сигнала/внешнего завершения. [file:22] 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; } // Простая зачистка возможных старых IPC-объектов. [file:21] shm_unlink(shm_name); sem_unlink(sem_client_name); sem_unlink(sem_server_name); // Создаём shared memory. [file:21] 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; } if (ftruncate(shm_fd, sizeof(shared_block_t)) == -1) { perror("ftruncate"); close(shm_fd); shm_unlink(shm_name); return -1; } 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); shm_unlink(shm_name); return -1; } if (close(shm_fd) == -1) { perror("close"); } // Инициализация shared memory. [file:21] shm_ptr->has_data = 0; shm_ptr->result_code = 0; memset(shm_ptr->buffer, 0, sizeof(shm_ptr->buffer)); // Создаём семафоры. [file:21] sem_t *sem_client = sem_open(sem_client_name, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 0); if (sem_client == SEM_FAILED) { perror("sem_open(sem_client)"); munmap(shm_ptr, sizeof(shared_block_t)); shm_unlink(shm_name); return -1; } sem_t *sem_server = sem_open(sem_server_name, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 0); if (sem_server == SEM_FAILED) { perror("sem_open(sem_server)"); sem_close(sem_client); sem_unlink(sem_client_name); munmap(shm_ptr, sizeof(shared_block_t)); shm_unlink(shm_name); return -1; } // Открываем файл вывода. [file:22] FILE *fout = fopen("output.txt", "w"); if (!fout) { perror("fopen(output.txt)"); // Продолжаем работать только через shared memory. [file:21] } int processed_count = 0; // Сколько строк обработано. [file:22] while (iterations < 0 || processed_count < iterations) { // Ждём строку от клиента. [file:21] if (sem_wait(sem_client) == -1) { perror("sem_wait(sem_client)"); processed_count = -1; break; } if (!shm_ptr->has_data) { fprintf(stderr, "Warning: sem_client posted, but has_data == 0\n"); shm_ptr->result_code = -1; } else { // Обрабатываем строку по новому заданию. [file:22] process_line(shm_ptr->buffer); shm_ptr->result_code = 0; shm_ptr->has_data = 0; processed_count++; if (fout) { fprintf(fout, "%s\n", shm_ptr->buffer); fflush(fout); } } // Сообщаем клиенту, что результат готов. [file:21] if (sem_post(sem_server) == -1) { perror("sem_post(sem_server)"); processed_count = -1; break; } } if (fout && fclose(fout) == EOF) { perror("fclose(output.txt)"); } // Выводим число операций или -1. [file:22] if (processed_count >= 0) { printf("%d\n", processed_count); } else { printf("-1\n"); } // Очистка IPC-объектов. [file:21] if (sem_close(sem_client) == -1) { perror("sem_close(sem_client)"); } if (sem_close(sem_server) == -1) { perror("sem_close(sem_server)"); } if (sem_unlink(sem_client_name) == -1) { perror("sem_unlink(sem_client)"); } if (sem_unlink(sem_server_name) == -1) { perror("sem_unlink(sem_server)"); } if (munmap(shm_ptr, sizeof(shared_block_t)) == -1) { perror("munmap"); } if (shm_unlink(shm_name) == -1) { perror("shm_unlink"); } return 0; }