Сообщений 14    Оценка 665        Оценить  
Система Orphus

Технологии построения распределенных приложений в .NET

Часть 2. Пространство имен System.Messaging

Автор: Мика Сухов
Источник: RSDN Magazine #3-2004
Опубликовано: 08.01.2005
Исправлено: 10.12.2016
Версия текста: 1.0
Введение
Взгляд из прошлого
Установка MSMQ
Архитектура MSMQ
Создание очередей
Транзакции
Multiple Destination Messaging
Distribution lists
IP Multicasting
Multiple-element format names
Триггеры и правила
Зависимый и независимый клиенты
HTTP/HTTPS
Инсталляция
Безопасность
Аутентификация
Настройка атрибутов авторизации
Шифрование
Code Access Security
Заключение

Демонстрационный проект

Введение

В первой части статьи рассказывалось, какую базовую функциональность предоставляет .NET для построения систем с распределенным вычислением. В этой части статьи речь пойдет о технологии Microsoft Windows Message Queuing (или сокращенно MSMQ), предназначенной для обмена сообщениями, и предоставляющей ряд сервисов, в том числе и мощный механизм гарантированной доставки сообщений. Классы, которые позволяют работать с MSMQ, находятся в пространстве имен System.Messaging – отсюда и название данной статьи. Ну, что ж, в бой?

Взгляд из прошлого

Взаимодействие в распределенных приложениях можно разделить на два типа: ориентированное на вызов удаленных процедур (RPC, Remote Procedure Call) и на использование сообщений (MO, Message-Oriented; и использующие такой подход компоненты MOM, Message-Oriented Middleware).

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

МО-подход подразумевает передачу сообщений удаленным объектам или приложениям. Поскольку посылка сообщений не подразумевает ожидания ответа, этот подход изначально ориентирован на асинхронное взаимодействие. Если в RPC-подходе четко прослеживается клиентская и серверная сторона (вызывающая сторона называется клиентом, а обрабатывающая вызов – сервером), то в MO-подходе четко выраженного деления на клиент и сервер не существует. Вместо этого используются роли получателя и отправителя сообщений. В зависимости от реализации получатель и отправитель могут взаимодействовать как напрямую, так и при посредничестве специально выделенных серверов. Примером такого подхода является технология MSMQ.

Использование MO в ряде случаев может оказаться выгоднее RPC, так как обеспечивает большую независимость приложения и обычно ориентировано на асинхронное взаимодействие. Естественно, в ряде случаев эти достоинства могут обернуться недостатками, и дело разработчика – определить границы применимости того или иного подхода в своих приложениях.

В мире существует немало реализаций MO-серверов. Наиболее известными являются IBM MQSeries и Microsoft MSMQ. Естественно, что в .NET Microsoft обеспечил поддержку именно своего продукта.

Установка MSMQ

Прежде чем начать работу с MSMQ, необходимо установить ряд Windows-компонентов. Для этого выберите Start -> Control Panel -> Add or Remove Programs -> Add/Remove Windows Components. В появившемся окне из списка выберите Application Server и нажмите кнопку Details. Появится еще одно окно со списком, в котором будет находится пункт “Message Queuing”. Нажмите Details, чтобы выбрать нужные вам компоненты MSMQ.

В таблице 1 описаны все компоненты MSMQ:

Название компонента Описание
Active Directory Intergation Интеграция MSMQ с Active Directory.
Common Функциональность для зависимого клиента и локальных очередей.
Downlevel Client Support Компоненты, позволяющие клиентам MSMQ версий 1.0 и 2.0 работать с данными Active Directory.
MSMQ HTTP Support Компоненты, позволяющие передавать сообщения по протоколу HTTP/HTTPS.
Routing Support Поддержка маршрутизации сообщений с использованием информации, хранящейся в Active Directory.
Triggers Поддержка триггеров.
Таблица 1. Описание компонентов MSMQ.

Архитектура MSMQ


Рисунок 1. Процесс доставки сообщения в MSMQ.

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

Существующие виды очередей перечислены в таблице 2.

Название Описание Тип
Public Очередь с входящими сообщениями, доступная через службу каталогов, например, Active Directory. Application
Private Очередь с входящими сообщениями, доступная в WorkGroup. Application
Report Сообщения с данными о маршруте, через которое прошло сообщение. Application
Response Ответные сообщения. Application
Administration Сообщения об успехе или провале той или иной операции. Application
Journal Все отосланные и принятые сообщения. System
Dead-Letter Очередь сообщений, которые не удается доставить. System
Transactional Dead-Letter Очередь неотосланных сообщений, которые участвовали в транзакции. System
Connector Позволяет работать с очередями, создаными на платформе, отличной от Windows. System
Outgoing Все исходящие сообщения. System

Преимущества MSMQ заключаются в следующем:

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

За вторым пунктом вообще скрывается целый “букет” недостатков (дополнительный маршалинг данных, платформенная зависимость и, самое для меня болезненное, отсутствие возможности «заглянуть под капот» ;o) ), но тут уж ничего не поделаешь, такова природа связи .NET и COM. Но не все так плохо. Давайте представим себе ситуацию, когда MSMQ используется, например, при взаимодействии компонентов корпоративной системы. Первый недостаток отпадает, так как вряд ли у вас не будет возможности установить компоненты MSMQ. Низкоуровневые подробности, связанные с ориентацией на сообщения, можно скрыть за фасадным кодом. И, наконец, последний пункт – невозможность прогнозирования окончания передачи данных. Но это, собственно, нельзя назвать недостатком – это особенность ориентированного на сообщения подхода.

Создание очередей

Чтобы работать с очередью, ее сперва нужно создать. Это можно сделать административно или программно, через MessageQueue.Create. При создании очереди нужно указать ее имя, а также, будет ли она транзакционной. При задании имени используются строки вида, описанного в таблице 3.

Тип очереди Использование
Public {Имя машины}\{Имя очереди}
Private {Имя машины}\Private$\{Имя очереди}
Journal {Имя машины}\{Имя очереди}\Journal$
Machine journal {Имя машины}\Journal$
Machine dead-letter {Имя машины}\Deadletter$
Machine transactional dead-letter {Имя машины}\XactDeadletter$

Так же можно указать имя по формату или метке (Таблица 4).

Вид Использование
Format FORMATNAME:DIRECT={Имя Протокола}:{Путь}[PRIVATE$\]{Имя очереди}FORMATNAME:MULTICAST={IP адрес}:{Номер Порта}FORMATNAME:DL={GUID Распределенного Списка}[@{Имя Домена}]
Label LABEL:{Метка Очереди}

Перед созданием нужно проверить, не существует ли уже такая очередь. Это делается через метод MessageQueue.Exist. Удалить очередь можно через метод MessageQueue.Delete.

Послать или получить сообщение можно с помощью методов MessageQueue.Send и MessageQueue.Receive, соответственно. В метод MessageQueue.Send передается объект типа object. Для большей гибкости рекомендуется использовать экземпляр класса Message, так как через него можно задать ряд специфичных свойств, например, настройки безопасности или информацию об очереди (внутри класса MessageQueue все объекты все равно оборачиваются в Message). В листинге 1 представлен код чат-программы, основанной на технологии MSMQ:

Листинг 1. Пример чата на основе очередей MSMQ.
      public
      struct IncomingMessage
{
  public IncomingMessage(string userName, string message)
  {
    _userName = userName;
    _message = message;
    _sentTime = DateTime.Now;
  }

  privatestring _userName;

  publicstring UserName
  {
    get { return _userName; }
    set { _userName = value; }
  }

  privatestring _message;

  publicstring Message
  {
    get { return _message; }
    set { _message = value; }
  }

  private DateTime _sentTime;

  public DateTime SentTime
  {
    get { return _sentTime; }
    set { _sentTime = value; }
  }
}


publicclass MSMQClient : IDisposable
{
  private MessageQueue _queue;

  public MSMQClient(string opponentName)
  {
    string path = string.Format(@".\Private$\{0}", opponentName);

    if (MessageQueue.Exists(path))
      _queue = new MessageQueue(path, true);
    elsethrownew ApplicationException("Opponent queue doesn't exist.");

    _queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(IncomingMessage) });
  }

  publicvoid SendMessage(IncomingMessage message)
  {
    _queue.Send(new Message(message));
  }

  publicvoid Dispose()
  {
    _queue.Close();
  }
}


publicclass MSMQServer : InteractiveServer
{
  private MessageQueue _queue;

  public MSMQServer(string userName)
  {
    string path = string.Format(@".\Private$\{0}", userName);

    if (MessageQueue.Exists(path))
      _queue = new MessageQueue(path);
    else
      _queue = MessageQueue.Create(path, true);

    _queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(IncomingMessage) });

    base.Start();
  }

  protectedoverridevoid OnProcessRequest()
  {
    Message message = _queue.Receive();
    base.RaiseEvent(new NewMessageEventArgs((IncomingMessage)message.Body));
  }

  protectedoverridevoid Dispose(bool disposing)
  {
    if (disposing)
    {
      if (_queue != null)
      {
        _queue.Close();
        _queue = null;
      }
    }
  }
}


publicclass MainForm : System.Windows.Forms.Form
{
  private System.Windows.Forms.RichTextBox allMessages;
  private System.Windows.Forms.RichTextBox outgoingMessage;
  private System.Windows.Forms.Button sendBtn;
  private System.ComponentModel.Container components = null;
  private MSMQClient _client;
  private MSMQServer _server;

  privatestring _userName;

  publicstring UserName
  {
    get { return _userName; }
    set { _userName = value; }
  }

  privatestring _opponentName;

  publicstring OpponentName
  {
    get { return _opponentName; }
    set { _opponentName = value; }
  }

  protectedoverridevoid Dispose( bool disposing )
  {
    if (disposing)
    {
      _client.Dispose();
      _server.Dispose();
      
      if (components != null)
        components.Dispose();
    }
    base.Dispose(disposing);
  }

  privatevoid sendBtn_Click(object sender, System.EventArgs e)
  {
    IncomingMessage message = 
      new IncomingMessage(_userName, outgoingMessage.Text);
    _client.SendMessage(message);
    OnAddNewMessage(message);
    outgoingMessage.Text = string.Empty;
    outgoingMessage.Select();
  }

  privatevoid MainForm_Load(object sender, System.EventArgs e)
  {
    _client = new MSMQClient(_opponentName);
    _server = new MSMQServer(_userName);
    _server.NewMessage += new EventHandler(_server_NewMessage);
    outgoingMessage.Select();
  }

  privatevoid outgoingMessage_TextChanged(object sender, System.EventArgs e)
  {
    sendBtn.Enabled = (outgoingMessage.Text != string.Empty);
  }

  privatedelegatevoid AddNewMessage(IncomingMessage message);

  privatevoid OnAddNewMessage(IncomingMessage message)
  {
    allMessages.AppendText(message.SentTime.ToShortTimeString() 
      + "  " + message.UserName + "  "
      + message.Message + Environment.NewLine);
  }

  privatevoid _server_NewMessage(object sender, EventArgs e)
  {
    NewMessageEventArgs newMgsArgs = (NewMessageEventArgs)e;
    IncomingMessage message = newMgsArgs.Message;
    base.Invoke(new AddNewMessage(OnAddNewMessage), newobject[] { message });
  }
}


class Program
{
  [STAThread]
  staticvoid Main(string[] args)
  {
    LoginForm loginForm = new LoginForm();

    if (loginForm.ShowDialog() == DialogResult.OK)
    {
      MainForm mainForm = new MainForm();
      mainForm.UserName = loginForm.UserName;
      mainForm.OpponentName = loginForm.OpponentName;
      Application.Run(mainForm);
    }
  }
}
ПРЕДУПРЕЖДЕНИЕ

Здесь есть один нюанс. Если отсылающая сторона (MSMQClient) обратится к несуществующей очереди принимающей стороны, то произойдет исключение. Поэтому создавать принимающую очередь необходимо перед запуском экземпляров приложений.

Данные в очередях сериализуются тремя видами форматеров: binary- (System.Messaging.BinaryMessageFormatter), xml- (System.Messaging.XmlMessageFormatter) или COM-форматтером (System.Messaging.ActiveXMessageFormatter).

Транзакции

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

Для лучшего усвоения термина “транзакционность MO” приведем жизненный пример, который знаком каждому программисту, а именно этапы создания программы. Как правило, в разработке ПО явно или неявно можно выделить пять основных этапов:

Допустим, мы моделируем процесс разработки ПО в нашей системе, и передача информации о результатах этапов осуществляется через MSMQ. Каждое сообщение содержит в себе информацию о результате этапа. Теперь нам нужно переслать эти сообщения таким образом, чтобы если хотя бы одно из сообщений не было доставлено, все предыдущие также не учитывались принимающей стороной. Логично, ведь как мы можем начать проектировать систему, не зная, что она будет выполнять. Именно эта функциональность, позволяющая в целости и сохранности доставить все (или ни одного) сообщения на сервер, называется транзакционностью сообщений.

Вернемся к классу MessageQueueTransaction. Он как раз и нужен для использования транзакций при пересылке сообщений. Для демонстрации напишем тестовую программу, отсылающую на два сервера заказы на покупку и продажу (листинг 2). Оба заказа зависят друг от друга.

Листинг 2. Заказы, отправляемые через единую MSMQ-транзакцию.
      public
      struct OrderInfo
{
  public OrderInfo(string path, string order)
  {
    _path = path;
    _order = order;
  }

  privatestring _path;

  publicstring Path
  {
    get { return _path; }
  }

  privatestring _order;

  publicstring Order
  {
    get { return _order; }
  }
}


class Program
{
  publicvoid ProcessOrders(OrderInfo[] orders)
  {
    using (MessageQueueTransaction orderTransaction = new MessageQueueTransaction())
    {
      orderTransaction.Begin();

      foreach (OrderInfo order in orders)
      {
        using (MessageQueue queue = new MessageQueue(order.Path, true))
        using (Message message = new Message())
            queue.Send(new Message(order.Order), orderTransaction);
      }

      orderTransaction.Commit();
    }
  }

  [STAThread]
  staticvoid Main(string[] args)
  {
    try
    {
      Program program = new Program();
      program.ProcessOrders(
        new OrderInfo[]
        { 
          new OrderInfo(@"BuyServer\IncomingOrgers", "Buy"),
          new OrderInfo(@"SellServer\IncomingOrgers", "Sell"),
        });
    }
    catch (MessageQueueException ex)
    {
      Console.WriteLine(ex);
    }
  }
}
ПРЕДУПРЕЖДЕНИЕ

Если очередь не поддерживает транзакции, то будет сгенерировано исключение MessageQueueException.

Multiple Destination Messaging

Очереди можно настроить таким образом, что одно и то же сообщение будет отправлено в несколько мест. Cуществует три способа осуществить это (вообще-то есть и четвертый, реализовать все самому ;o) ):

Distribution lists

В ActiveDirectory можно завести так называемый распределенный список, в который вписать адреса всех публичных адресов очередей или других таких списков. Чтобы создать такую очередь, необходимо передать в конструктор MessageQueue в качестве параметра path (или в метод MessageQueue.Create, если очередь только создается) строку следующего формата:

FORMATNAME:DL=04065905-087D-4cf7-91F7-B5E2DBB0181B.

IP Multicasting

Очередь можно настроить на работу с сообщениями через IP Multicasting. Для этого нужно:

В клиентском приложении необходимо создать очередь, передав в нее формат вида: FORMATNAME:MULTICAST=224.0.0.0:8320.

ПРЕДУПРЕЖДЕНИЕ

При взаимодействии такого рода невозможно пользоваться некоторыми свойствами MSMQ, а именно транзакционностью и шифрованием.

Multiple-element format names

Этот способ фактически является объединением описанных выше. В очередь передается формат, который может содержать и простой путь к очереди, и распределенный список, и multicast-адрес. Например: FORMATNAME:PUBLIC=12714085-6F6C-4ba0-B86D-855B108BF0BA,DL=04065905-087D-4cf7-91F7-B5E2DBB0181B,MULTICAST=224.0.0.0:8320.

Триггеры и правила

На некоторые действия с очередью можно назначить определенную реакцию. Это делается с помощью так называемых триггеров (Triggers). Поддерживаются следующие операции над сообщениями (таблица 5).

Типы операций Описание
Peeking Триггер не удаляет сообщение.
Retrieval Триггер удаляет сообщение.
Transactional Retrieval Триггер удаляет сообщение после окончания транзакции.

Триггеры подразделяются на сериализуемые и не сериализуемые. Первый тип работает в синхронном состоянии (когда приходит новое сообщение, оно обрабатывается каждым триггером по очереди). Второй – в асинхронном состоянии (пока один триггер обрабатывает сообщение, другой может обрабатывать следующее). Сфера действия триггера ограничивается одной очередью.

Каждый триггер может содержать множество правил. Правило – это такое действие, которое определяет, удовлетворяет ли сообщение определенному условию (например, содержит ли сообщение такой-то текст), и, если да, то выполняется какое-то действие (вызывается метод COM-объекта или создается процесс, в который передаются параметры MSMQ-сообщения).

Зависимый и независимый клиенты

В MSMQ существуют два термина: зависимый и независимый клиенты.

Зависимый клиент не имеет локальной очереди исходящих сообщений и отсылает сообщения напрямую серверу. Этот тип клиента не поддерживает работу в отключенном от сети режиме. Если сервер в данный момент не доступен, сразу же происходит ошибка доставки сообщения. Так же он не поддерживает таких вещей, как триггеры, IP multicating и т.д.

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

HTTP/HTTPS

Последняя, третья версия MSMQ поддерживает пересылку сообщений через Интернет. Сообщения посылаются через HTTP/HTTPS в виде SOAP-запроса. Для того, чтобы включить эту функциональность, нужно:

Реализована возможность взаимодействия через прокси-серверы. Хост-адреса и аутентификационные данные берутся из настроек IE. Можно произвести настройки и через утилиту proxycfg.

ПРИМЕЧАНИЕ

Если обслуживанием очередей занимается несколько серверов, можно включить поддержку Network Load Balansing.

Инсталляция

Как уже было описано выше, создать очередь можно двумя способами: административно (через оснастку Computer Management) или программно (MessageQueue.Create). Но есть и другой способ, через класс MessageQueueInstaller. MessageQueueInstaller является наследником Installer, позволяющий создавать собственные установщики средствами .NET. Такой установщик можно запустить через специальную утилиту InstallUtil.exe, входящую в состав .NET Framework.

Для примера давайте рассмотрим небольшое приложение, представленное в листинге 3, и позволяющее создавать MSMQ-очереди:

Листинг 3. Приложение для установки MSMQ-очередей.
      public
      class ManagementForm : System.Windows.Forms.Form
{
  ...
  privatevoid installBtn_Click(object sender, System.EventArgs e)
  {
    MessageQueueInstaller installer = new MessageQueueInstaller();

    // Задаем настройки установщику.
    installer.Authenticate = authenticate.Checked;
    installer.BasePriority = Convert.ToInt16(basePriority.Value);
    installer.Category = new Guid(category.Text);
    installer.EncryptionRequired = (EncryptionRequired)Enum.Parse(
      typeof(EncryptionRequired),
      (string)encryptionRequired.SelectedItem,
      false);
    installer.Label = label.Text;
    installer.MaximumJournalSize = Convert.ToInt64(maximumJournalSize.Value);
    installer.MaximumQueueSize = Convert.ToInt64(maximumQueueSize.Value);
    installer.Path = path.Text;
    installer.Transactional = transactional.Checked;
    installer.UseJournalQueue = useJournalQueue.Checked;

    // Так как мы запускаем установщик из собственного кода// (а не из-под утилиты InstallUtil), нам необходимо самим// выставить контекст установки.
    installer.Context = new InstallContext();

    IDictionary stateSaver = new Hashtable();
    try
    {
      installer.Install(stateSaver);
      installer.Commit(stateSaver);
      MessageBox.Show("Установка прошла успешно.");
    }
    catch (Exception ex)
    {
      // Показываем ошибку.
      MessageBox.Show(ex.ToString());
      installer.Rollback(stateSaver);
    }
  }

  privatevoid ManagementForm_Load(object sender, System.EventArgs e)
  {
    encryptionRequired.DataSource = Enum.GetNames(typeof(EncryptionRequired));
    encryptionRequired.SelectedItem = EncryptionRequired.Optional.ToString();
    maximumJournalSize.Maximum = long.MaxValue;
    maximumQueueSize.Maximum = long.MaxValue;
    maximumJournalSize.Value = uint.MaxValue;
    maximumQueueSize.Value = uint.MaxValue;
    category.Text = Guid.Empty.ToString();

    // Наша тестовая очередь
    path.Text = @".\Private$\TestQueue1";
  }
}

Безопасность

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

Аутентификация

Если вам необходима аутентификация сообщений, выставите значение свойства MessageQueue.Authenticate в true. В клиентской части следует использовать свойство Message.UseAuthentication. MSMQ для таких сообщений автоматически создает цифровую подпись (в принципе, вы и сами можете ее создать, воспользовавшись свойством Message.DigitalSignature). Чтобы определить, каким криптопровайдером будет создаваться цифровая подпись, используется свойство Message.AuthenticationProviderType (по умолчанию установленный в CryptographicProviderType.RsaFull) или Message.AuthenticationProviderName. Код в листинге 4 демонстрирует, как работать с очередью, требующей аутентификации клиента:

Листинг 4. Аутентификация клиента в MSMQ.
        using (MessageQueue queue = GetQueue())
{
  using (MessageQueueTransaction transaction = new MessageQueueTransaction())
  {
    transaction.Begin();
    using (Message message = new Message("Hello"))
    {
      message.UseAuthentication = true;
      queue.Send(message, transaction);
    }
    transaction.Commit();
  }
}

Настройка атрибутов авторизации

Чтобы пройти процесс авторизации, на серверной стороне необходимо создать ряд разрешений. Это делается через методы MessageQueue.SetPermissions и MessageQueue.ResetPermissions. Через класс MessageQueueAccessControlEntry можно дать или отнять права на использование очереди (PeekMessage, DeleteMessage и т.д.), а так же ассоциировать их с именем пользователя, группы, компьютера, домена или алиаса (alias).

Чтобы посмотреть текущие разрешения, зарегистрированные для очереди, нужно:

Код, представленный в листинге 5, показывает, как нужно давать разрешения для очереди:

Листинг 5. Настройка авторизации для очереди MSMQ
MessageQueue queue = MessageQueue.Create(@".\TestQueue", true);
queue.SetPermissions("Guest", MessageQueueAccessRights.FullControl, AccessControlEntryType.Deny);

Шифрование

Чтобы установить шифрованное соединение, используется свойство MessageQueue.EncryptionRequired. Через перечисление EncryptionRequired можно установить значения, приведенные в таблице 6.

Имя поля Описание
Body Очередь работает только с шифрованными сообщениями.
None Очередь работает только с незашифрованными сообщениями.
Optional Очередь поддерживает оба типа сообщений, в зависимости от опции Message.UseEncryption.

Чтобы установить тип алгоритмов шифрования и хеширования, можно воспользоваться свойствами Message.EncryptionAlgorithm и Message.HashAlgorithm. Чтобы настроить ключи для шифрования сообщений, нужно:

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


Рисунок 2. Процесс передачи шифрованных сообщений в MSMQ.

После того, как на обеих сторонах создан сессионный ключ, начинается обычный процесс обмена сообщениями.

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

ПРИМЕЧАНИЕ

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

Соединение в MSMQ можно настроить через шифрование с использованием сертификатов стандарта x.509 v.3. Для этого нужно:

Код, представленный на листинге 6, показывает, как нужно работать с шифрованным каналом в MSMQ:

Листинг 6. Шифрование сообщений в очередях MSMQ
        using (MessageQueue queue = GetQueue())
{
  using (MessageQueueTransaction transaction = new MessageQueueTransaction())
  {
    transaction.Begin();
    using (Message message = new Message("Hello"))
    {
      message.UseAuthentication = true;
      message.UseEncryption = true;

      queue.Send(message, transaction);
    }
    transaction.Commit();
  }
}

На клиентской части сертификат нужно установить через свойство Message.SenderCertificate. Стоит также отметить, что такая функциональность работает только в MSMQ, сконфигурированном под Active Directory.

Code Access Security

Code Access Security (CAS), «родную» безопасность .NET, при использовании MSMQ можно установить через класс MessageQueuePermission. Использование разрешений аналогично WebPermission и SocketPermission, о которых рассказывалось в предыдущей статье. Для декларативной установки разрешений используется MessageQueuePermissionAttribute. Код, представленный в листинге 7, показывает, как нужно работать с CAS в MSMQ:

Листинг 7. Установление ограничений для клиента на использование очереди MSMQ.
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Send, _path);
permission.Deny();

// Тут произойдет ошибка выполнения, так // как полномочие на подключение к очереди снято.using (MessageQueue queue = GetQueue())
{
  using (MessageQueueTransaction transaction = new MessageQueueTransaction())
  {
    transaction.Begin();
    using (Message message = new Message("Hello"))
      queue.Send(message, transaction);
    transaction.Commit();
  }
}

Напомню, что такие полномочия очень удобны, ибо они действительны не только для серверной части, но и для клиентской - если не хватает прав на подключение к серверу, ошибка доступа к ресурсу будет выдана уже на компьютере клиента.

Заключение

Ну, вот, пожалуй, и все. Надеюсь, моя статья поможет вам в работе с технологией MSMQ. Удачи вам!


Эта статья опубликована в журнале RSDN Magazine #3-2004. Информацию о журнале можно найти здесь
    Сообщений 14    Оценка 665        Оценить