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

169 lines
6.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: читает строки из input.txt, передаёт их серверу через
// разделяемую память и выводит обработанные строки на stdout. [file:21][web:57]
#include <stdio.h> // printf, fprintf, perror, FILE, fopen, fclose, fgets [web:60]
#include <stdlib.h> // exit, EXIT_FAILURE
#include <string.h> // memset, strncpy, strlen
#include <errno.h> // errno
#include <fcntl.h> // O_RDWR [web:29]
#include <sys/mman.h> // shm_open, mmap, munmap [web:47]
#include <sys/stat.h> // mode_t
#include <semaphore.h> // sem_t, sem_open, sem_close, sem_wait, sem_post [file:21]
#include <unistd.h> // 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 <shm_name> <sem_client_name> <sem_server_name>\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]
}