Главная » Silverlight » Сервер политики

0

Перед разработкой сокетного сервера нужно создать сервер политики, сообщающий Silverlight, каким клиентам разрешено устанавливать соединение с сокетным сервером.

Как было показано выше, Silverlight не разрешает загружать содержимое или вы­зывать веб-службу, если в домене нет файла clientaccesspolicy .xml или crossdomain. xml, в котором эти операции явно разрешены. Аналогичное ограничение налбжено и на сокетный сервер. Если не предоставить клиентскому устройству возможность загрузить файл clientaccesspolicy .xml, разрешающий отдаленный доступ, Silverlight откажется устанавливать соединение.

К сожалению, предоставление файла clientaccesspolicy. cml сокетному приложе­нию — более сложная задача, чем его предоставление посредством веб-сайта. При ис­пользовании веб-сайта программное обеспечение веб-сервера может предоставить файл clientaccesspolicy .xml, нужно лишь не забыть добавить его. В то же время при ис­пользовании сокетного приложения нужно открыть сокет, к которому клиентские прило­жения могут обращаться с запросами политики. Кроме того, нужно вручную создать код, обслуживающий сокет. Для решения этих задач необходимо создать сервер политики.

Далее будет показано, что сервер политики работает так же, как сервер сообщений, он лишь обслуживает немного более простые взаимодействия. Серверы сообщений и политики можно создать отдельно или объединить в одном приложении. Во втором случае они должны прослушивать запросы в разных потоках. В рассматриваемом при­мере мы создадим сервер политики, а затем объединим его с сервером сообщений.

Для создания сервера политики нужно сначала создать приложение .NET. В качестве сервера политики может служить приложение .NET любого типа. Проще всего приме­нить консольное приложение. Отладив консольное приложение, можно переместить код в службу Windows, чтобы он постоянно выполнялся в фоновом режиме.

Файл политики

Ниже приведен файл политики, предоставляемый сервером политики.

<?xml version="1.0" encoding="utf-8" ?>

<access-policy> <cross-domain-access> <policy> <allow-from>

<domain uri="*"/> </allow-from> <grant-to>

<socket-resource port="4502-4534" protocol="tcp"/> </grant-to> </policy> </cross-domain-access>

</access-policy>

Файл политики определяет три правила.

•       Разрешает доступ ко всем портам от 4502 до 4532 (это полный диапазон портов, поддерживаемых надстройкой Silverlight). Для изменения диапазона доступных портов нужно изменить значение атрибута port элемента <socket-resource>.

•       Разрешает доступ TCP (разрешение определено в атрибуте protocol элемента <socket-resource>).

•       Разрешает вызов из любого домена. Следовательно, приложение Silverlight, уста­навливающее соединение, может хостироваться любым веб-сайтом. Для измене­ния этого правила нужно отредактировать атрибут uri элемента <domain>.

Для облегчения задачи правила политики размещаются в файле clientaccess- ploi.cy.xml, добавляемом в проект. В Visual Studio параметру Copy to Output Directory (Копировать в выходную папку) файла политики нужно присвоить значение Сору Always (Всегда копировать). должен всего лишь найти файл на жест­ком диске, открыть его и вернуть содержимое клиентскому устройству.

Класс PolicyServer

Функциональность сервера политики основана на двух ключевых классах: PolicyServer и PolicyConnection. Класс PolicyServer обеспечивает ожидание со­единений. Получив соединение, он передает управление новому экземпляру класса PoicyConnection, который передает файл политики клиенту. Такая процедура, состоя­щая из двух частей, часто встречается в сетевом программировании. Вы еще не раз увидите ее при работе с серверами сообщений.

Класс PolicyServer загружает файл политики с жесткого диска и сохраняет его в поле как массив байтов.

public class PolicyServer

{

private byte[] policy;

public PolicyServer(string policyFile) {

// Загрузка файла политики FileStream policyStream = new FileStream(policyFile, FileMode.Open); policy = new byte[policyStream.Length]; policyStream.Read(policy, 0, policy.Length); policyStream.Close();

)

Чтобы начать прослушивание, серверное приложение должно вызвать метод PolicyServer. Start (). Он создает объект TcpListener, который ожидает запросы. Объект TcpListener сконфигурирован на прослушивание порта 943. В Silverlight этот порт зарезервирован для серверов политики. При создании запросов на файлы полити­ки приложение Silverlight автоматически направляет их в порт 943.

private TcpListener listener;

public void Start ()

{

// Создание прослушивающего объекта

listener = new TcpListener(IPAddress.Any, 943);

// Начало прослушивания; метод Start () возвращается II немедленно после вызова listener.Start();

// Ожидание соединения; метод возвращается немедленно;

II ожидание выполняется в отдельном потоке

listener.BeginAcceptTcpClient(OnAcceptTcpClient, null);

)

Чтобы принять предлагаемое соединение, сервер политики вызывает метод Begin­AcceptTcpClient (). Как все методы Beginxxx () инфраструктуры .NET, он возвращается немедленно после вызова, выполняя необходимые операции в отдельном потоке. Для сетевых приложений это весьма существенный фактор, потому что благодаря ему воз­можна одновременная обработка многих запросов на файлы политики.

Примечание. Начинающие сетевые программисты часто удивляются, как можно обрабатывать более одного запроса одновременно, и думают, что для этого нужно несколько серверов. Однако это не так. При таком подходе клиентские приложений быстро исчерпали бы доступные порты. На практике серверные приложения обрабатывают многие запросы через один порт. Этот процесс невидим для приложений, потому что встроенная в Windows подсистема TCP автоматически идентифицирует сообщения и направляет их в соответствующие объекты в коде приложений. Каждое соединение уникально идентифицируется на основе четырех параметров: ІР-адрес клиента, номер порта клиента, ІР-адрес сервера и номер порта сервера.

При каждом запросе запускается метод обратного вызова OnAcceptTcpClient (). Он опять вызывает метод BeginAcceptTcpClient О , чтобы начать ожидание следующего запроса в другом потоке, и после этого начинает обрабатывать текущий запрос.

public void OnAcceptTcpClient(IAsyncResult аг) {

if (isStopped) return;

Console.WriteLine("Получен запрос политики."); // Ожидание следующего соединения.

listener.BeginAcceptTcpClient(OnAcceptTcpClient, null);

// Обработка текущего соединения.

try {

TcpClient client = listener.EndAcceptTcpClient(аг); PolicyConnection policyConnection = new PolicyConnection(client, policy); policyConnection.HandleRequest() ;

}

catch (Exception err) {

Console.WriteLine(err.Message);

}

}

Каждый раз при получении нового соединения создается новый объект PolicyConnection, чтобы обработать его. Кроме того, объект PolicyConnection обслу­живает файл политики.

Последний компонент класса PolicyServer — метод Stop (), который останавливает ожидание запросов. Приложение вызывает его при завершении.

private bool isStopped;

public void StopO {

isStopped = true;

try {

listener. Stop () ;

}

catch (Exception err) {

Console.WriteLine(err.Message);

}

)

}

Для запуска сервера политики в методе Main () сервера приложения используется следующий код.

static void Main(string[] args) {

PolicyServer policyServer = new PolicyServer("clientaccesspolicy.xml"); policyServer.Start();

Console.WriteLine("Запущен сервер политики."); Console.WriteLine("Нажмите клавишу Enter для выхода.");

// Ожидание нажатия клавиши <Enter>; с помощью метода // Console.ReadKey() можно задать ожидание определенной // строки (например, quit) или нажатия любой клавиши Console.ReadLine();

policyServer.Stop();

Console.WriteLine("Завершение сервера политики.");

}

Класс PolicyConnection

Класс PolicyConnection выполняет более простую задачу. Объект PolicyConnection сохраняет ссылку на данные файла политики. Затем, после вызова метода HandleRequest (), объект PolicyConnection извлекает из сетевого потока новое сое­динение и пытается прочитать его. Клиентское устройство должно передать строку, содержащую текст <policy-file-request/>. После чтения этого текста клиентское устройство записывает данные политики в поток и закрывает соединение. Ниже при­веден код класса PolicyConnection.

public class PolicyConnection (

private TcpClient client; private byte[] policy;

public PolicyConnection(TcpClient client, byte[] policy) {

this.client = client; this.policy = policy;

}

// Создание запроса клиента private static string policyRequestString = "<policy-file-request/>";

public void HandleRequest () {

Stream s = client.GetStream(); // Чтение строки запроса политики

byte[] buffer = new byte[policyRequestString.Length];

// Ожидание выполняется только 5 секунд client.ReceiveTimeout = 5000;’

s.Read(buffer, 0, buffer.Length);

// Передача политики (можно также проверить, есть ли //в запросе политики необходимое содержимое) s.Write(policy, 0, policy.Length);

// Закрытие соединения client.Close ();

Console.WriteLine("Файл политики обслужен.");

)

}

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

Источник: Мак-Дональд, Мэтью. Silverlight 3 с примерами на С# для профессионалов. : Пер. с англ. —- М. : ООО «И.Д. Вильяме», 2010. — 656 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии