works no files

This commit is contained in:
2025-12-10 14:23:02 +07:00
parent 2b488e06eb
commit 43b29e59e7
3 changed files with 439 additions and 0 deletions

221
lab_6/server.c Normal file
View File

@@ -0,0 +1,221 @@
// server.c
// Сервер POSIX IPC: разделяемая память + именованные семафоры.
// Обрабатывает строки по заданию варианта 12:
// "Заменить на пробелы все символы, совпадающие с первым символом в строке,
// кроме самого первого символа."
#include <stdio.h> // printf, fprintf, perror
#include <stdlib.h> // exit, EXIT_FAILURE, strtoul
#include <string.h> // memset, strncpy, strlen
#include <errno.h> // errno
#include <fcntl.h> // O_CREAT, O_EXCL, O_RDWR
#include <sys/mman.h> // shm_open, mmap, munmap
#include <sys/stat.h> // mode_t, S_IRUSR, S_IWUSR
#include <semaphore.h> // sem_t, sem_open, sem_close, sem_unlink, sem_wait, sem_post
#include <unistd.h> // ftruncate, close
// Максимальная длина строки для обмена (включая '\0').
#define SHM_BUFFER_SIZE 1024
// Структура данных в разделяемой памяти.
typedef struct {
// Флаг наличия данных от клиента: 0 - нет, 1 - есть.
int has_data;
// Флаг, который сервер выставляет как код возврата:
// 0 - нормальное завершение обработки
// -1 - ошибка обработки (например, некорректные данные).
int result_code;
// Буфер для строки.
char buffer[SHM_BUFFER_SIZE];
} shared_block_t;
// Функция обработки строки по варианту 12.
static void process_line(char *s) {
// Если строка пустая или первый символ - '\0', делать нечего.
if (s == NULL || s[0] == '\0') {
return;
}
// Сохраняем первый символ строки.
char first = s[0];
// Идём по строке начиная со второго символа.
for (size_t i = 1; s[i] != '\0'; ++i) {
// Если текущий символ совпадает с первым, заменяем его на пробел.
if (s[i] == first) {
s[i] = ' ';
}
}
}
// Основная функция сервера.
int main(int argc, char *argv[]) {
// Ожидаем минимум два аргумента:
// argv[1] - имя объекта shared memory (например, "/myshm").
// argv[2] - имя семафора для клиента (например, "/sem_client").
// argv[3] - имя семафора для сервера (например, "/sem_server").
// Дополнительно можно передать количество итераций.
if (argc < 4) {
fprintf(stderr,
"Usage: %s <shm_name> <sem_client_name> <sem_server_name> [iterations]\n",
argv[0]);
// -1 по заданию в случае ошибки.
return -1;
}
// Извлекаем имена объектов POSIX IPC.
const char *shm_name = argv[1];
const char *sem_client_name = argv[2];
const char *sem_server_name = argv[3];
// Количество итераций обработки (по умолчанию - бесконечно).
int iterations = -1;
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;
}
// Создаём или открываем объект разделяемой памяти.
// Используем флаги O_CREAT | O_EXCL | O_RDWR, чтобы сервер был тем,
// кто создаёт объект впервые. В случае существования - ошибка.
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;
}
// Инициализируем структуру в разделяемой памяти.
shm_ptr->has_data = 0;
shm_ptr->result_code = 0;
memset(shm_ptr->buffer, 0, sizeof(shm_ptr->buffer));
// Закрываем дескриптор файла, отображение уже есть.
if (close(shm_fd) == -1) {
perror("close");
// Не выходим немедленно, поскольку отображение активно.
}
// Создаём именованные семафоры. [web:16]
// sem_client: клиент делает sem_post, сервер делает sem_wait. [web:16]
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_server: сервер делает sem_post, клиент делает sem_wait. [web:16]
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;
}
// Основной цикл обработки.
// Если iterations == -1, цикл бесконечный, прерывается по сигналу.
int processed_count = 0;
while (iterations < 0 || processed_count < iterations) {
// Ожидаем, пока клиент запишет строку и выполнит sem_post(sem_client). [web:16]
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 {
// Обрабатываем строку.
process_line(shm_ptr->buffer);
// В данном примере считаем, что обработка всегда успешна.
shm_ptr->result_code = 0;
// Сбрасываем флаг наличия необработанных данных.
shm_ptr->has_data = 0;
// Увеличиваем счётчик обработанных операций.
processed_count++;
}
// Сообщаем клиенту, что результат готов. [web:16]
if (sem_post(sem_server) == -1) {
perror("sem_post(sem_server)");
processed_count = -1;
break;
}
}
// Выводим количество выполненных операций или -1 в случае ошибки.
if (processed_count >= 0) {
printf("%d\n", processed_count);
} else {
printf("-1\n");
}
// Освобождаем ресурсы: закрываем и удаляем семафоры. [web:16]
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)");
}
// Отсоединяем разделяемую память и удаляем объект. [web:8]
if (munmap(shm_ptr, sizeof(shared_block_t)) == -1) {
perror("munmap");
}
if (shm_unlink(shm_name) == -1) {
perror("shm_unlink");
}
return 0;
}