автор: rabderus, 10 волна
0. Важно понимать. Нам нужно: Makefile, хэдер, всякая си-мелочь и два основных процесса (.с файла): клиент и сервер (в них надо также расписать main).
В этом разборе объясню основные тонкости реализации этих двух функций, на момент написания (начало февраля 2022 года) мне понадобились следующие функции из новых разрешенных: kill, getpid, sigaction, exit.
I. Клиент. Идея клиента состоит в том, что он заданную нами строку бьёт на каждый отдельный символ, который потом перекодирует в двоичный формат, и посредством разрешенных двух пользовательских сигналов (один играет роль ‘1’, другой ‘0’), отправляет этот символ серверу.
ВАЖНО: для успешного написания проекта необходимо наладить обмен сигналами между сервером и клиентом, причем БЕЗ использования функции sleep - он нам не нужен. Под ‘обмен сигналами’ мы подразумеваем: клиент отправляет сигнал серверу, принимает от него отклик в виде ответного сигнала, и только после этого отправляет следующий сигнал, и так до конца передачи. Отклик и там и там фиксируется посредством глобальной переменной, служащей нам в качестве ‘флага’.
Про кодировку и про проект в целом хорошо рассказно ЗДЕСЬ. (PID сервера, который мы пишем в терминале, как раз для функции kill)
II. Сервер. У сервера история обратная - он принимает сигналы, на основе ‘болванки’ формирует байт-символ, сохраняет его маллоком в статический массив (да, нам их можно использовать), и так до ‘\0’, после чего выводим (я делал через write).
III. Общая конструкция. В обоих процессах у вас должны быть: (1) обработчик сигнала (’шифрование’ / ’дешифрование’); (2) функция, которая вися в вечном цикле фиксирует отклик посредством сменой флага, а потом меняет флаг обратно; (3) отправитель сигнала процессу.
Причём (2) автономна от (1) - она связана с ней только через изменение глобальной переменной. Если объяснять, то функция sigaction - это настройка (или переопределение) входящих сигналов посредством, опять же, настройки элементов структуры sigaction. (Настройку мы производим в данном проекте потому что сигналы пользовательские, и делают они только то, что мы им назначим) ****Фокус в том, что происходит как бы два действия одновременно: вечный цикл-ожидание ответного сигнала И функция, которая срабатывает только при принятие этого сигнала, и чтобы не было при этом асинхронна, то есть чтобы всегда выполнялось только что-то одно в моменте, ведь всё происходит быстро, нам нужен надежный флаг.
IV. Флаг. Мы прошаренные ребята, потому будем использовать ‘volatile sig_atomic NAME**’** ! [Второе определение.](http://www.pic24.ru/doku.php/osa/articles/volatile_for_chainiks#:~:text=Определение,-( volatile в переводе&text=Итак%2C volatile в языке Си,)%2C не должна быть оптимизирована.) ****Пример использование и некоторое (мда уж) объяснение ЗДЕСЬ.
Что это в принципе такое? Вот объяснение с древнего форума: ”Сигнал — внешнее по отношению к программе событие, возникающее асинхронно (т. е., не по инициативе программы, например вследствие нажатия пользователем Ctrl+Break, ошибки доступа к памяти и т. д.). При помощи функции signal программа может зарегистрировать обработчик сигнала. Т. к. сигнал может поступить в любой момент времени, рассчитывать на то, что объекты программы находятся во внутренне согласованном состоянии, невозможно. Такая гарантия может быть дана средой исполнения только в отношении объектов типа volatile sig_atomic_t.”
Как мне объяснили, это такой тип данных, операция над которой выполняется в одну инструкцию, что препятствует асинхронну, который приводит к глюкам, остановке, неккоректному исполнению.
И в клиенте и в сервере используете как глобальную переменную, и будет вам счастье. В сервере её можно реализовать в виде массива, и в один из элементов запихнуть PID клиента (struct_Name->si_pid).
**Методическая литература.
Доп. информация по теме. 1) Интересная статья на хабре (близкая к нашему проекту): https://habr.com/ru/post/122823/ 2) Как раз хорошая статья за volatile sig_atomic_t : глава 21.1.3, на странице 453
