Раньше создание счётчиков на VC++ было весьма сложным делом(про создание счётчиков на Visual C++ читать Рихтера "Программирование серверных приложений для Windows 2000"), но с выходом .Net всё изменилось. В .Net уже встроены объекты, которые позволяют очень быстро создавать счётчики. Мы на примере постараемся создать счётчики, которые бы подсчитывали количество принятых байт в секунду(объяснять как перехватывать пакеты не буду, читайте MSDN и PSDK, там кажется есть про Raw сокеты, если лень там искать читайте на www.firststeps.ru).
Попытаюсь отобразить на схеме, что мы хотим получить:
Category: Traffic IGMP ICMP TCP UDP Unknown Counter: 10.100.100.130 Yes yes yes yes yes Counter:80.1.0.73 Yes yes yes yes yes
То - есть нам нужно создать категорию Traffic(Performance object), далее создать счётчики по IP, у меня на машине их на самом деле больше, чем указано в таблице и потом несколько экземпляров для каждого ip(icmp, tcp и т.д. пакеты).
Для работы с категориями используются объекты:
System.Diagnostics.PerformanceCounterCategory
сперва мы должны проверить, создана ли уже категория Traffic, для этого воспользуемся, статическим методом Exists.
if(!PerformanceCounterCategory.Exists(_CategoryName)) { ...... }
Далее нам нужно создать счётчики для этой категории, для этого воспользуемся классом:
System.Diagnostics.CounterCreationData
Этот класс описывает счётчик, попробуем создать описание счётчика:
CounterCreationData ccd = new CounterCreationData(); ccd.CounterType = PerformanceCounterType.NumberOfItems32; ccd.CounterName = _ip;
CounterName - это имя счётчика, которое будет отображаться при выборе счётчика в диалоговом окне. Особое внимание стоит уделить CounterType - это тип счётчика. Тип PerformanceCounterType.
Некоторые типы счётчиков представляют собой просто данные, в то время как другие могут представлять вычисляемые значения на основе нескольких других счётчиков попробую описать основные категории:
Average: обычно отображает среднее значение последних двух значений.
Difference: обычно разница между двумя последними значениями. Если эта разница положительная, то всё в порядке иначе 0
Instantaneous: отображают последние значение измерения
Percentage: отображает вычисляемое значение в процентах
Rate: обычно используется для отображения увеличивающихся данных, похожи на Average, но полезны когда увеличивается показатель, как используется ресурс. Вычисляется по формуле ((Xn -X 0)/(T n -T 0))/ frequency, где Xn - это N значение, Tn - время когда было получено Xn, а frequency - кажется количество тиков в секунду(обычно они используются для счётчиков типа "операций в секунду")
Для каждого типа счётчика используются свои формулы или используется несколько счётчиков(сперва должен идти счётчик одного типа, за ним другого и основе их значений вычисляется значение). Более подробно вы можете почитать про это в SDK. Так как нам ничего такого не надо мы будем использовать просто счётчики типа NumberOfItems32.
итак после создания класса описания счётчика мы добавляем его в коллекцию типа CounterCreationDataCollection.
ccds = new CounterCreationDataCollection(); for(...) { ccds.Add(ccd); }
И создаём категорию:
PerformanceCounterCategory.Create(_CategoryName, _CategoryHelp,ccds);
Только вот странно если категория создана, то мы почему-то не можем добавлять в неё счётчики, хотя по идее можно :(.
Итак теперь для работы со счётчиками нам нужно создать объекты PerformanceCounter
Для этого воспользуемся конструктором типа
PerformanceCounter(_CategoryName, _CounterName, _Instancse, _readwrite);
У меня они вызываются следующим образом:
PerformanceCounter(_CategoryName, _ip, "IGMP", false);
После чего вызываю функцию UpdateInstances() для создания остальных экземпляров. Тело функции:
public void UpdateInstances() { if(_counter != null) { _counter.InstanceName = "IGMP"; _counter.RawValue = igmp_total; _counter.InstanceName = "ICMP"; _counter.RawValue = icmp_total; _counter.InstanceName = "TCP"; _counter.RawValue = tcp_total; _counter.InstanceName = "UDP"; _counter.RawValue = udp_total; } }
Нам остаётся только каждую, секунду обновлять значение счётчика(я для этого воспользовался объектом Timer).
private void OnTimer(object sender, System.EventArgs e) { _PerformanceObject.UpdateAllCounters(); }