Files
CS-LABS/lab_6/client.c
2025-12-10 14:23:02 +07:00

158 lines
5.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// client.c
// Клиент POSIX IPC: подключается к существующей разделяемой памяти
// и именованным семафорам, передаёт строку серверу и получает результат. [web:8]
#include <stdio.h> // printf, fprintf, perror, fgets
#include <stdlib.h> // exit, EXIT_FAILURE
#include <string.h> // memset, strncpy, strlen
#include <errno.h> // errno
#include <fcntl.h> // O_RDWR
#include <sys/mman.h> // shm_open, mmap, munmap
#include <sys/stat.h> // mode_t
#include <semaphore.h> // sem_t, sem_open, sem_close, sem_wait, sem_post
#include <unistd.h> // 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 <shm_name> <sem_client_name> <sem_server_name>\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;
}