6-vlad untested

This commit is contained in:
2025-12-10 14:37:14 +07:00
parent 27b7c6c923
commit 02c4d80b5e
4 changed files with 414 additions and 0 deletions

51
lab_6/vlad/Makefile Normal file
View File

@@ -0,0 +1,51 @@
CC = gcc
CFLAGS = -Wall -Wextra -std=c99 -g
LDFLAGS_IPC = -lrt -pthread
SHM_NAME ?= /myshm
SEM_CLIENT_NAME ?= /sem_client
SEM_SERVER_NAME ?= /sem_server
SERVER_ITERS ?= 1000
all: shm
shm: server client
server: server.c
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS_IPC)
client: client.c
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS_IPC)
test_server: shm
@echo "=== Запуск сервера POSIX SHM+SEM ==="
@echo "В другом терминале выполните: make test_client"
./server $(SHM_NAME) $(SEM_CLIENT_NAME) $(SEM_SERVER_NAME) $(SERVER_ITERS)
test_client: shm
@echo "=== Запуск клиента, чтение input.txt, вывод на stdout ==="
./client $(SHM_NAME) $(SEM_CLIENT_NAME) $(SEM_SERVER_NAME)
test_all: shm
@echo "=== Автотест POSIX SHM+SEM с файлами input.txt/output.txt ==="
./server $(SHM_NAME) $(SEM_CLIENT_NAME) $(SEM_SERVER_NAME) $(SERVER_ITERS) & \
SRV=$$!; \
sleep 1; \
./client $(SHM_NAME) $(SEM_CLIENT_NAME) $(SEM_SERVER_NAME); \
wait $$SRV
clean:
@echo "Очистка..."
rm -f server client
rm -f output.txt
help:
@echo "Available targets:"
@echo " shm - Build POSIX SHM+SEM programs"
@echo " test_server - Run SHM+SEM server (client in another terminal)"
@echo " test_client - Run client reading input.txt"
@echo " test_all - Automatic end-to-end test with input.txt/output.txt"
@echo " clean - Remove built files"
@echo " help - Show this help"
.PHONY: all shm test_server test_client test_all clean help

147
lab_6/vlad/client.c Normal file
View File

@@ -0,0 +1,147 @@
// client.c
// Клиент: читает строки из input.txt, передаёт их серверу через shared memory,
// ожидает обработку и печатает результат на stdout. [file:21][file:22]
#include <stdio.h> // printf, fprintf, perror, FILE, fopen, fclose, 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 // Должен совпадать с server.c. [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[]) {
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];
// Открываем существующий shm. [file:21]
int shm_fd = shm_open(shm_name, O_RDWR, 0);
if (shm_fd == -1) {
perror("shm_open");
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);
return -1;
}
if (close(shm_fd) == -1) {
perror("close");
}
// Открываем семафоры. [file:21]
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. [file:22]
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];
while (fgets(input, sizeof(input), fin) != NULL) {
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));
strncpy(shm_ptr->buffer, input, SHM_BUFFER_SIZE - 1);
shm_ptr->buffer[SHM_BUFFER_SIZE - 1] = '\0';
shm_ptr->has_data = 1;
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;
}
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;
}
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;
}
printf("%s\n", shm_ptr->buffer);
}
if (fclose(fin) == EOF) {
perror("fclose(input.txt)");
}
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;
}

6
lab_6/vlad/input.txt Normal file
View File

@@ -0,0 +1,6 @@
abacaba
xxxxxx
hello
aaaaa
1abc1d1e1
qwerty

210
lab_6/vlad/server.c Normal file
View File

@@ -0,0 +1,210 @@
// server.c
// Сервер POSIX IPC: разделяемая память + именованные семафоры. [file:21]
// Задача: во всех парах одинаковых соседних символов второй символ заменить на пробел. [file:22]
#include <stdio.h> // printf, fprintf, perror, FILE, fopen, fclose, fprintf
#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> // S_IRUSR, S_IWUSR
#include <semaphore.h> // sem_t, sem_open, sem_close, sem_unlink, sem_wait, sem_post
#include <unistd.h> // 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 <shm_name> <sem_client_name> <sem_server_name> [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;
}