Шаг 193 - Доступ к System Monitor из Net

Раньше создание счётчиков на 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();
}

Загрузить проект | Предыдущий Шаг | Оглавление
Автор Leonid Molochniy - 26.07.2002