Файл: Федеральное государственное автономное образовательное учреждение высшего образования казанский (приволжский) федеральный университет высшая школа информационных технологий и информационных систем.docx

ВУЗ: Не указан

Категория: Реферат

Дисциплина: Не указана

Добавлен: 08.11.2023

Просмотров: 92

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

СОДЕРЖАНИЕ

Содержание

Введение.

Обзорная часть В обзорно-аналитической главе будет проведен обзор предметной области, рассмотрены аналоги системы, их преимущества и недостатки. 1.1 История. Изначально кластерные технологии использовались при развертывании компьютерных сетей. Немалую роль в появлении высокоскоростной передачи между компьютерами имела возможность объединения вычислительных ресурсов. Лаборатория Xerox PARC вместе с группой разработчиков протокола TCP/IP разработали и закрепили стандарты сетевого взаимодействия уже в начале 1970-ых годов. Была разработана операционная система Hydra («Гидра»), которая работала на компьютерах PDP-11, которые выпускала компания DEC. На базе это ОС был разработан кластер, который был назван C.mpp в 1971 году в Америке в городе Питтсбург, который находится штате Пенсильвания. Однако, только в 1983 году научились распределять задачи и распространять файлы с помощью компьютерных сетей, огромный вклад в разработку этого внесла компания Sun Microsystems, которая предоставила операционную систему на основе BSD, которая имела название SunOS.Первым коммерческим проектом кластера стал ARCNet, созданный компанией Datapoint в 1977 году, однако этот продукт не принес прибыль компании, поэтому разработка кластеров была заморожена до 1984 года. В этом году компанией DEC был создан кластер VAXcluster, который был построен для ОС VAX/VMS. Каждый из этих кластеров мог не только производить совместные вычисления, но и предоставлял возможность совместного использования файловой системы и других составляющих, при этом не теряя целостность файлов и неизменность данных. На данный момент VAXCluster (называемый теперь VMSCluster) входит в сотав операционной системы HP OpenVMS, которая использует процессоры Alpha и Itanium.Также есть еще несколько первых разработок кластера, которые преобрели популярность. Такими продуктами являются класера Himalaya, который разработан компанией Tandem в 1994 году, а также Parallel Sysplex, который был разаботан компанией IBM также в 1994 году.Большей часть разработкой кластеров, которые состояли из персональных компьютеров, занимался проект Parallel Virtual Machine. Первый релиз данной программы произошёл в 1989 году. Это программное обеспечение предоставляло возможность из нескольких обычных компьютеров собрать один виртуальный суперкомпьютер. Появилась возможность очень быстро и просто создавать кластера. Данные дешевые кластера были даже лучше по производительности, чем производительность мощностей коммерческих систем.Разработку кластеров, состоящих из ПК в данной области продолжило Американское аэрокосмическое агентство NASA в 1993г. И уже в 1995 году появился кластер Beowulf. Это также поспособствовало развитию grip-сетей, который были созданы вместе с системами UNIX. 1.2 О кластере. Термин «кластер» имеет множество определений. Для некоторых главной составляющей является отказоустойчивость, для других — масштабируемость, для третьих — управляемость. Классическое определение кластера звучит примерно так: «кластер — параллельная или распределенная система, состоящая из нескольких связанных между собой компьютеров и при этом используемая как единый, унифицированный компьютерный ресурс». Следовательно, кластер – это некоторое количество серверов или компьютеров, которые объединены в одну сеть, которой можно управлять, и работают как неразделимый механизм. Для работы кластера необходимо, чтобы на любой узле (ноде, компьютере, сервере) была запущена своя копия ОС.Грегори Пристер как-то дал определение кластерным технологиям: «Кластер представляет собой одну из разновидностей распределенной или параллельной системы». Этот человек сыграл немалую роль на начальном этапе создания кластеров. Именно он был одним из ранних архитекторов кластерных решений.Однако эксперты Aberdeen Group дали более глобальное определение кластеру. По их мнению, кластер - это система, которая может работать как единый целый механизм, обеспечивает высокую отказоустойчивость, имеет централизованное управление всеми ресурсами и общую файловую систему и, кроме того, обеспечивает гибкость конфигурации и легкость в наращивании ресурсов.Все узлы кластера объединены в единую сеть, с помощью коммутационных каналов, через которые сервера могут обмениваться информацией. Каждый узел следит за состоянием других узлов, а также отправляет необходимую информацию, которая может включать в себя конфигурационные данные, данные об общих системах хранения и их работоспособности. Процедура обмена данной информацией называется heartbeat («сердцебиение», или «пульс»), и если кластер получил этот сигнал, следовательно сервер-адресант работает исправно. Если в какой-то момент один из узлов перестает посылать heartbeat-сигналы, то остальные узлы начинают считать его неисправным и кластер начинает перенастраиваться. Сигналы «сердцебиения» могут передаваться по одному каналу с какими-либо данным, но при создании крупных систем, лучше выделить для этого другой канал, чтобы не происходила потеря сигнала. С помощью таких сигналов также можно определить узел, который будет контролировать работу остальных узлов.Бывает ситуация, когда приложение перестает быть доступным для пользователя, этот период называется время простоя (или отключения). Есть классификация простоев, которая состоит из двух категорий: запланированные: замена оборудования; обслуживание; обновление программного обеспечения; резервное копирование (автономное резервное копирование); тестирование (периодическое тестирование необходимо для проверки кластеров); разработка; незапланированные: ошибки администратора; отказы приложений; отказы оборудования; ошибки операционной системы; стихийные бедствия. Таким образом, кластерные технологии должны обеспечивать доступность сервиса при любых простоях, как запланированных, так и незапланированных.. Наиболее популярными приложениями, которые лучше запускать в кластерах, являются: базы данных; системы управления ресурсами предприятия (ERP); средства обработки сообщений и почтовые системы; средства обработки транзакций через Web и Web-серверы; системы взаимодействия с клиентами (CRM); системы разделения файлов и печати. Также есть у кластеров есть своя классификация. Обычно различают следующие основные виды кластеров: отказоустойчивые кластеры (High-availability clusters, HA, кластеры высокой доступности) кластеры непрерывной доступности (Fault tolerant) вычислительные кластеры 1.2.1 Высокая доступность. Высокодоступные кластера обозначаются аббревиатурой HA (англ. High Availability — высокая доступность). Данные кластеры позволяют предоставить высокую доступность сервиса. Количество узлов в HA кластере всегда избыточное, чтобы при отказе одного или нескольких, можно было бы запустить сервис на других. Минимальное количество узлов в данном кластере составляет два. В противном случае повысить доступность не получиться. Существует большое количество программ, которое предоставляют решение для HA-кластера.Существует три варианта построение высокодоступного кластера: с холодным резервом или активный/пассивный. В этом случае активный узел обрабатывает все запросы, а пассивный включается в работу только лишь при отказе активного. Пример — резервные сетевые соединения, в частности, Алгоритм связующего дерева. Например связка DRBD и HeartBeat. с горячим резервом или активный/активный. Все ноды принимают и обрабатывают запросы, и при отказе одного из них, нагрузка распределяется по оставшимся нодам. Следовательно, при отказе одного узла кластер переконфигурируется. Примеры — практически все кластерные технологии, например, Microsoft Cluster Server. OpenSource проект OpenMosix. с модульной избыточностью. Данный вариант самый трудозатратый. Его используют только в случаях, когда простой системы невозможен. В это конфигурации один и тот же запрос может выполняться несколькими узлами и выдается результат любого узла. Следовательно, очень важно, чтобы результаты всех узлов были идентичными (либо различия незначительны). Примеры — RAID и Triple modular redundancy. Некоторые решения кластеров могут сочетать несколько вариантов построения кластеров. Так, например, Linux-HA может обслуживать очень рискованные запросы всеми узлами, это называется режим обоюдной поглощающей конфигурации, а другие запросы могут равномерно распределяться между узлами.Высокая доступность кластеризация является метод, используемый для минимизации времени простоя и обеспечить непрерывное обслуживание, когда некоторые компоненты системы терпят неудачу. Kластеры HA состоит из множества узлов, которые взаимодействуют и обмениваются информацией через общие сетках памяти данных и являются отличным способом, чтобы обеспечить высокую доступность системы, надежность и масштабируемость.Учитывая эти разнообразные элементы высоко-доступность требует: Тщательное и полное планирование физических и логических процедур доступа и эксплуатации ресурсов, от которых зависит приложение. Эти процедуры помогают избежать сбоев в первую очередь. Пакет мониторинга и восстановления, что позволяет автоматизировать обнаружение и восстановление после ошибок. Хорошо контролируемый процесс для поддержания аппаратных и программных аспектов конфигурации кластера, сохраняя при этом доступны приложения. Отказоустойчивый кластеры предоставляют решение задач, таких как: 24 часа в сутки 7 дней недели любые приложения готовы к запуску, независимо от отказов в работе операционной системы, устройств хранения, приложения или инфраструктуры; держать очень высокий показатель SLA (перевыполнение обязательств); при предоставляемом оборудовании (базе, инфраструктуре) гарантировать максимальную высокую доступность; обеспечение целостности и доступности приложения в кластере, а также ПО; быстрое восстановление данных при поломках; уменьшение количество сбоев, чтобы не происходило простоев ОС, а также увеличение скорости развертывания нового оборудования; тщательный контроль за доступностью очень важных приложениями, таких как базы данных; гарантирование высокой доступности в виртуальных, реальных и смешанных средах. Преимущества высокой доступности: все компоненты стандартизированы и могут быть запущенные на существующих серверах и машинах; могут кластеризовать большую часть существующих приложений могут работать с очень большим вариантом работают практически со всеми приложениями (зависит только от умения того, кто осуществляет внедрение); работают с большинством существующих типов дисков и сетей; стоимость таких приложений относительно невысока. Непрерывная доступность (Fault tolerant) Для того, чтобы можно было предоставить полностью отказоустойчивый сервис, нужно, чтобы постоянно была точная копия узла, на котором запущен необходимый сервис. При создании копии после поломки оборудования придется потратить некоторое время на копирования или может случиться ситуация, при которой невозможно будет достать необходимую информацию из проблемного узла и это приведет к утере информации.Именно для таких ситуаций существует способ создания непрерывно доступного кластера. Существует два способа реализации такого решения: аппаратный и программный.Аппаратный способПри этом способе создаются два сервера, один из которых выполняет запросы, а другой полностью его копирует. При этом они оба независимо производят вычисления. Также есть узел, который проверяет и сверяет получившиеся результаты и выполняет поиск ошибок. Если невозможно исправить получившуюся ошибку, то сервер, который считается неисправным, отключается.В этом случае оборудование будет простаивать не более 32 секунд в год. Чтобы получить такие результаты необходимо пожертвовать большими деньгами на приобретение данного оборудования. По подсчетам одной российской компании на данный кластер придется потратить порядка $1 600 000Программный способ.Самым известным программным продуктом для реализации непрерывно доступного кластера в настоящее время является vSphere от VMware.Но данный способ реализации имеет свои ограничения, такие как: Определенный процессор на физической машине Intel архитектуры Sandy Bridge (или новее). Avoton не поддерживается. AMD Bulldozer (или новее). Сетка, с пропускной способностью в 10-гигабит, через которую общаются виртуальные машины Количество виртуальных машин на физической не должно превышать 8 Количество виртуальных процессов виртуальной машины не более 4 Количество виртуальных процессов на хосте не более 8 Не поддерживаются снэпшоты ISO-образы должны быть находиться в общем хранилище, чтобы все машины имели к ним доступ. Было проведено несколько экспериментов, результатами которых стал вывод, что при использовании FT от VMware виртуальные машины начинали работать значительно медленнее, производительность упала на

1.3 Рынок

Реализация

2.1 Демон

2.2 Сервисное приложение

2.3 Клиентское приложение.

Вывод.

Список литературы.

Приложение



Файл MainDaemon.cpp
#if !defined(_GNU_SOURCE)

#define _GNU_SOURCE

#endif
#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include "tinystr.h"

#include "tinyxml.h"
#include

#include

#include

#include

#include "string.h"
#include

#include

#include
using namespace std;
// лимит для установки максимально кол-во открытых дискрипторов

#define FD_LIMIT 1024*10
// константы для кодов завершения процесса

#define CHILD_NEED_WORK 1

#define CHILD_NEED_TERMINATE 2
#define PID_FILE "/var/run/my_daemon.pid"

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int node_status;

int need_start_app;

int diff_need_start;

int diff_app_status;

int my_app_status;

time_t last_time;

int stop_app;
int timeout;
string log_file;

string my_ip;

int my_port;

string diff_ip;

int diff_port;

string my_app;
// функция записи лога

int WriteLog(string Msg, ...) {

FILE *f = fopen(log_file.c_str(), "a");

if (f == NULL) {

return -1;

} else {

char buffer[80];

time_t seconds = time(NULL);

struct tm *timeinfo = localtime(&seconds);

strftime(buffer, 80, "%a %B %d %H:%M:%S %Y", timeinfo);

char third[1024];

snprintf(third, sizeof third, "%s\t%s", buffer, Msg.c_str());

fputs(third, f);
}

fclose(f);

return 1;

}
// функция загрузки конфига

int LoadConfig(char* FileName) {

TiXmlDocument *xml_file = new TiXmlDocument(FileName);

if (!xml_file->LoadFile()) {

printf("file have errors");

return -1;

}
TiXmlElement *xml_1 = 0;

xml_1 = xml_file->FirstChildElement();
TiXmlElement *xml_2 = 0;

xml_2 = xml_1->FirstChildElement("log_file");

log_file = xml_2->GetText();

xml_2 = xml_1->FirstChildElement("my_ip");

my_ip = xml_2->GetText();

xml_2 = xml_1->FirstChildElement("listen_port");

my_port = atoi(xml_2->GetText());

xml_2 = xml_1->FirstChildElement("another_ip");

diff_ip = xml_2->GetText();

xml_2 = xml_1->FirstChildElement("another_port");

diff_port = atoi(xml_2->GetText());

xml_2 = xml_1->FirstChildElement("timeout");

timeout = atoi(xml_2->GetText());

xml_2 = xml_1->FirstChildElement("my_app");

my_app = xml_2->GetText();

return 1;

}
void *Client(void*) {

int m_sock; // дескриптор сокета

sockaddr_in m_addr; // переменная адреса интерфейса

sockaddr_in s_addr; // переменная адреса получателя

string my_addr = my_ip; // Адрес локального интерфейса

string ip_addr = diff_ip; // Адрес получателя

/* Создание сокета и присвоение значения дескриптору сокета для UDP пакетов

* PF_INET - IP protocol family

* SOCK_DGRAM - Raw protocol interface */

if ((m_sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {

perror("socket");

pthread_exit(NULL);

}

WriteLog("[CLIENT] Started\n");

/* Обнуляем переменную m_addr и забиваем её нужными значениями */

bzero(&m_addr, sizeof(m_addr));

m_addr.sin_family = AF_INET; // обязательно AF_INET!

m_addr.sin_port = htons(0); // 0 - выдать порт автоматом

/* Переводим адрес в нужный нам формат */

if (inet_aton(my_addr.c_str(), &m_addr.sin_addr) == 0) {

WriteLog("[CLIENT] Creating address failed\n");

perror("inet_aton");

close(m_sock);

pthread_exit(NULL);

}

WriteLog("[CLIENT] Bind\n");

/* Биндим сокет */

if (bind(m_sock, (struct sockaddr*) &m_addr, sizeof(m_addr)) < 0) {

WriteLog("[CLIENT] Bind failed\n");

perror("bind");

close(m_sock);

pthread_exit(NULL);

}

/* Обнуляем переменную s_addr и забиваем её нужными значениями */

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(diff_port);

/* Переводим адрес в нужный нам формат */

if (inet_aton(ip_addr.c_str(), &s_addr.sin_addr) == 0) {

WriteLog("[Client] Inet ation failed\n");

perror("inet_aton");

close(m_sock);

pthread_exit(NULL);

}
/* Засыпаем адресата пачкой пакетов */

string msg;

while (1) {

pthread_mutex_lock(&mutex1);

WriteLog("[CLIENT] Sent\n");

if ((my_app_status == 1) && (diff_need_start == 1)) {

msg = "10";

}

if ((my_app_status == 1) && (diff_need_start == 0)) {

msg = "10";

}

if ((my_app_status == 0) && (diff_need_start == 1)) {

msg = "01";

}

if ((my_app_status == 0) && (diff_need_start == 0)) {

msg = "00";

}

if (sendto(m_sock, msg.c_str(), 3, MSG_NOSIGNAL,

(struct sockaddr*) &s_addr, sizeof(s_addr)) < 0) {

perror("sendto");

close(m_sock);

pthread_exit(NULL);

}

pthread_mutex_unlock(&mutex1);

sleep(2);

}

WriteLog("[CLIENT] Failed/n");

/* Закрываем сокет и выходим из программы */

close(m_sock);

pthread_exit(NULL);

}
void *Server(void*) {

int m_sock; // дескриптор сокета

sockaddr_in m_addr; // переменная адреса интерфейса

string my_addr = my_ip; // Адрес локального интерфейса
/* Создание сокета и присвоение значения дескриптору сокета для UDP пакетов

* PF_INET - IP protocol family

* SOCK_DGRAM - Raw protocol interface */

if ((m_sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {

perror("socket");

pthread_exit(NULL);

}

WriteLog("[SERVER] Started\n");

/* Обнуляем переменную m_addr и забиваем её нужными значениями */

bzero(&m_addr, sizeof(m_addr));

m_addr.sin_family = AF_INET; // обязательно AF_INET!

m_addr.sin_port = htons(my_port); // 0 - выдать порт автоматом

/* Переводим адрес в нужный нам формат */

if (inet_aton(my_addr.c_str(), &m_addr.sin_addr) == 0) {

WriteLog("[SERVER] Creating address failed\n");

perror("inet_aton");

close(m_sock);

pthread_exit(NULL);

}

WriteLog("[SERVER] Bind\n");

/* Биндим сокет */

if (bind(m_sock, (struct sockaddr*) &m_addr, sizeof(m_addr)) < 0) {

WriteLog("[SERVER] Bind failed\n");

perror("bind");

close(m_sock);

pthread_exit(NULL);

}
/* Получаем пакеты от отправителя */

char recvline[3];

int bytesrecv;

while (1) {

if ((bytesrecv = recvfrom(m_sock, recvline, 3, MSG_NOSIGNAL,

(sockaddr*) NULL, NULL)) < 0) {

perror("recvfrom");

close(m_sock);

pthread_exit(NULL);

}

pthread_mutex_lock(&mutex1);

last_time = time(NULL);

if (node_status == 0) {

WriteLog("[SERVER] Another node online\n");

node_status = 1;
}

WriteLog("[SERVER] Heartbeat\n");

if (strcmp(recvline, "00") == 0) {

diff_app_status = 0;

}

if (strcmp(recvline, "01") == 0) {

if ((my_app_status == 0) && (diff_app_status == 0)) {

need_start_app = 1;

}

}

if (strcmp(recvline, "10") == 0) {

diff_app_status == 1;

}

pthread_mutex_unlock(&mutex1);

}
/* Закрываем сокет и выходим из программы */

WriteLog("[SERVER] Failed/n");

close(m_sock);

pthread_exit(NULL);

}
void *Monitoring(void*) {

WriteLog("[MONITOR] Started\n");

while (1) {

pthread_mutex_lock(&mutex1);

WriteLog("[MONITOR] Status check\n");

stringstream ss;

if (need_start_app == 1) {

need_start_app = 0;

if ((my_app_status == 0) && (diff_app_status == 0)) {

WriteLog("[MONITOR] Start application\n");

my_app_status = 1;

//start app

}

}

if (node_status == 1) {

time_t current_time = time(NULL);

double diff = difftime(current_time, last_time);

if (diff > timeout) {

WriteLog("[MONITOR] Another node offline\n");

node_status = 0;

WriteLog(

"[MONITOR] Checking the status of the another application\n");

if (diff_app_status == 1) {

WriteLog("[MONITOR] Start application\n");

diff_app_status = 0;

my_app_status = 1;

//need start app

} else {

WriteLog(

"[MONITOR] Application on another server is not running\n");

}

}

}

pthread_mutex_unlock(&mutex1);

sleep(7);

}

pthread_exit(NULL);

}

// функция мониторинга

int InitWorkThread() {

int rc1, rc2, rc3;

pthread_t thread1, thread2, thread3;

/* Create independent threads each of which will execute functionC */
if ((rc1 = pthread_create(&thread1, NULL, &Client, NULL))) {

WriteLog("[DEAMON] Client creation failed");

}
if ((rc2 = pthread_create(&thread2, NULL, &Server, NULL))) {

WriteLog("[DEAMON] Server creation failed");

}

if ((rc3 = pthread_create(&thread3, NULL, &Monitoring, NULL))) {

WriteLog("[DEAMON] Monitor creation failed");

}
/* Wait till threads are complete before main continues. Unless we */

/* wait we run the risk of executing an exit which will terminate */

/* the process and all threads before the threads have completed. */
pthread_join(thread1, NULL);

pthread_join(thread2, NULL);

pthread_join(thread3, NULL);
return 1;

}

// функция обработки сигналов

static void signal_error(int sig, siginfo_t *si, void *ptr) {

void* ErrorAddr;

void* Trace[16];

int x;

int TraceSize;

char** Messages;
// запишем в лог что за сигнал пришел

WriteLog("[DAEMON] Signal: %s, Addr: 0x%0.16X\n", strsignal(sig),

si->si_addr);

/*

#if __WORDSIZE == 64 // если дело имеем с 64 битной ОС

// получим адрес инструкции которая вызвала ошибку

ErrorAddr = (void*)((ucontext_t*)ptr)->uc_mcontext.gregs[REG_RIP];

#else

// получим адрес инструкции которая вызвала ошибку

ErrorAddr = (void*) ((ucontext_t*) ptr)->uc_mcontext.gregs[REG_EIP];

#endif

*/

// произведем backtrace чтобы получить весь стек вызовов

TraceSize = backtrace(Trace, 16);

Trace[1] = ErrorAddr;
// получим расшифровку трасировки

Messages = backtrace_symbols(Trace, TraceSize);

if (Messages) {

WriteLog("== Backtrace ==\n");
// запишем в лог

for (x = 1; x < TraceSize; x++) {

WriteLog("%s\n", Messages[x]);

}
WriteLog("== End Backtrace ==\n");

free(Messages);

}
WriteLog("[DAEMON] Stopped\n");
// остановим все рабочие потоки и корректно закроем всё что надо

DestroyWorkThread();
// завершим процесс с кодом требующим перезапуска

exit(CHILD_NEED_WORK);

}
// функция установки максимального кол-во дескрипторов которое может быть открыто

int SetFdLimit(int MaxFd) {

struct rlimit lim;

int status;
// зададим текущий лимит на кол-во открытых дискриптеров

lim.rlim_cur = MaxFd;

// зададим максимальный лимит на кол-во открытых дискриптеров

lim.rlim_max = MaxFd;
// установим указанное кол-во

status = setrlimit(RLIMIT_NOFILE, &lim);
return status;

}
int WorkProc() {

struct sigaction sigact;

sigset_t sigset;

int signo;

int status;

// сигналы об ошибках в программе будут обрататывать более тщательно

// указываем что хотим получать расширенную информацию об ошибках

sigact.sa_flags = SA_SIGINFO;

// задаем функцию обработчик сигналов

sigact.sa_sigaction = signal_error;
sigemptyset(&sigact.sa_mask);
// установим наш обработчик на сигналы
sigaction(SIGFPE, &sigact, 0); // ошибка FPU

sigaction(SIGILL, &sigact, 0); // ошибочная инструкция

sigaction(SIGSEGV, &sigact, 0); // ошибка доступа к памяти

sigaction(SIGBUS, &sigact, 0); // ошибка шины, при обращении к физической памяти
sigemptyset(&sigset);
// блокируем сигналы которые будем ожидать

// сигнал остановки процесса пользователем

sigaddset(&sigset, SIGQUIT);
// сигнал для остановки процесса пользователем с терминала

sigaddset(&sigset, SIGINT);
// сигнал запроса завершения процесса

sigaddset(&sigset, SIGTERM);
// пользовательский сигнал который мы будем использовать для обновления конфига

sigaddset(&sigset, SIGUSR1);

sigprocmask(SIG_BLOCK, &sigset, NULL);
// Установим максимальное кол-во дискрипторов которое можно открыть

SetFdLimit(FD_LIMIT);
// запускаем все рабочие потоки

status = InitWorkThread();

if (!status) {

// цикл ожижания сообщений

for (;;) {

// ждем указанных сообщений

sigwait(&sigset, &signo);

break;

}

}
WriteLog("[MONITOR] Stopped/n");
// вернем код не требующим перезапуска

return CHILD_NEED_TERMINATE;

}
void SetPidFile(string Filename) {

FILE* f;
f = fopen(Filename.c_str(), "w+");

if (f) {

fprintf(f, "%u", getpid());

fclose(f);

}

}

void Init_vars() {

node_status = 0;

need_start_app = 0;

diff_app_status = 0;

my_app_status = 0;

stop_app = 0;

diff_need_start = 0;

last_time = time(NULL);
}
int Daemon() {

int pid;

int status;

int need_start = 1;

sigset_t sigset;

siginfo_t siginfo;

WriteLog("[DAEMON] Started\n");

// настраиваем сигналы которые будем обрабатывать

sigemptyset(&sigset);
// сигнал остановки процесса пользователем

sigaddset(&sigset, SIGQUIT);
// сигнал для остановки процесса пользователем с терминала

sigaddset(&sigset, SIGINT);
// сигнал запроса завершения процесса

sigaddset(&sigset, SIGTERM);
// сигнал посылаемый при изменении статуса дочернего процесс

sigaddset(&sigset, SIGCHLD);
// сигнал посылаемый при изменении статуса дочернего процесс

sigaddset(&sigset, SIGCHLD);
// пользовательский сигнал который мы будем использовать для обновления конфига

sigaddset(&sigset, SIGUSR1);

sigprocmask(SIG_BLOCK, &sigset, NULL);
// данная функция создат файл с нашим PID'ом

SetPidFile(PID_FILE);
Init_vars();
// создаём потомка

pid = fork();
if (pid == -1) // если произошла ошибка

{

// запишем в лог сообщение об этом

WriteLog("[MONITOR] Fork failed (%s)\n", strerror(errno));

} else if (!pid) // если мы потомок

{

// данный код выполняется в потомке
// запустим функцию отвечающую за работу демона

status = WorkProc();
// завершим процесс

exit(status);

} else // если мы родитель

{

for (;;) {

// данный код выполняется в родителе
// ожидаем поступление сигнала

sigwaitinfo(&sigset, &siginfo);
// если пришел сигнал от потомка

if (siginfo.si_signo == SIGCHLD) {

// получаем статус завершение

wait(&status);
// преобразуем статус в нормальный вид

status = WEXITSTATUS(status);
// если потомок завершил работу с кодом говорящем о том, что нет нужны дальше работать

if (status == CHILD_NEED_TERMINATE) {

// запишем в лог сообщени об этом

WriteLog("[DAEMON] Childer stopped\n");
// прервем цикл

break;

} else if (status == CHILD_NEED_WORK) // если требуется перезапустить потомка

{

// запишем в лог данное событие

WriteLog("[DAEMON] Childer restart\n");

}

} else // если пришел какой-либо другой ожидаемый сигнал

{

// запишем в лог информацию о пришедшем сигнале

WriteLog("[DAEMON] Signal %s\n", strsignal(siginfo.si_signo));
// убьем потомка

kill(pid, SIGTERM);

status = 0;

break;

}

}

}
// запишем в лог, что мы остановились

WriteLog("[DAEMON] Stopped\n");
// удалим файл с PID'ом

unlink(PID_FILE);
return status;

}
int main(int argc, char** argv) {

int status;

int pid;
// если параметров командной строки меньше двух, то покажем как использовать демана

if (argc != 2) {

printf("Usage: ./my_daemon filename.cfg\n");

return -1;

}
// загружаем файл конфигурации

status = LoadConfig(argv[1]);

if (!status) // если произошла ошибка загрузки конфига

{

printf("Error: Load config failed\n");

WriteLog("Error: Load config failed\n");

return -1;

}

FILE *f = fopen(log_file.c_str(), "w");

if (f == NULL) {

printf("Could not open log file");

} else {

char buffer[80];

time_t seconds = time(NULL);

struct tm *timeinfo = localtime(&seconds);

strftime(buffer, 80, "%a %B %d %H:%M:%S %Y", timeinfo);

char third[1024];

snprintf(third, sizeof third, "%s\t%s", buffer, "Start\n");

fputs(third, f);
}

fclose(f);

// создаем потомка

pid = fork();
if (pid == -1) // если не удалось запустить потомка

{

// выведем на экран ошибку и её описание

printf("Start Daemon Error: %s\n", strerror(errno));
return -1;

} else if (!pid) // если это потомок

{

// данный код уже выполняется в процессе потомка

// разрешаем выставлять все биты прав на создаваемые файлы,

// иначе у нас могут быть проблемы с правами доступа

umask(0);
// создаём новый сеанс, чтобы не зависеть от родителя

setsid();
// переходим в корень диска, если мы этого не сделаем, то могут быть проблемы.

// к примеру с размантированием дисков

chdir("/");

printf("run!");

// закрываем дискрипторы ввода/вывода/ошибок, так как нам они больше не понадобятся

close(STDIN_FILENO);

close(STDOUT_FILENO);

close(STDERR_FILENO);
// Данная функция будет осуществлять слежение за процессом

status = Daemon();
return status;

} else // если это родитель

{

// завершим процес, т.к. основную свою задачу (запуск демона) мы выполнили

return 0;

}

}

Service.py

from flask import Flask, render_template, redirect, url_for

from flask import request

app = Flask(__name__)

app_status="off"

node_status="on"

@app.route('/', methods=['GET', 'POST'])

def contact():

global app_status

global node_status

if request.method == 'POST':

if request.form['submit'] == 'This node':

app_status= "on"

return redirect(url_for('.contact'))

elif request.form['submit'] == 'Another node':

app_status="on"

return redirect(url_for('.contact'))

elif request.form['submit'] == 'Stop app':

app_status="off"

return redirect(url_for('.contact'))

else:

pass # unknown

elif request.method == 'GET':

return render_template('index_3.html',node_status=node_status, app_statu s=app_status )

if __name__ == '__main__':

app.run(host='0.0.0.0',port=8081,debug=True)

Client.py

from flask import Flask, render_template, redirect, url_for

from flask import request

app = Flask(__name__)

@app.route('/test', methods=['GET', 'POST'])

def contact1():

if request.method == 'POST':

if request.form['submit'] == 'Return':

return redirect(url_for('.contact'))

#pass # do somethin

#print "Left gjhgjh"

else:

pass # unknown

elif request.method == 'GET':

return render_template('index_2.html')

@app.route('/', methods=['GET', 'POST'])

def my_client():

if request.method == 'POST':

if request.form['submit'] == 'Left':

#pass # do somethin

print ("Left")

return redirect(url_for('.my_client'))

elif request.form['submit'] == 'Right':

print ("Roght")

return redirect(url_for('. my_client'))

else:

pass # unknown

elif request.method == 'GET':

return render_template('index.html')

if __name__ == '__main__':

app.run(host='0.0.0.0',port=8081,debug=True)

index.html







Client











Service app



Node 1






Anoter node status: {{node_status}}

Application status: {{app_status}}


{% if app_status in "on" %}



{% else %}

{% if node_status in "off" %}


Run application on:




{% else %}


Run application on:






{% endif %}

{% endif %}



1   2   3   4   5   6