Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2 3 4 5 6 7 8 9 10 11   вперед  Ctrl      все
 ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Типа, просто и понятно, но чем плохи сокеты Windows или чем не устраивает Indy или ICS или IPWorks! или ещё что...
И - где лучше не использовать.
23 сен 14, 06:52    [16607877]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Вот что пишут.

Предположим, мы проектируем систему и используем "чистый" tcp.

Вопросы:
- используем блокирующие сокеты? Или асинхроные? Блокировка => просто кодить, но считается, что приложение "плохо масштабируется". Если же используем асинхронный i/o, то запариваемся с кодингом.

- как решить вопрос с изменением нагрузки? Какой компонент будет считаться сервером, какой - клиентом? Что делать, чтобы подключить сервер к серверу? Что делать, если связь часто обрывается?

- что делать, когда сообщение частично? Что делать, если сообщения поступают слишком часто? Если сообщение не помещаются во входной буфер?

- где и как хранить очередь сообщений? Нужна ли очередь на приеме? ... на передаче?

- что делать с потерянными сообщениями? Игнорировать? , отправить запрос повторно, выбросить исключение, ...?

- что делать, если нам нужно использовать другой сетевой транспорт? Скажите, мультикаст вместо уникаст TCP ? Или IPv6?

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

- как обработать ошибки сети? Игнорировать, попробовать еще раз, завершить работу?

- ...?
23 сен 14, 07:33    [16607904]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Есть вариант использовать готовые системы, ориентированные на обмен сообщения.
Они отлажены, стандартизированы, решают проблемы с балансировкой нагрузки, с обработкой ошибок, с динамической маршрутизацией, с кодировками и т.п.
К сожалению, эти системы - брокер - ориентированные. То есть, обычно предполагают наличие специального вычислительного процесса, который работает на выделенном железе и обслуживается специально выделенными людьми.
Следовательно, это стоит делать только для больших распределенных приложений с множеством компонентов, построенных большими командами.
...
PS: мы, например, для одной распределенной задачи использовали существующую сеть jabber - серверов, "паразитируя" на них.
Кодить, используя сообщения, а не tcp - поток, намного приятнее. :)
Позднее мы пытались отойти от использования публичных jabber -серверов и запустили на своем железе собственный сервер, но надежность системы в итоге упала: наш админ не смог обеспечить доступ к ресурсу в обещанном режиме 24х7...

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

Или использовать существующие системы обмена сообщениями и в зависеть от третьей стороны.

ZeroMQ была создана для того, чтобы сделать возможной работу с сообщениями простым и дешевым образом, чтобы она могла работать в любом приложении, и была бесплатной (или со стоимостью, близкой к нулевой).
Она была разработана как библиотека, которую просто можно использовать без каких-либо зависимостей.
Она запускается на любой ОС и работает с любым языком программирования.
23 сен 14, 07:51    [16607918]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Поехали!

Сокеты.

Жизнь сокетов ZeroMQ состоит из четырех частей.

1. Создание и уничтожение, которые должны идти парами: см zmq_socket (), zmq_close ().
2. Настройка сокета: установить параметры сокета: zmq_setsockopt (), проверить настройки сокета: zmq_getsockopt ().
3. Подключение сокета в топологию сети путем создания сходящего или исходящего ZeroMQ соединения: zmq_bind (), zmq_connect ().
4. Использование сокета для передачи данных путем записи и приема сообщений в/из них: zmq_msg_send ()/ zmq_msg_recv ().

Сокеты в Delphi представлены просто указателями (Pointer).
А сообщения zmq_msg_t - структурой:

zmq_msg_t = record
    _: Array[0..32-1] of Byte;
  end; 



Подключение сокетов

Для создания соединения между двумя узлами на одном узле использует zmq_bind(), а на втором zmq_connect().
Принято считать, что узел, где zmq_bind() - это "сервер", который располагается в заранее известной точке сети (т.е., имеет фиксированный сетевой адрес). А узел, где используется zmq_connect() - "клиент", его сетевой адрес заранее неизвестен. Говорят "привязка" сокета ("биндинг") и подключение ("коннектинг"). То есть "привязываем" сокет к конкретной точке, и "подключаем" сокет к конкретной точке, "конкретная точка" - это известный сетевой адрес.

Соединения ZeroMQ отличаются от привычных соединений TCP:

Работают по разным транспортным протоколам (inproc, ipc, tcp, pgm, epgm).
Один сокет может иметь много исходящих и много входящих соединений.
Метода Accept() /zmq_accept()/ нет! Когда сокет привязывается к конретной точке, Accept() стартует автоматически.
Сотевые соединения выполняются в фоне, а ZeroMQ автоматом реконнектится, если сеть обрывается и восстанавливается.
Приложение не будет работать с соединением напрямую, только через сокет ZeroMQ.


В ранее рассмотренных примерах мы запускали клиента до запуска сервера, безо всяких проблем.
В обычных сетях мы бы уже получили сообщение, что сервер не готов и т.д.
Но ZeroMQ позволяет запускать и останавливать разные сетевые компоненты в произвольной последовательности. Как только узел - клиент вызывает zmq_connect (), соединение уже существует, и что узел может начать писать сообщения в сокет.
На определенном этапе (хорошо бы, до момента переполнения очереди сообщений ), сервер оживает, выполняет zmq_bind (), и ZeroMQ начинает доставлять сообщения.

Узел-сервер может биндиться к нескольким конкретным точкам сети. И даже к разным протоколам.

zmq_bind (socket, 'tcp://*:5555');
zmq_bind (socket, 'tcp://*:9999');
zmq_bind (socket, 'inproc://somename');


К конкретной точке сети нельзя биндиться дважды. Если будет запущено два сервера, выполняющие такой код:
zmq_bind (socket, 'tcp://*:9999');
- то работать будет первый, второй будет ждать.

Пишут, однако, что для ipc транспорта допускается множественный биндинг, но нас это пока не касается: ipc пока реализован только на всяких линуксах.
23 сен 14, 09:34    [16608170]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Добавление:

Протокол inter-thread (inproc) - это транспорт, основанный на сигналах. Очень быстрый. Но с ограничениями: сервер должен выполнить биндинг до того, как клиент попытается законнектиться. Пишут, что в будущем, возможно, это поведение будет исправлено (приведено к стандартному). А пока рекомендованная схема: главный поток создает сокет, биндит его к уникальному имени, потом создает дочерний поток, в котором так же создается сокет, который коннектится к inproc с тем же именем.

В остальном с inproc точно так же:

Биндинг в одном потоке:
//  Имя - "#1"
zmq_bind(socket, 'inproc://#1');
...
//  Имя - 'my-endpoint'
zmq_bind(socket, 'inproc://my-endpoint');


Конектинг в другом:

zmq_connect(socket, 'inproc://#1');
...
zmq_connect(socket, 'inproc://my-endpoint'); 


То есть: 'имя протокола://уникальное имя коннекта'
23 сен 14, 09:56    [16608271]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Дальше я буду писать ZMQ вместо ZeroMQ.
Или даже 0MQ.

С целью экономии ресурса клавиатуры.
25 сен 14, 05:57    [16618938]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Шаблоны сетевых топологий ZeroMQ.

В первой части
были представлены и подробно описаны приложения, реализующих два простых шаблона сетевой топологии вроде "Запрос - Ответ" и "Издатель - Подписчик.
Во 2й части был представлен шаблон решения задачи методом "Разделяй и Властвуй" (когда задачу разделяем на кусочки и разадаем исполнителям). При этом использовался шаблон "Параллельный трубопровод" (Parallel Pipeline).



Считается, что ZMQ "искаропки" реализует четыре шаблона:

1. Запрос-Ответ (Request-Reply), в котором соединяются множество клиентов к множеству сервисов ("серверов"). Этот шаблон предназначен для реализации удаленного выполнения каких-либо задач, вроде.
2. Издатель - Подписчик (Pub-sub), в котором соединяются множество издателей с множеством подписчиков. Это - шаблон для реализации задачи предоставления данных по подписке.
3. Трубопровод (Pipeline), в котором соединяются узлы для "проталкивания" (в т.ч. параллельного) сообщений, для задач, требующих в процессе решения множество этапов перемещения (в том числе циклического) данных. Это - шаблон для решения задач вроде разделения большого задания на несколько меньших с последующим сбором результатов.
4. Эксклюзивная пара (Exclusive pair), в которой соединяются только два сокета. Это - шаблон для решения задач вроде связи двух потоков в процессе.

Четвертый шаблон ("Эксклюзивная пара") представляется слишком очевидным для того, чтобы делать под него отдельно приложение, использовать его можно так, как описано здесь: 16608271.

В каждом из представленных приложениях сокеты настраивались в соответствии с задачей.
Для пар сокетов ZMQ есть следующие допустимые комбинации настроек:


PUB - SUB
REQ - REP
REQ - ROUTER
DEALER - REP
DEALER - ROUTER
DEALER - DEALER
ROUTER - ROUTER
PUSH - PULL
PAIR - PAIR

Половину из этих комбинаций мы уже знаем. :)
Остальные я еще только собираюсь пощупать.

Из документации:
Использование пар сокетов ZMQ в других комбинациях повлечет появление недокументированных эффектов и, возможно, чудовищные разрушения оборудования.
25 сен 14, 06:28    [16618950]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Поговорим о СООБЩЕНИЯХ ZMQ

В рассмотренных ранее тестовых приложениях мы пользовались методами zmq_send () и zmq_recv (). В их параметрах мы указывали сокет, адрес буфера с данными и длину данных. Все незатейливо. Беда в том, что zmq_recv() нельзя использовать, если не знаешь заранее размер принимаемого сообщения: если сообщение не поместится, хвост отсечётся.

Так вот, в API ZMQ есть чудесные методы для работами со структурой zmq_msg_t.
Здесь уже возможностей больше (но и кодить придется больше):


Инициализация сообщения: zmq_msg_init(), zmq_msg_init_size(), zmq_msg_init_data().
Отправка и получение соощения: zmq_msg_send(), zmq_msg_recv().
Освобождение (ресурсов) сообщения: zmq_msg_close().
Доступ к данным сообщения: zmq_msg_data(), zmq_msg_size(), zmq_msg_more().
Работа со свойствами сообщения: zmq_msg_get(), zmq_msg_set().
Манипуляции с сообщениями: zmq_msg_copy(), zmq_msg_move().

В памяти сообщение представляется собой структуру:

type
  zmq_msg_t = record
    _: Array[0..32-1] of Byte;
  end;


Особенности работы с сообщениями ZMQ:
- вы создаете и передаете в работу только объекты zmq_msg_t, а не блоки данных;
- для чтения сообщения, сначала вызываем zmq_msg_init() (создается пустое сообщение), а затем передаем его в zmq_msg_recv();
- для инициализации сообщения вашими данными, необходимо вызвать zmq_msg_init_size() - будет создано сообщение и выделен блок данных указанного размера. Затем вы "руками" заполняете данные и передаете сообщение в zmq_msg_send().
- для освобождения (для очистки, а не для удаления объекта zmq_msg_t), вызываем zmq_msg_close(). Это действие сбросит ссылку в ZMQ на структуру и для ZMQ соощение перестанет существовать.
- для доступа к содержимому сообщения, используем zmq_msg_data(). Для получения длины блока данных в байтах используем zmq_msg_size().

Внимание! Операции zmq_msg_move(), zmq_msg_copy(), zmq_msg_init_data() опасны разрушением контекста, если вы не знаете, для чего и как их использовать.

После того, как сообщение было передано в zmq_msg_send(), ZMQ очистит сообщение, то есть, например, заполнит структуру нулями.

PS: ХЗ, что там делается реально - сообщение то зануляется, то нет. Ну, раз сказано, значит, так и есть.

Вы не можете отправить одно и то же сообщение дважды, точно так же вы не можете получить доступ к блоку данных сообщения после его отправки.

Для zmq_send() и zmq_recv(), эти правила не работают, тут вы пересылаете свой массив байт, а не структуру zmq_msg_t.
25 сен 14, 07:09    [16618967]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Если все же нужно отправить одно и то же сообщение более, чем один раз, и оно довольно большое, создаем еще одно сообщение, инициализируем его с помощью zmq_msg_init(), а потом используем zmq_msg_copy(). Будет создана копия исходного сообщения. Такой способ не создает копию сообщения, а просто создает копию ссылки на сообщение.
Теперь это сообщение можно отправить дважды (если нужно больше - создаем больше копий).

  zmq_msg_init_size(fMsg1, 9999 * SizeOf(Char)); // Инициализация
  FillChar(zmq_msg_data(fMsg2)^, 9999, 'ё'); // Запонение буквами ё

  zmq_msg_init(fMsg2); // Создание копии
  zmq_msg_copy(fMsg2, fMsg1);

  zmq_msg_send(fMsg1, fSocketSender, 0);
  zmq_msg_send(fMsg2, fSocketSender, 0);

Сообщение будет полностью удалено только после того, как будет отправлена последняя копия.
25 сен 14, 07:22    [16618972]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
ZeroMQ также поддерживает сообщения, состоящие из нескольких частей (фрагментов, фреймов).

В этом случае в одном сообщении содержится несколько кадров.
Для однокадровых сообщений структура пересылаемых данных очень проста:
[Длина блока данных][...блок данных ...]
Составные (многокадровые) сообщения состоят из нескольких таких кадров, например

3 'ABC'    // Длина: 3 байта + строка из трех однобайтных символов
0          // Длина: 0 байт (пустой кадр)
6 'Привет' // Длина: 6 байт + строка из шести однобайтных символов


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

Фреймы представляют собой базовый для ZMQ формат, в котором данные передаются по выбранному транспорту.
Длина - от нуля и дальше.

PS: фреймы - это несомненная польза с т.зр. программистов, использовавших TCP, для которых всегда был актуален вопрос: "а сколько мне нужно прочитать данных из данного сокета в данных момент?".


Такой покадровый обмен данными называется ZMTP протоколом.

Обычно сообщения ZeroMQ состоит из одного кадра, наподобие датаграммы UDP.
Для превращения сообщения в мультикадровое ZMQ просто устанавливает в кадре бит "есть ещё!". Затем читаем следующие кадры, пока не получим последний кадр со сброшенным битом.

И так.

Сообщение может состоять из одного и более частей.
Части сообщения называются кадры/фреймы (frames).
Каждая часть есть представляется объектом zmq_msg_t.
Программист принимает и отправляет каждую часть отдельно (используя API нижнего уровня).
API высших уровней обеспечивают обертками для отправки составных сообщений целиком.

Кроме того:


Можно посылать сообщения нулевой длины. Например, для отправки сигнала из одного потока в другой. Или - как мы делали в приложении 16607836:
    zmq_send(fSocketSender, PChar(fDummy)^, 0, 0); // Отправка сигнала сборщику результата


ZeroMQ гарантирует доставку либо всех частей сообщения, либо ни одной части.

ZeroMQ не отправляет сообщение (ни простое, ни составное) прямо сразу, а выполняет это с задержкой. То есть, нужно учитывать, что составные сообщения должны помещаться в памяти.

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

После использования принятого сообщения, его нужно закрыть: zmq_msg_close().
При отправке сообщения этот метод вызывать не нужно. То есть, чисткой занимается получатель.
25 сен 14, 07:54    [16618997]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Ах, да.

Есть удивительный метод zmq_msg_init_data(). Этот метод позволяет инициализировать сообщение без копирования данных пользователя. Для скорости, с целью экономии памяти и т.д.
Так вот, пока не используем его, если не хотим проблем (например: для использования метода нужно определить деаллокирующую данные функцию, да не простую, а thread-safe).

В документации сказано то же самое.
25 сен 14, 08:02    [16619007]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Работа с несколькими сокетами ZMQ.

Во всех примерах, что мы рассмотрели ранее, схема работы была примерно одинаковой - в цикле повторялись одни те же действия:
    

Ожидание сообщение из сокета
Обработка сообщения.
"Смыть, повторить."


Что делать, если нам нужно читать сообщения из нескольких конечных точек одновременно?
Самое простое - коннектить один сокет ко всем нужным конечным точкам и позволть, чтобы ZeroMQ втягивала нужные нам данные. Это допустимо, если все конечные точки настроены для работы по одному и тому же шаблоны, но может быть неправильным, если, например, коннектить PULL - сокеты к конечной точке типа PUB.

Так вот, чтобы иметь возможность читать из множества сокетов сразу, следует использовать метод zmq_poll().
Более того, рекомендуется обернуть zmq_poll() в удобный для ситуации собственный фреймворк.

Создадим простое приложение, которое покажет, как читать данные из неблокирующего сокета.
Будем читать данные из двух сокетов с использованием неблокирующего чтения. Приложение будет работать и как подписчик, и как работник в системе обработки параллельных задач.
25 сен 14, 08:18    [16619033]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Вот исходник ридера, читающего данные и от нашей старой задачи "Ventilator" и от сервера метеостанции:

+

program MS_Reader;

{$APPTYPE CONSOLE}

uses
  SysUtils, ZMQ;

var

  fConext: Pointer;
  fSocketReceiver: Pointer;
  fSocketSubscriber: Pointer;
  fMsgBuff: array[0..255] of Char;
  fSize: Integer;
begin

// Подключение к задаче "ventilator"
  fConext := zmq_ctx_new();
  fSocketReceiver := zmq_socket(fConext, ZMQ_PULL);
  zmq_connect(fSocketReceiver, 'tcp://localhost:5557');

// Подклчение к серверу метеостанции
  fSocketSubscriber := zmq_socket(fConext, ZMQ_SUB);
  zmq_connect(fSocketSubscriber, 'tcp://localhost:5556');
  zmq_setsockopt(fSocketSubscriber, ZMQ_SUBSCRIBE, PChar('10001 '), 6);

// Процесс обработки для обоих сокетов
// Считаем, что трафик от  задачи "ventilator" для нас важнее
  while true do begin
    while true do begin
      fSize := zmq_recv(fSocketReceiver, fMsgBuff, SizeOf(fMsgBuff), ZMQ_DONTWAIT);
      if fSize >= 0 then
        // Выполнение задания
      else
        break;
    end;
    while true do begin
      fSize := zmq_recv(fSocketSubscriber, fMsgBuff, SizeOf(fMsgBuff), ZMQ_DONTWAIT);
      if fSize >= 0 then
    // Обработка данных о погоде
      else
        break;
    end;
    // Активности нет, спим 1 ms
    Sleep(1);
  end;
  zmq_close(fSocketReceiver);
  zmq_close(fSocketSubscriber);
  zmq_ctx_destroy(fConext);

  Readln;

end.



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

А теперь рассмотрим такое же приложение, но уже с использованием zmq_poll().
25 сен 14, 08:43    [16619081]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Теперь: "правильный" мульиридер:

+


program MS_Reader_Poll;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ZMQ;

var

  fConext: Pointer;
  fSocketReceiver: Pointer;
  fSocketSubscriber: Pointer;
  fMsgBuff: array[0..255] of Char;
  fSize: Integer;
  fItems: array[0..1] of pollitem_t;
begin

// Подключение к задаче "ventilator"
  fConext := zmq_ctx_new();
  fSocketReceiver := zmq_socket(fConext, ZMQ_PULL);
  zmq_connect(fSocketReceiver, 'tcp://localhost:5557');

// Подклчение к серверу метеостанции
  fSocketSubscriber := zmq_socket(fConext, ZMQ_SUB);
  zmq_connect(fSocketSubscriber, 'tcp://localhost:5556');
  zmq_setsockopt(fSocketSubscriber, ZMQ_SUBSCRIBE, PChar('Temperature '), 12);

  fItems[0].socket := fSocketReceiver;
  fItems[0].fd := 0;
  fItems[0].events := ZMQ_POLLIN;
  fItems[0].revents := 0;

  fItems[1].socket := fSocketSubscriber;
  fItems[1].fd := 0;
  fItems[1].events := ZMQ_POLLIN;
  fItems[1].revents := 0;
// Процесс обработки для обоих сокетов
  while true do begin

    zmq_poll(fItems[0], Length(fItems), -1);
    if ((fItems[0].revents and ZMQ_POLLIN) <> 0) then begin
      fSize := zmq_recv(fSocketReceiver, fMsgBuff, SizeOf(fMsgBuff), 0);
      if fSize >= 0 then
        // Выполнение задания
      else
        break;
      if ((fItems[1].revents and ZMQ_POLLIN) <> 0) then begin
        fSize := zmq_recv(fSocketSubscriber, fMsgBuff, SizeOf(fMsgBuff), 0);
        if fSize >= 0 then
    // Обработка данных о погоде
        else
          break;
      end;
    end;
  end;

  zmq_close(fSocketReceiver);
  zmq_close(fSocketSubscriber);
  zmq_ctx_destroy(fConext);

  Readln;

end.


Видим, что появилась интересная структура:

type
  pollitem_t = record
    socket: Pointer; // Сокет ZeroMQ
    fd: Integer; // Стандартный сокет, представленный дескриптором файла
    events: Word; // Маска событий 
    revents: Word; // Маска событий 
  end;


Массив таких структур

  fItems: array[0..1] of pollitem_t;

инициализируется следующим образом:

  fItems[0].socket := fSocketReceiver;
  fItems[0].fd := 0;
  fItems[0].events := ZMQ_POLLIN;
  fItems[0].revents := 0;

  fItems[1].socket := fSocketSubscriber;
  fItems[1].fd := 0;
  fItems[1].events := ZMQ_POLLIN;
  fItems[1].revents := 0;

В каждом элементе указан свой сокет и задана маска ожидаемых событий (ZMQ_POLLIN).

Далее вызывается метод

zmq_poll(fItems[0], Length(fItems), -1);
Последний параметр - время ожидания события в ms. Если -1 - то ожидание будет выполняться бесконечно долго.

Событие, произошедшее при выполнении zmq_poll(), заносится в битовую маску revents.
25 сен 14, 09:32    [16619247]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
чччД
...

Видим, что появилась интересная структура:

type
  pollitem_t = record
    socket: Pointer; // Сокет ZeroMQ
    fd: Integer; // Стандартный сокет, представленный дескриптором файла
    events: Word; // Маска событий 
    revents: Word; // Маска событий 
  end;


...


Честно говоря, не въехал, как использовать поле fd. Что "за стандартный сокет"?
25 сен 14, 09:35    [16619257]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Составные сообщения.

Процесс доставки сообщения атомарен.

+ Атомарен
То есть, если на принимающей стороне API сообщило, что пришло сообщение, это значит, что сообщение уже полностью принято (и присутствует в памяти принимающей стороны). А если в процессе пересылки возникнут какие-то проблемы, то принимающая сторона об этом даже не догадается, до приемника сообщение просто не дойдет.
Гарантированной доставки нет. О гарантированной доставке нужно заботиться программисту - с помощью нумерации сообщений, подтверждающих запросов, таймаутов и проч.

Так вот, как было сказано ранее (16618997), сообщение может быть составным (состоять из нескольких кадров).
В реальных приложениях это полезно - например, для реализации собственных структур и алгоритмов (например, для простых способов сериализации объектов).

Так вот, насчет составных сообщений. Для каждой части (кадра) составного сообщения нужен свой экземпляр структуры zmq_msg_t.
Необязательно, чтобы все части (zmq_msg_t) были объявлены одновременно, можно инициализировать очередной кадр и отправлять его с признаком ("будет ещё!"), используя единственный zmq_msg_t. Однако, все кадры сообщения будут накапливаться в памяти передающей стороны до момента отправки.

Например, отправляем составное сообщение из 5 кадров. Можно объявить, инициализировать, заполнить данными, отправить и очистить пять разных zmq_msg_t. А можно работать с одним zmq_msg_t для всех пяти кадров последовательно.

Пример (сообщение из 5 кадров), 5 экземпляров zmq_msg_t:

var
...
  fMsg_1: zmq_msg_t;
  fMsg_2: zmq_msg_t;
  fMsg_3: zmq_msg_t;
  fMsg_4: zmq_msg_t;
  fMsg_5: zmq_msg_t;


begin
...
  zmq_msg_send(fMsg_1, fSocketSender, ZMQ_SNDMORE); // Кадры с признаком "будет ещё!"
  zmq_msg_send(fMsg_2, fSocketSender, ZMQ_SNDMORE);
  zmq_msg_send(fMsg_3, fSocketSender, ZMQ_SNDMORE);
  zmq_msg_send(fMsg_4, fSocketSender, ZMQ_SNDMORE);
  zmq_msg_send(fMsg_5, fSocketSender, 0); // Завершающий кадр


Пример приема сообщения из 5 кадров, 1 экземпляр zmq_msg_t:

var
...
  fMsg: zmq_msg_t;
...
begin
...
  while True do begin
    zmq_msg_init(fMsg);
    zmq_msg_recv(fMsg, fSocketReceiver, 0);
// Обработка кадра сообщения
    zmq_msg_close(fMsg);
    if not zmq_msg_more(fMsg) then
      break; // Это был последний кадр
  end;
...


Вещи, которые [b]важны при работе с составными сообщениями:[/b]

- При отправки составного сообщения и первый, и все последующие кадры начнут отправляться "физически" только тогда, когда был отправлен финальный кадр.
- Если на приме используется zmq_poll(), то следует иметь в виду, что в момент, когда вы получили первую часть сообщения, все остальные части были уже получены.
- Вы физически получаете либо все части сообщения, либо ни одного.
- Каждая часть сообщения есть отдельный элемент zmq_msg.
- Вы получите всегда ВСЕ части сообщения, вне зависимости от того, проверяете ли вы свойство "ещё!".
- На передающей стороне ZeroMQ последовательно помещает кадры сообщения в очередь, до кадра с признаком "последний" (вернее, без признака "будет ещё!" ), а только потом выполняется пересылка всех кадров сообщения.
- не существует иного способа отказаться от частично отправленного сообщения, кроме как закрыть сокет: zmq_close().
25 сен 14, 22:12    [16623222]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
defecator
Member

Откуда:
Сообщений: 38600
чччД, читаю, очень интересно...Но всё равно возникает вопрос из заголовка - а для чего ?
Всё равно ведь ниже ZeroMQ лежат виндовые сокеты, а их не перепрыгнуть?
Можно примеры каких-нить настолько высоконагруженных приложений, в которых без стероидов ну никак ?...
25 сен 14, 22:17    [16623228]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
defecator
чччД, читаю, очень интересно...Но всё равно возникает вопрос из заголовка - а для чего ?
Всё равно ведь ниже ZeroMQ лежат виндовые сокеты, а их не перепрыгнуть?
Можно примеры каких-нить настолько высоконагруженных приложений, в которых без стероидов ну никак ?...

У меня там была рекламная страничка, но Рустам её грохнул.
Но я её помню наизусть:

+

Особенности ZeroMQ:

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

Сетевые компоненты могут подключаться и отключаться динамически, при этом ZeroMQ будет реконнектиться автоматически. Имеется в виду, что вы можете запускать компоненты в любой последовательности. Можно создать "сервис - ориентированную архитектуру" (SOAs), в которой сервисы могут подключаться и отключаться к сети в любой момент.

Сообщения могут автоматически ставиться в очередь, по необходимости. Это делается логично, с проталкиванием сообщения как можно ближе к приемнику перед их постановкой в очередь.

ZeroMQ умеет бороться с переполнением очередей (называется "high water mark"). Когда очередь полна, ZeroMQ автоматически блокирует отправителя, или отбрасывает сообщения в зависимости от режима обмена сообщениями (см. ранее о "шаблонах").

Она позволяет вашему приложению общаться в через произвольный транспорт: TCP, multicast, in-process, inter-process. Вам не нужно менять код для использования другого транспорта.

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

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

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

Она доставляет сообщения полностью в том виде, в котором оно было отправлено, используя простую упаковку. Если вы отправили сообщение длиной 10к, вы и получите сообщение длиной 10к.

Она не налагает ограничений на формат сообщений. Сообщения представляют собой блобы длиной от нуля до нескольких гигабайт. Когда вам нужно специальное представление данных, вы выберете другой продукт, типа msgpack, Google's protocol buffers, и т.д.

Она разумно обрабатывает сетевые ошибки, выполняя повторные запросы когда это имеет смысл.

Она уменьшает затраты на железо.

С использованием ZeroMQ в центр приложения быстро перемещается цикл обработки сообщения, а ваше приложение вскоре распадается на набор задач обработки сообщений. Это элегантно и естественно. И это масштабируется: каждая из этих задач транслируется в узел сети, а узлы общаться друг с другом через произвольные транспорты. Два узла в одном процессе (узлом является поток), два узла на одном компьютере (узлом является процесс), или два узла в одной сети (узлом является компьютер)-это все прозрачно и без изменения кода приложения.


Ах да, твой вопрос... имхо, проще и легковеснее, чем ZMQ, я ничего не видел.
Прочие ориентированные на сообщения системы реализуются в виде службы, а ZMQ - просто библиотека.

Типа, FireBird Embedded: для больший задач лучше настоящий сервер, а для приложения "на флешке" - FB Embedded - самое оно. :)

...хотя, есть примеры "больших" приложений: Веб-сайту Second Life удалось получить 13,4 микросекунды непрерывного времени ожидания и обслуживать до 4 100 000 сообщений в секунду.
25 сен 14, 22:43    [16623279]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
defecator
Member

Откуда:
Сообщений: 38600
чччД, а то, что асинхронные сокеты изобрёл Мелкософт, никого уже не смущает ?
4 ляма сообщений в секунду - это железо умалчивается ?
25 сен 14, 22:48    [16623293]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
defecator
Member

Откуда:
Сообщений: 38600
не наезжаю, ни боже мой.
Я просто пытаюсь понять, чем эта либа отличается от другой прослойки типа RealThinClient - тм тоже изначально синхронные сокеты
25 сен 14, 22:50    [16623298]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
defecator
чччД, читаю, очень интересно...Но всё равно возникает вопрос из заголовка - а для чего ?
Всё равно ведь ниже ZeroMQ лежат виндовые сокеты, а их не перепрыгнуть?
...

Кроме того, ZMQ использует не только TCP, но и, например, inproc протокол для связи между потоками (а в UNIX-системах - между процессами).
...
У меня лично от Windows сокетов послевкусие. Особенно после асинхронных. "Ах, что-то пришло в буфер, посмотрим... Заголовок уже загружен? Нет еще, ну ладно... Опять сообщение - ура, заголовок загружен, и даже часть тела... аккуратно анализируем заголовок, и снова цикл ожидания загрузки остатка сообщения..."
А сообщения ZMQ - атомарны.
Конечно, атомарность сообщений ZMQ - не всегда благо. Например, при получении данных большого объема: сколько тебе послали, столько ты и получишь, все сразу. А с винсокетами ты можешь послать всех, кто (например) неправильно отправил заголовок, еще "в процессе", на принимая сообщения целиком.
По этой причине, если выставить ZMQ сокет "в интернет", его сразу могут завалить всяким мусором. Ну, если не принимать никаких мер. Но в локальной сети ведь злоумышленников быть не должно? :)

Т.е., это - не "серебряная пуля". А такой ничего себе ножичек.
25 сен 14, 22:54    [16623306]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
defecator
чччД, а то, что асинхронные сокеты изобрёл Мелкософт, никого уже не смущает ?
...

А они как раз и используются в ZMQ, вовсю.

defecator
...
4 ляма сообщений в секунду - это железо умалчивается ?

Там используется распределенная архитектура, там МНОГО железа. Для организации его в сеть там как раз используется ZMQ.
25 сен 14, 22:56    [16623310]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
defecator
...
Я просто пытаюсь понять, чем эта либа отличается от другой прослойки типа RealThinClient - тм тоже изначально синхронные сокеты

А в ZMQ - асинхронные...
...а про RealThinClient я вообще ничего не знаю.
25 сен 14, 22:58    [16623316]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Проблема динамического обнаружения

+ Краткое содержание
Вопрос сродни вот этому: Как получить список доступных MS SQL серверов?




Одной из проблем, возникающих при проектировании крупных распределенных систем является обнаружение сервисов. Частный случай проблемы - "как клиент узнает, к какому серверу нужно коннектиться?" А в общем случае - "как элементам сети найти друг друга?"

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

Эта проблема решается везде по-разному: используется служба DNS, или широковещательные сообщения (UDP) и т.п.

Есть несколько простых решений проблемы динамического обнаружения. Можно жестко закодировать адрес(ip + порт) (конечную точку). Вообще никаких проблем - и никакой гибкости. Впрочем, некоторой гибкости для tcp транспорта можно добавить с помощью службы DNS.
Можно конечную току задавать с помощью конфигурационных файлов (и т.д.). Главное - не забывать их вовремя обновлять .
Можно использовать специальный брокер адресации, который передаст вам нужные данные. Только вот адрес этого брокера должен быть известен...
Можно построить средство, исследующее окружение, сканирующее известные диапазоны адресов и порты. Или рассылающее (получающее) udp - пакеты об адресной информации.
...
...
...
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Можно при запуске нового элемента сети вручную задавать конечную точку ("адрес сервера"). То есть, при подключении вы просто знаете конфигурацию сети и сообщаете нужные данные новому элементу сети. Так часто делают, но в реальности это приводит к громоздким и хрупким топологиям.
Вспомним пример "Издатель-Подписчик": 16583825.
Пусть есть один издатель и тысяча подписчиков. Каждый подписчик коннектится к одному издателю. Можно руками конфигурировать подключение каждого подписчика, это просто. Сделали, работает. Подписчик - динамичный (может подключаться из любого места, и включаться когда угодно), а издатель - статичный. Сделали, работает.

К сообщению приложен файл. Размер - 8Kb
25 сен 14, 23:33    [16623417]     Ответить | Цитировать Сообщить модератору
 Re: ZeroMQ - сокеты на стероидах, часть 3 (а для чего?).  [new]
чччД
Guest
Неожиданно набежали янычары. А вот теперь представим, что появился еще одни издатель. Нужно еще раз настроить каждого подписчика. Всех, 1000 шт. И каждый раз появление нового издателя повлечет за собой увеличение стоимости настройки.

Нужно динамическое обнаружение.

Добавим брокер сообщений. ZMQ не поставляется с брокерами, но позволяет его легко построить.
Теперь Издатель-Подписчик схема будет выглядеть вот так:

К сообщению приложен файл. Размер - 11Kb
26 сен 14, 00:00    [16623492]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2 3 4 5 6 7 8 9 10 11   вперед  Ctrl      все
Все форумы / Delphi Ответить