/
MaestroN
/
Eltex_Homework
Обзор
Документация
Войти
/
MaestroN
/
Eltex_Homework
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
Task_12/server.c
153 строки
7 KB
nikita_shub
Добавление задания 12 сервер-клиент
04 фев 2025, 11:30
04 фев 2025, 11:30
ef5bb30
Код
Авторство
О чём код?
/*Асинхронное взаимодействие через сигналы и сокеты Цель: Научиться реализовывать асинхронную обработку событий, используя сигнал SIGIO (асинхронный ввод/вывод) для уведомления о доступности данных в сокете. • Создайте TCP-сервер, который устанавливает режим асинхронного ввода/вывода для своего сокета. • Настройте обработчик сигнала SIGIO, чтобы получать уведомления о поступлении данных. • Когда данные поступают, обработчик должен считывать их (с использованием recv()) и выводить на стандартный вывод. • Клиент отправляет сообщение на сервер, что инициирует срабатывание сигнала. Рекомендации: • Используйте функцию fcntl() для установки сокета в неблокирующий режим и установки владельца файла (F_SETOWN) для получения сигнала SIGIO. • Убедитесь, что обработчик сигнала выполняет только async-signal-safe операции, например, чтение с сокета и запись через write(). • Проверьте корректное завершение работы сервера, учитывая асинхронные уведомления.*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <signal.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 8080 #define BUFFER_SIZE 1024 int server_fd, client_fd; // Глобальные дескрипторы сокетов void error_exit(const char *msg) { perror(msg); exit(EXIT_FAILURE); //exit(1); } // Обработчик сигнала SIGIO void sigio_handler(int signo) { char buffer[BUFFER_SIZE]; ssize_t bytes_read; // Чтение данных из сокета bytes_read = recv(client_fd, buffer, sizeof(buffer) - 1, 0); if (bytes_read > 0) { buffer[bytes_read] = '\0'; // Завершаем строку write(STDOUT_FILENO, "Получено сообщение: ", 37); write(STDOUT_FILENO, buffer, bytes_read); write(STDOUT_FILENO, "\n", 1); } else if (bytes_read == 0) { printf("Клиент закрыл соединение.\n"); close(client_fd); exit(EXIT_SUCCESS); } else { perror("Ошибка чтения из сокета"); } } int main() { struct sockaddr_in server_addr, client_addr; socklen_t client_len = sizeof(client_addr); // Создание сокета server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd == -1) { error_exit("Ошибка создания сокета"); } // Настройка адреса сервера memset(&server_addr, 0, sizeof(server_addr)); //заполнение структуры нулями server_addr.sin_family = AF_INET; //AF_INET — семейство адресов IPv4 server_addr.sin_addr.s_addr = INADDR_ANY; //INADDR_ANY позволяет принимать соединения на любом сетевом интерфейсе машины //htons() и htonl() — функции перевода чисел в сетевой порядок байт. server_addr.sin_port = htons(PORT); //port 8080 // Привязка сокета к адресу if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { error_exit("Ошибка привязки сокета"); } // Прослушивание входящих соединений if (listen(server_fd, 5) == -1) { //Число 5 — размер очереди ожидающих соединений. Это означает, что сервер готов одновременно //удерживать до 5 непринятых подключений. error_exit("Ошибка прослушивания"); } printf("Сервер запущен и ожидает соединений на порту %d...\n", PORT); // while (1) { // client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len); // if (client_fd == -1) { // perror("Ошибка принятия соединения"); // continue; // Пропускаем текущую итерацию и ждем новое соединение // } // // Обработка клиента // printf("Клиент подключен!\n"); // // Здесь можно добавить код для работы с клиентом // close(client_fd); // Закрываем соединение с клиентом // } // Принятие входящего соединения,accept() возвращает новый файловый дескриптор //теперь сервер может считывать данные с дескриптора client_fd client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len); if (client_fd == -1) { error_exit("Ошибка принятия соединения"); //может здесь continue? } printf("Клиент подключен: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); // Установка сокета в неблокирующий режим int flags = fcntl(client_fd, F_GETFL, 0); if (flags == -1) { error_exit("Ошибка получения флагов сокета"); } if (fcntl(client_fd, F_SETFL, flags | O_NONBLOCK | O_ASYNC) == -1) { // fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); error_exit("Ошибка установки неблокирующего режима"); } // Установка текущего процесса владельцем сокета для получения SIGIO if (fcntl(client_fd, F_SETOWN, getpid()) == -1) { error_exit("Ошибка установки владельца сокета"); } // Настройка обработчика сигнала SIGIO struct sigaction sa; sa.sa_handler = sigio_handler; // Указываем функцию-обработчик sa.sa_flags = 0; // Без дополнительных флагов sigemptyset(&sa.sa_mask); // Очищаем маску сигналов if (sigaction(SIGIO, &sa, NULL) == -1) { error_exit("Ошибка установки обработчика SIGIO"); } // Ожидание событий printf("Ожидание сообщений от клиента...\n"); while (1) { pause(); // Ожидание сигнала } // Закрытие сокетов close(client_fd); close(server_fd); return 0; }