Решил написать не сложную утили для мониторинга сети в фоновом режиме отслеживающую главные показатели и сохраняя их в логи. Все это будет работать под виндой, по этому будем изучать новый язык C#. По чему Си шарп, по тому что так проще для новичка. То есть меня )))
Задачи.
- Пинга до заданого хоста.
- Возможность подключиться по TCP.
- Доступность роутера и т.п.
Так как программа будет работать в фоновом режиме, оформим ее как системный сервис (для упрощения и отладки сделал пока консольный вариант). Проверка не должна загружать канал, так что не будем флудить пингом и т.д. Будем отправлять несколько запросов раз в две — три минуты. Сохранять логи, загружать настройки будем в каком нибудь удобном формате: JSON и CSV.
Подготовка.
Я скачал Visual Studio с сайта Микрософт. Добавляем подержу .NET и C# при установке . Ну и создаем проект консольной программы для Windos на C#. Запускаем, вроде все работает.



Настраиваем MSI Afterburner — Мониторинг, фпс, frametime, железо в оверлее
Для нашей программы нам потребуются настройки (IP хоста, порт, задержка и т.д.).Сделаем файл настроек из которого будем загружать данные. Составим список настроек, определимся с форматом переменных для этих значение:
- Хост и порт для которого мы будет проверять доступность HTTP. Так же зададим и ТАЙМ-АУТ для подключения.
- Количество пакетов Ping и их тайм-аут. Задержка между отправлениями пакетов.
- Хост который будем пинговать.
- IP адрес роутера. Если роутер не доступен то зачем вообще делать все остальное )
- Максимальный уровень packet loss, при котором подключение считается нормальным.
- Выходной файл CSV, в который будут дописываться результаты.
- Изюминка: выходной формат строки для CSV, если ты вдруг решишь отключить вывод ненужных столбцов или изменить порядок.
- Возможность отключить логирование.
Сделаем все современненько, файл настроек будет в формате JSON — setting.json .
JSON (англ. JavaScript Object Notation) — текстовый формат обмена данными, основанный на JavaScript. Как и многие другие текстовые форматы, JSON легко читается людьми. Формат JSON был разработан Дугласом Крокфордом.
JSON-текст представляет собой (в закодированном виде) одну из двух структур:
Набор пар ключ: значение. В различных языках это реализовано как запись, структура, словарь, хеш-таблица, список с ключом или ассоциативный массив. Ключом может быть только строка (регистрозависимая: имена с буквами в разных регистрах считаются разными), значением — любая форма.
Упорядоченный набор значений. Во многих языках это реализовано как массив, вектор, список или последовательность.
< «http_test_host»: «api.ipify.org», «http_test_port»: «80», «http_timeout»: «3000», «ping_count»: «10», «ping_timeout»: «3000», «ping_packet_delay»: «0», «ping_hosts»: [ «ya.ru», «1.1.1.1» ], «measure_delay»: «60000», «cui_output»: «true», «router_ip»: «192.168.0.1», «nq_max_loss»: «0,1», «out_file»: «log.csv», «w_csv»: «true», «out_format»: «FTIME;STIME;IUP;HTTP;AVGRTT;ROUTERRTT;LOSS;RN» >// RN — маркер конца строки
Кодинг.
Первым делом объявим переменные для настроек :
static String HTTP_TEST_HOST; // HTTP сервер, соединение до которого будем тестировать static int HTTP_TEST_PORT; // Порт HTTP сервера static int HTTP_TIMEOUT; // Таймаут подключения static int PING_COUNT; // Количество пакетов пинга static int PING_DELAY; // Ожидание перед отправкой следующего пакета пинга static int PING_TIMEOUT; // Таймаут пинга static List PING_HOSTS; // Хосты, пинг до которых меряем static int MEASURE_DELAY; // Время между проверками static String ROUTER_IP; // IP роутера static double MAX_PKT_LOSS; // Максимально допустимый Packet loss static String OUT_FILE; // Выходной файл CSV static bool WRITE_CSV; // Писать ли CSV static String CSV_PATTERN; // Шаблон для записи в CSV // Промежуточные переменные static bool prev_inet_ok = true; static DateTime first_fail_time; static long total_time = 0; static int pkt_sent = 0; static int success_pkts = 0; static int exited_threads = 0; static Dictionary measure_results = new Dictionary();
Теперь нам надо загрузить настройки в переменные. Для работы с форматом JSON будем использовать библиотеку Json.NET .
Json.NET — популярная и простая библиотека для работы с JSON.
https://www.nuget.org/packages/Newtonsoft.Json/
Теперь загружаем данные из файла :
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Threading; using System.Net.Sockets; using System.Net.NetworkInformation; var config = JsonConvert.DeserializeObject>(File.ReadAllText(«setting.json»)); HTTP_TEST_HOST = (String)config[«http_test_host»]; PING_HOSTS = ((JArray)config[«ping_hosts»]).ToObject>(); ROUTER_IP = (String)config[«router_ip»]; HTTP_TEST_PORT = int.Parse((String)config[«http_test_port»]); HTTP_TIMEOUT = int.Parse((String)config[«http_timeout»]); PING_COUNT = int.Parse((String)config[«ping_count»]); PING_TIMEOUT = int.Parse((String)config[«ping_timeout»]); PING_DELAY = int.Parse((String)config[«ping_packet_delay»]); MEASURE_DELAY = int.Parse((String)config[«measure_delay»]); OUT_FILE = (String)config[«out_file»]; WRITE_CSV = bool.Parse((String)config[«w_csv»]); CSV_PATTERN = (String)config[«out_format»]; MAX_PKT_LOSS = double.Parse((String)config[«nq_max_loss»]); Console.WriteLine(«Load config complit. «);
Теперь мы создадим понятные заголовки для файла CSV и запишем их в файл.
String CSV_HEADER = CSV_PATTERN .Replace(«FTIME», «Data») .Replace(«IUP», «Internet up») .Replace(«AVGRTT», «Average ping (ms)») .Replace(«ROUTERRTT», «Ping to router (ms)») .Replace(«LOSS», «Packet loss, %») .Replace(«HTTP», «HTTP OK») .Replace(«STIME», «Time»); foreach (var host in PING_HOSTS) < CSV_HEADER = CSV_HEADER.Replace(«RN», $»Ping to ;RN»); > CSV_HEADER = CSV_HEADER.Replace(«RN», «rn»); if (WRITE_CSV) // Если запись включена в настройках создать файл и записать заголовки. < // Если файла нету , создать и записать заголовки. if (!File.Exists(OUT_FILE)) File.WriteAllText(OUT_FILE, CSV_HEADER); >
Во время мониторинга программа будет собирать много данных, давайте выделим из в отдельную структура.
struct net_state < public bool inet_ok; // Флаг доступности сети public bool http_ok; // Флаг теста http public Dictionaryavg_rtts; // Словарь пинга до хостов public double packet_loss; // Потеря пакетов public DateTime measure_time; // Дата, время public int router_rtt; // >
Давайте теперь напишем функцию записи данных в лог файл:
static void Save_log(net_state snapshot) < if (WRITE_CSV) // Если запись логов включена < String rtts = «»; int avg_rtt = 0; foreach (var ci in PING_HOSTS) < rtts += $»;»; avg_rtt += snapshot.avg_rtts[ci]; > avg_rtt = avg_rtt / PING_HOSTS.Count; File.AppendAllText(OUT_FILE, CSV_PATTERN .Replace(«FTIME», snapshot.measure_time.ToShortDateString()) .Replace(«IUP», snapshot.inet_ok.ToString()) .Replace(«AVGRTT», avg_rtt.ToString()) .Replace(«ROUTERRTT», snapshot.router_rtt.ToString()) .Replace(«LOSS», snapshot.packet_loss.ToString()) .Replace(«HTTP», snapshot.http_ok.ToString()) .Replace(«STIME», snapshot.measure_time.ToShortTimeString()) .Replace(«RN», $»rn»)); > >
Теперь пишем основную часть кода, сам мониторинг в отдельной функции. Проверяем доступность роутера,если не доступен то записываем лог и выходим. Потом проверяем HTTP соединение, затем пингуем заданные хосты.
static void Monit() < // Создаем экземпляр измерений. net_state snapshot = new net_state(); snapshot.inet_ok = true; snapshot.measure_time = DateTime.Now; // Проверяем доступность роутера Ping ping = new Ping(); var prr = ping.Send(ROUTER_IP, PING_TIMEOUT); // В CSV файле все поля должны быть заполнены. Если роутер не пингуется заполняем их параметром PING_TIMEOUT snapshot.router_rtt = prr.Status == IPStatus.Success ? (int)prr.RoundtripTime : PING_TIMEOUT; if (prr.Status != IPStatus.Success) < snapshot.avg_rtts = new Dictionary(); snapshot.http_ok = false; snapshot.inet_ok = false; snapshot.packet_loss = 1; foreach (var ci in PING_HOSTS) < snapshot.avg_rtts.Add(ci, PING_TIMEOUT); >Console.WriteLine(«Router was unreachable.»); Save_log(snapshot); return; > snapshot.inet_ok = true; // Проверяем доступность HTTP try < snapshot.http_ok = true; TcpClient tc = new TcpClient(); tc.BeginConnect(HTTP_TEST_HOST, HTTP_TEST_PORT, null, null); Thread.Sleep(HTTP_TIMEOUT); // Если подключиться не удалось if (!tc.Connected) < snapshot.http_ok = false; >tc.Dispose(); > catch < snapshot.http_ok = false; snapshot.inet_ok = false; >//Теперь пингуем заданные хосты exited_threads = 0; pkt_sent = 0; success_pkts = 0; total_time = 0; measure_results = new Dictionary(); // Перебираем все хосты и запускаем пинг в отдельном потоке. foreach (var ci in PING_HOSTS) < Thread thread = new Thread(new ParameterizedThreadStart(PingTest)); thread.Start(ci); >while (exited_threads < PING_HOSTS.Count) continue; //Анализируем результаты пинга snapshot.avg_rtts = measure_results; snapshot.packet_loss = (double)(pkt_sent — success_pkts) / pkt_sent; snapshot.inet_ok = !( snapshot.http_ok == false || ((double)total_time / success_pkts >= 0.75 * PING_TIMEOUT) || snapshot.packet_loss >= MAX_PKT_LOSS || snapshot.router_rtt == PING_TIMEOUT); Save_log(snapshot); if (prev_inet_ok !snapshot.inet_ok) < //Интернет был , но теперь неудачу prev_inet_ok = false; first_fail_time = DateTime.Now; >else if (!prev_inet_ok snapshot.inet_ok)
Так как хостов для пинга у нас может быть сколько угодно и количество пингов тоже. Выделим процес самого пинга в отдельную функцию PingTest()
static void PingTest(Object arg) < String host = (String)arg; int pkts_lost_row = 0; int local_success = 0; long local_time = 0; Ping ping = new Ping(); // Запускаем пинг заданное количество раз. for (int i = 0; i < PING_COUNT; i++) < // Если потеряно 3 пакеты, записываем результаты и выходим из цикла if (pkts_lost_row == 3) < measure_results.Add(host, (int)(local_time / (local_success == 0 ? 1 : local_success))); exited_threads++; return; >try < var result = ping.Send(host, PING_TIMEOUT); // Если пинг прошел if (result.Status == IPStatus.Success) < pkts_lost_row = 0; local_success++; // RoundtripTime Возвращает количество миллисекунд, затраченных на отправку Эхо-запроса local_time += result.RoundtripTime; total_time += result.RoundtripTime; pkt_sent++; success_pkts++; >switch (result.Status) < case IPStatus.Success: break; //Already handled case IPStatus.BadDestination: measure_results.Add(host, -1); exited_threads++; return; case IPStatus.DestinationHostUnreachable: case IPStatus.DestinationNetworkUnreachable: case IPStatus.DestinationUnreachable: measure_results.Add(host, -1); exited_threads++; return; case IPStatus.TimedOut: pkts_lost_row++; pkt_sent++; break; default: measure_results.Add(host, -1); exited_threads++; return; >> catch (Exception xc) < exited_threads++; measure_results.Add(host, -1); return; >> measure_results.Add(host, (int)(local_time / (local_success == 0 ? 1 : local_success))); exited_threads++; return; >
Теперь осталось зациклить вызов Monit() и поставить задержу между тестами.
while (true)
Вот такой отчет получился у меня.

Думаю тут будет совсем не сложно добавить любой функционал который вам нужен. Например отправку сообщение о сбое в Телеграм.
Скачать код целиком можно с нашего сайте.
В статье использовался материал журнала Хакер( https://xakep.ru).
Ошибка в тексте? Выделите её и нажмите «Ctrl + Enter»
Источник: xn--90aeniddllys.xn--p1ai
C#. Создание приложения для отслеживания счетов. Часть 1
От автора: программирование — очень полезный навык не только в высоких технологиях. В этом уроке Вы увидите, как создать основу для небольшого приложения по отслеживанию счетов. Чтобы сохранять приложение как можно более простым — будем использовать ASP .NET Razor Pages.
По итогам урока Вы узнаете: как создавать шаблоны страниц с кодогенератором .NET Core; как управлять маршрутизацией; как автоматизировать некоторые операции с помощью командной оболочки Powershell.
Профессия PHP-разработчик с нуля до PRO
Готовим PHP-разработчиков с нуля
Вы с нуля научитесь программировать сайты и веб-приложения на PHP, освоите фреймворк Laravel, напишете облачное хранилище и поработаете над интернет-магазином в команде. Сможете устроиться на позицию Junior-разработчика.
Источник: webformyself.com