Упрощаем управление серверами, работающими с потоковыми данными

Для тех, кто не имел дела с потоковыми данными и пакетом WMS, я сначала немного расскажу об этих понятиях. Затем я продемонстрирую, как писать сценарии, получающие информацию от WMS и управляющие этими службами.

Что такое потоковые данные?

Потоковые данные – это аудио, видео и любые другие данные, передаваемые по сети в реальном времени. Можно постоянно принимать определенную информацию или получать ее по запросу.

Потоковое вещание. Потоковое вещание напоминает кабельный телеканал. Чтобы посмотреть любимую передачу, мы настраиваем свой телевизор или кабельную приставку на определенную станцию вещания и начинаем получать сигнал практически мгновенно. Нам не приходится ждать, пока передаваемая информация загрузится на диск, она воспроизводится одновременно с приемом данных.

При работе в реальном времени потоковые данные становятся идеальным средством демонстрации различных развлекательных мероприятий посредством сети. Концерты могут транслироваться как «вживую» так и в записи, но они рассматриваются как информация, предназначенная для множества людей. Как и в случае с телеканалом, потоковое вещание может приниматься одновременно множеством пользователей. Поэтому все зрители в любой момент времени видят одинаковую картинку.

Многие сетевые радиостанции и музыкальные службы широко используют преимущества потокового вещания для трансляции музыки, радиопередач и других видов информации. Во многих отраслях бизнеса потоковое вещание применяется для снижения затрат и сообщения сотрудникам о важных решениях. Например, вместо того, чтобы отправлять служащих из региональных офисов по всему миру и размещать их в отелях ради проведения конференции или собрания, многие компании организуют такие мероприятия через защищенную корпоративную сеть или даже посредством Internet.

Заказываемые потоки данных. Если просмотр потокового вещания можно сравнить с передачей по кабельному телевидению, то просмотр заказываемого потока аналогичен просмотру фильма на DVD. Вы можете просматривать заказываемый поток данных в любой момент и прерывать просмотр, когда пожелаете.

Некоторые компании используют заказываемые потоки в учебных классах. Собрать сотрудников на специализированный тренинг может быть непросто, поэтому имеет смысл предложить коллегам просмотреть учебную информацию в удобное для них время. А поскольку тренинг представляет собой заказываемый поток, пользователи могут приостановить тренинг, чтобы ответить по телефону или поесть, вернуться к непонятому разделу и даже ускорить воспроизведение информации, если она выдается слишком медленно.

В пакете WMS появился новый режим, FastCache, который разрешает передачу заказываемых потоков со скоростью большей, чем реальная скорость воспроизведения потока. При вещании в режиме FastCache клиент осуществляет кэширование информации одновременно с ее воспроизведением. Так как скорость приема выше, чем скорость воспроизведения, можно завершить кэширование информации до того, как завершится воспроизведение. В этом случае остаток информации воспроизводится из кэша на диске. В дальнейшем перенос информации с сервера не осуществляется, даже при остановке, воспроизведении или перемотке.

Что такое WMS?

Пакет WMS (также известный как WMS 9 Series), часть платформы Windows 2003, предлагает простой в использовании интерфейс, совмещенный с мощным сервером потоковых данных. В отличие от своего предшественника WMS 4.1, который поставлялся с системой Windows 2000 Server, пакет WMS 9 Series является простым в использовании, более гибким и обладает лучшей масштабируемостью.

Версия WMS, которая выпускается в комплекте с системой Windows 2003 Standard Edition, отличается от версии, поставляемой с системой Windows 2003 Enterprise Edition. Корпоративная версия WMS предоставляет больше возможностей, таких как поддержка встраиваемых модулей создания сценариев событий. Вне зависимости от установленной версии, можно использовать язык Perl для взаимодействия с WMS.

Все средства Windows Media, необходимые для создания, распространения и воспроизведения аудио и видео информации, предоставляются бесплатно. Для создания информации используются службы Windows Movie Maker и Windows Media Encoder. После того как информация создана, WMS применяется для ее передачи непосредственно на проигрыватель или на другой сервер (в целях распространения). Альтернативный вариант: вы принимаете потоковое вещание со средства кодирования и передаете информацию на серверы и проигрыватели. Windows Media Player (WMP) используется для приема и интерпретации информации. Система доступна целиком и не требует покупки дополнительных лицензий для каждого потока. Более подробную информацию о средствах Windows Media можно найти на сайте http://www.windowsmedia.com.

Создание сценариев для WMS

Полезная особенность WMS заключается в том, что полная объектная модель WMS 9 Series поддается описанию с точки зрения сценариев, то есть мы можем использовать языки написания сценариев, такие как Perl, VBScript и JavaScript для взаимодействия с WMS. Такая поддержка написания сценариев является идеальной. Можно писать сценарии, а затем запускать их из командной строки, или создавать Web-страницы на базе элементов Active Server Pages (ASP), которые смогут взаимодействовать с имеющимся сервером WMS.

Набор для разработки программного обеспечения (SDK) для WMS 9 Series включает все необходимое для создания кода, который будет взаимодействовать с WMS. Набор SDK доступен на сайте Microsoft Developer Network (MSDN) по адресу http://msdn.microsoft.com/library/en-us/wmsrvsdk/htm/aboutwindowsmediasdk.asp.

Первый вопрос, на который должен ответить создатель сценариев под WMS, - «С чего начать?». При использовании языка Perl начинать необходимо с добавления кода, приведенного в Листинге 1, в ваш сценарий. Этот код сначала загружает расширение Win32::OLE, чтобы сценарий мог использовать модель COM. Далее код загружает библиотеку типов WMS, чтобы сценарий имел доступ к значениям констант WMS. И, наконец, код из блока A в Листинге 1 создает соединение с WMS. При работе этого кода переменная $Server указывает интерфейс IWMSServer, который является точкой входа на сервер WMS. Различные свойства и методы объекта IWMSServer позволяют получать информацию о сервере WMS и управлять службами WMS. Более подробную информацию о методах и свойствах, предоставляемых этим интерфейсом, можно найти на сайте http://msdn.microsoft.com/library/en-us/wmsrvsdk/htm/iwmsserverobject.asp.

Нужно иметь в виду, что код блока A работает, только когда ваша учетная запись имеет разрешение для работы в качестве администратора служб WMS и когда сценарий запускается на том же локальном сервере Windows 2003, на котором установлен WMS. Если необходимо подключиться к службам WMS на удаленном сервере Windows 2003, можно использовать модель Distributed COM (DCOM). Также требуется удалить код в блоке A и снять комментарии с блока B. Переменная $Machine может содержать имя удаленного сервера WMS, имя DNS или IP-адрес. Благодаря тому, что код в блоке B работает как для локальных, так и для удаленных систем, именно этот код я использую в своих сценариях. Однако следует иметь в виду, что вам придется переопределять переменную $Machine, для того чтобы она указывала на вашу локальную систему.

Получение информации с сервера WMS

После создания переменной $Server можно взаимодействовать со своим сервером WMS в любом объеме. Два сценария wmServerStatus.pl и wmServerLimits.pl служат примерами такого взаимодействия.

Сценарий wmServerStatus.pl демонстрирует простое взаимодействие. Этот сценарий получает текущее состояние указанного сервера WMS. Вы указываете сервер при запуске сценария. Команда запуска имеет следующий синтаксис:

perl wmServerStatus.pl

[machine name]

где «machine name» - имя удаленного сервера WMS, на котором нужно запустить сценарий. Чтобы запустить сценарий на локальном сервере WMS, не надо указывать данный параметр. Хотя эта команда здесь разбита на несколько строк, в окне команд ее необходимо вводить одной строкой. Это относится ко всем многострочным командам, приведенным в данной статье.

Листинг 2 содержит отрывок сценария wmServerStatus.pl. Как видно из кода в блоке B, этот сценарий использует объект IWMSServer (отображенный в переменной $Server) для подключения к указанному серверу WMS. Далее сценарий запрашивает у сервера значение свойства Status объекта IWMSServer. Код в блоке A описывает возможные значения состояния в списке, названном %SERVER_STATUS.

Сценарий wmServerLimits.pl демонстрирует более сложное взаимодействие с сервером WMS. Этот сценарий получает ограничения сервера WMS. WMS определяет множество ограничений, запрещающих службе выходить за установленные рамки. Например, ограничение ConnectedPlayers определяет, какое количество проигрывателей может быть одновременно подключено к службе, а ограничение ConnectionRate определяет скорость, на которой служба WMS разрешает новые соединения. Эти ограничения позволяют администраторам WMS контролировать использование полосы пропускания и других ресурсов.

Для запуска сценария wmServerLimits.pl следует применить команду

perl wmServerLimits.pl
 [machine name]

[-p PUBPOINT]

Эта команда отличается от команды запуска сценария wmServerStatus.pl только наличием параметра «-p». Чтобы отобразить ограничения для пункта публикации, а не для сервера WMS, используйте параметр «-p PUBPOINT», где «PUBPOINT» - имя пункта публикации. Пункт публикации - в сущности, имя, с которым связана информация. Точно так же имя общей папки или Web-сервера Microsoft IIS отображает на виртуальный корневой каталог для папок на жестком диске.

Сценарий wmServerLimits.pl использует объект IWMSServer для подключения к указанному серверу WMS. Затем сценарий использует свойство Limits объекта IWMSServer для получения объекта IWMSServerLimits, который хранит информацию об ограничениях сервера WMS. Далее сценарий проверяет, хочет ли пользователь получить ограничения для определенного пункта публикации или для сервера WMS. Если пользователь указал параметр «-p», сценарий подключается к требуемому пункту публикации. В конце сценарий опрашивает поименно все ограничения (в алфавитном порядке) и отображает имя и значение каждого из них.

Управление службами WMS

Так как платформа WMS полностью поддается описанию, создавать сценарии Perl для управления службой WMS достаточно просто. Давайте посмотрим, как создавать сценарии, которые отслеживают количество пользователей, подключенных к WMS, и ошибки в службах WMS.

Отслеживание подключенных клиентов. Администраторам по разным причинам может понадобиться информация о том, сколько клиентов подключено к WMS. Например, потребуется отключить WMS или возникнет подозрение, что кто-то пытается атаковать службу. Сценарий wmClients.pl направляет пункту публикации WMS запрос на создание списка подключенных клиентов. К службам WMS может быть подключено любое количество систем нижнего уровня. Клиентами нижнего уровня могут быть проигрыватели (то есть компьютеры людей, использующих WMP для просмотра или прослушивания потоковой информации), серверы распространения или proxy-серверы с кэшем. Сценарий позволяет указывать тип отображаемых клиентов: проигрыватели или серверы распространения. Proxy-серверы с кэшем будут отображаться как серверы распространения. По умолчанию сценарий отображает проигрыватели.

Чтобы понять принцип работы сценария wmClients.pl, нужно ознакомиться с его командой запуска, которая имеет следующий синтаксис:

perl wmClients.pl Machine
 [-dlr] [-s SortField]

PubPoint [PubPoint2 [...] ]

Эта команда имеет два обязательных параметра: «Machine», который определяет имя нужного сервера WMS (в отличие от других сценариев, здесь этот параметр является обязательным), и «PubPoint», который определяет имя запрашиваемого пункта публикации. Можно указать несколько пунктов публикации. Если ввести строку «"."» в качестве значения параметра «PubPoint» (или не указать пункт публикации), сценарий будет опрашивать все пункты публикации для данного сервера WMS и отобразит результат. Если требуется, чтобы сценарий выводил список серверов распространения вместо списка проигрывателей, необходимо добавить параметр « -l». Параметры «-s», «-d» и «-r» позволяют настраивать сортировку и отображение значений в списке. Более подробную информацию об этих параметрах можно найти в секции синтаксиса сценария wmClients.pl.

Как и два других сценария, сценарий wmClients.pl использует объект IWMSServer для подключения к указанному серверу WMS. Далее сценарий wmClients.pl начинает процесс опроса каждого пункта публикации для определения статуса каждого клиента (то есть «отключен», «не занят», «открыт» или «работает с потоком»). Листинг 3 отображает эту часть сценария. Как видно из блока A, сценарий сначала определяет, сколько пунктов публикации необходимо опросить. За это отвечает код, приведенный в блоке D. После того как сценарий обработает все параметры командной строки, код в блоке D определяет, были ли указаны пункты публикации в командной строке. Код выполняет эту проверку, помещая все считанные параметры (которые содержат имена пунктов публикации) в массив. Затем код проверяет, является ли хоть один из параметров именем пункта публикации. Если нет – код помещает строку «"."» в массив пунктов публикации. После этого сценарий опрашивает список пунктов публикации в данном массиве и запускает код блока A для каждого пункта. Код в блоке A привязывает переменную $PubPoint либо к объекту IWMSServer ($Server), либо к соответствующему пункту публикации, в зависимости от того, содержит массив строку «"."» или нет. В любом случае сценарий заносит в переменную $PubPoint объект COM, который отображает один из двух объектов-наборов: Players (отображает набор проигрывателей) и OutgoingDistributionConnections (отображает набор серверов распространения). Какой объект-набор будет использовать сценарий, зависит от того, добавлен ли параметр «-l» в командную строку.

Интересно, что объекты Players и OutgoingDistributionConnections создаются как на глобальном уровне сервера, так и на уровне пункта публикации. Благодаря этому сценарий работает с минимальным объемом кода.

Код блока B запрашивает состояние клиентских объектов (то есть подсоединенных проигрывателей или серверов). Этот код вызывает функцию in() расширения Win32::OLE для подсчета элементов из соответствующего объекта-набора. Функция in() возвращает массив объектов COM, который сортируется сценарием с помощью функции sort(). Функция «ort() вызывает процедуру SortPlayers(), изображенную в блоке C, чтобы обеспечить логический аппарат для сортировки объектов COM.

Отслеживание ошибок. Администраторы, как правило, проводят опрос систем Windows на предмет обнаружения ошибок и предупреждений в журнале событий Win32. Эта информация помогает обнаружить проблемы и незавершенные процессы. Кроме того, используя журнал событий Win32, пакет WMS предлагает интерфейс диагностики, названный IWMSDiagnosticEvents, который позволяет обнаружить ошибки и предупреждения, связанные с потоковыми данными, не требуя запуска программы Event Viewer.

Все события диагностики хранятся в службах WMS. Можно обратиться к ним с помощью оснастки Windows Media Services консоли Microsoft Management Console (MMC) или из Web-браузера, используя службу Windows Media Services Administrator для Web-ресурсов. Также можно обратиться к событиям диагностики через сценарии. Один такой сценарий, wmServerErrors.pl», показан в Листинге 4.

Сценарий wmServerErrors.pl подключается к службе WMS на определенной системе, затем использует функцию in() расширения Win32::OLE для подсчета объектов IWMSDiagnosticEvent в объекте-наборе IWMSDiagnosticEvents. Сценарий сортирует подсчитанные объекты в хронологическом порядке, в соответствии со значениями свойства Time объектов IWMSDiagnosticEvent. Таким образом, сценарий обрабатывает события диагностики в порядке их появления.

Сценарий копирует значения свойства из каждого объекта IWMSDiagnosticEvent в список, названный %ErrorData, после чего выводит данные на экран. Значения свойства первым делом копируются в локальный список, по двум причинам. Во-первых, команда write выводит только глобальные и локальные переменные. Команда write не печатает данные из переменной, если вы ограничиваете переменную, используя ключевое слово my. Во-вторых, формат вывода подразумевает, что одно из значений свойства объекта IWMSDiagnosticEvent должно быть изменено, чтобы обеспечить переход на следующую строку при отображении. Однако все свойства имеют атрибут «только чтение». Копирование значений в список чтения-записи %ErrorData позволяет модифицировать эти значения.

Нужно иметь в виду, что %ErrorData - локальный список. В сценарии wmServerErrors.pl строка

local %ErrorData = %$Error;

не только определяет, что список %ErrorData относится к локальным ресурсам, но и устанавливает все ключи и значения в списке с помощью указателя на список $Error. Так как $Error - это указатель на список, сценарий выделяет его, добавляя символ «%» в начало имени скалярной переменной $Error.

Вы можете запустить сценарий wmServerErrors.pl, указав имя сервера WMS и дополнительный параметр -r, при наличии которого с сервера будут удалены все ошибки. Используйте следующий синтаксис команды:

perl wmServerErrors.pl
 
 
 [machine name] [-r]

Создание собственных сценариев для WMS

Познакомившись с пакетом WMS, вы можете судить о том, насколько легко писать сценарии для получения информации из WMS и управления службами. Используя объектную модель WMS 9 Series, можно писать сложные сценарии для потоковых данных, которые упрощают создание и поддержку сайтов с технологией WMS.


ЛИСТИНГ 1: Код, который загружает Win32::OLE, библиотеку WMS Type Library и подключается к WMS
use Win32::OLE qw( in with HRESULT );
use Win32::OLE::Const "Windows Media Services Server Object
 Model and Plugin 9.0 Type Library";
# BEGIN CALLOUT A
my $Server = new Win32::OLE( "WMSServer.Server" ) || die;
# END CALLOUT A
# BEGIN COMMENT
# Если вы подключаетесь к службе WMS на удаленном сервере Windows 2003,
# удалите код в блоке  A и уберите символ комментария со следующего кода.
# END COMMENT
# BEGIN CALLOUT B
# my $Server =
# new Win32::OLE( [$Machine
ЛИСТИНГ 2: Отрывок из сценария wmServerStatus.pl
# BEGIN CALLOUT A
%SERVER_STATUS = (
 &WMS_SERVER_RUNNING => 'running',
 &WMS_SERVER_ERROR => 'erroring',
 &WMS_SERVER_ERROR_CRITICAL => 'critically in error',
);
# END CALLOUT A
 
%Config = ( machine => Win32::NodeName() );
Configure( \%Config );
if( $Config{help} )
{
 Syntax();
 exit;
}
 
my $Server = new Win32::OLE( [ $Config{machine},
 "WMSServer.Server" ] ) || die;
# BEGIN CALLOUT B
my $Status = $Server->{Status};
# END CALLOUT B
print "The Windows Media service on machine
 U$Config{machine}E is $SERVER_STATUS{$Status}.
";
 
ЛИСТИНГ 3: Отрывок из сценария wmClients.pl
foreach my $PubPointName ( @{$Config{pubpointnames}} )
{
# BEGIN CALLOUT A
 if( my $PubPoint = ( "." eq $PubPointName )? $Server :
 $Server->PublishingPoints( $PubPointName ) )
# END CALLOUT A
 {
 local( $iCount );
 $iCount = 0;
 print "Players connected to Pub Point: '$PubPointName'
";
 $~ = "Data_Header";
 write;
 $~ = "Data_Body";
# BEGIN CALLOUT B
 foreach my $PlayerObject ( sort{ SortPlayers() }
 in( $PubPoint->{$Config{collection_type}} ) )
 {
 local $URL;
 local( $Player ) = $PlayerObject;
 if( $Config{resolved} )
 {
 $URL = $Player->{ResolvedURL};
 }
 else
 {
 $URL = $Player->{RequestedURL};
 }
 $iCount++;
 write;
 }
# END CALLOUT B
 }
 else
 {
 print "Could not find Publishing Point: '$PubPointName'
";
 }
 print "
";
}
 
# BEGIN CALLOUT C
sub SortPlayers
{
 my $TempA = $a;
 my $TempB = $b;
 # In a sort method, assume $a and $b are already defined...
 if( $Config{descending} )
 {
 $TempA = $b;
 $TempB = $a;
 }
 return( $TempA->{$Config{sort}} cmp $TempB->{$Config{sort}} );
}
# END CALLOUT C
 
sub Configure
{
 my $Config = shift @_;
 my $Result;
 Getopt::Long::Configure( "prefix_pattern=-|/" );
 $Config->{sort} = "Status";
 $Result = GetOptions( $Config, qw( sort|s=s descending|d
 list_servers|l resolved|r help|?|h ) );
 $Config->{machine} = shift @ARGV || ( $Config->{help} = 1 );
# BEGIN CALLOUT D
 push( @{$Config->{pubpointnames}}, @ARGV );
 push( @{$Config->{pubpointnames}}, "." )
 if( ! scalar @{$Config->{pubpointnames}} );
 $Config->{collection_type} = ( $Config->{list_servers} )?
 "OutgoingDistributionConnections" : "Players";
# END CALLOUT D
 $Config->{help} = 1 if( ! $Result );
}
Листинг 4. Сценарий vmServerErrors.pl

 

se vars qw( %Config $VERSION );
use Getopt::Long;
use Win32::OLE qw( in with HRESULT );
use Win32::OLE::Const "Windows Media Services Server Object Model and Plugin 9.0 Type Library";
    
$VERSION = 20040826;
%DIAG_EVENT = (
  &WMS_DIAGNOSTIC_EVENT_LIMIT_HIT =>  'Limits',
  &WMS_DIAGNOSTIC_EVENT_PLUGIN_EVENT_LOG_ERROR  => 'Plugin error',
  &WMS_DIAGNOSTIC_EVENT_PLUGIN_EVENT_LOG_WARNING  => 'Plugin warning',
  &WMS_DIAGNOSTIC_EVENT_SERVER_EVENT_LOG_ERROR    =>  'WMS error',
  &WMS_DIAGNOSTIC_EVENT_SERVER_EVENT_LOG_WARNING  =>  'WMS warning',
);
%Config = (
  machine => Win32::NodeName(),
);
Configure( \%Config );
if( $Config{help} )
{
    Syntax();
    exit;
}
 
# Begin Callout A
my $Server = new Win32::OLE( [ $Config{machine}, "WMSServer.Server" ] ) || die;
# End Callout A
 
if( $Config{remove_errors} )
{
  $Server->{DiagnosticEvents}->RemoveAll();
  print "All errors have been removed.
";
}
else
{
  
  print "Total of $Server->{DiagnosticEvents}->{Count} on $Server->{Name}.
";
  $~ = "ERROR_DUMP";                                 
  # Begin Callout B
  foreach my $Error ( sort( {$a->{Time} cmp $b->{Time} } ( in( $Server->{DiagnosticEvents} ) ) ) )
  {
    local %ErrorData = %$Error;
    write;  
  }
  # End Callout B
}
 
sub Configure
{
    my $Config = shift @_;
    my $Result;
    
    Getopt::Long::Configure( "prefix_pattern=-|/" );
    $Result = GetOptions( $Config, 
                            qw( 
                                help|?|h
                                remove_errors|r
                            ) );
    $Config->{help} = 1 if( ! $Result );
    $Config->{machine} = shift @ARGV if( scalar @ARGV );
}
 
sub Syntax
{
    my( $Script ) = ( $0 =~ m#([^/]+)$# );
    my $Line = "-" x length( $Script );
    print << "EOT";
 
$Script
$Line
Displays diagnostic events on a Windows Media v9 Server
 
    Version: $VERSION
 
    Syntax: $Script [machine name] [-r]
        -r.............Removes all errors from the error list.
    
EOT
}
 
format ERROR_DUMP =
@<<<<<<<<<<<<<<<<<<<    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$ErrorData{Time}, $ErrorData{AdditionalInfo}
@<<<<<<<<<<<<<<<<<<<    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$DIAG_EVENT{$ErrorData{Type}},            $ErrorData{AdditionalInfo}
~                       ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                        $ErrorData{AdditionalInfo}
~                       ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                        $ErrorData{AdditionalInfo}
~                       ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                        $ErrorData{AdditionalInfo}