Библиотека P2 CGate представляет собой набор следующих компонент:
системные библиотеки Plaza-2
маршрутизатор сообщений P2MQRouter
шлюзовая библиотека cgate
заголовочный файл с описанием API - cgate.h
Все эти компоненты необходимы для разработки с использованием библиотеки P2 CGate.
Для того, чтобы начать разработку, требуется установить компоненты инсталлятором, соответствующим используемой Вами операционной системе. В зависимости от операционной системы библиотеки и заголовочный файл будут установлены либо в стандартные предназначенные для этого места, либо в место, указанное при установке. В ходе дальнейших инструкций каталог установки будет обозначаться как CGATE_HOME (В ОС семейства Windows при инсталляции будет создана системная переменная окружения с именем CGATE_HOME, значением которой является путь установки CGate).
Для работы с библиотекой необходимо наличие логина в систему Plaza-2 и ключа приложения. Для разработки используются логины в тестовую систему Plaza-2 и тестовые ключи, которые могут быть использованы всеми разработчиками произвольно. Для production используются production-логины и ключи. Production-ключи могут быть получены путём прохождения процедуры сертификации.
Для проверки корректности установки и готовности к разработке можно выполнить тестовую сборку примеров и их исполнение. Для этого надо выполнить следующие шаги:
Настройка маршрутизатора Plaza-2 в соответствии с имеющимся логином (в случае использования интерактивного инсталлятора данное действие выполняется автоматически)
Необходимо открыть файл настройки рутера P2MQRouter, который, как правило, называется client_router.ini и в секции [AS:NS] заполнить логин и пароль:
[AS:NS] USERNAME=<your login> PASSWORD=<your password>
Сборка примеров
Примеры располагаются в каталоге CGATE_HOME\sdk\samples для платформы Windows или в каталоге /usr/share/doc/cgate-examples для Linux. Сборка примеров выполняется запуском сборочных скриптов, которые различаются в зависимости от используемой платформы и языка программирования. Для ОС Linux рекомендуется сделать копию примеров в своём домашнем каталоге и собирать их оттуда.
Исполнение примеров
Для исполнения примеров необходимо убедиться, что рутер P2MQRouter запущен и соединен с сетью Plaza-2 (анализом сообщений рутера), в доступности библиотек Plaza-2 для запускаемого файла примера (возможно потребуется добавление каталога CGATE_HOME\p2bin в переменную окружения PATH или указание каталога CGATE_HOME\p2bin в Вашей среде разработки), а также в доступности конфигурационных файлов.
Описание примеров
Пример aggrspy
aggrspy - пример построения агрегированного стакана на покупку и продажу по фиксированному инструменту по потоку FORTS_FUTAGGR50_REPL. При нажатии Enter в outfile выводится срез стакана.
Команда для запуска:
aggrspy ISIN_ID depth outfile [r]
Входные аргументы:
isin_id - id инструмента;
depth - глубина выводимого стакана в файл (не больше 50);
outfile - файл для печати стакана;
r - включить обратное направление сортировки (параметр используется для инструментов с обратной сортировкой).
Пример repl
repl - получение реплики данных по потоку. Пример печатает все получаемые сообщения в log. При разрыве соединения реплика начинается сначала. Входных аргументов нет.
Пример repl_resume
repl_resume - пример идентичиен repl. Отличие заключается в том, что после разрыва соединения repl_resume продолжает реплику с последнего сообщения TN_COMMIT. Входных аргументов нет.
Пример send
send - выставляет заявку на FORTS. Выводит в лог ответ торговой системы. Входных аргументов нет.
Пример orderbook
orderbook - пример построения агрегированного стакана на покупку и продажу по фиксированному инструменту по online потоку FORTS_ORDLOG_REPL и снепшот потоку FORTS_FUTORDERBOOK_REPL. При нажатии Enter в outfile выводится срез стакана.
Команда для запуска:
orderbook ISIN_ID depth outfile [r]
Входные аргументы:
isin_id - id инструмента;
depth - глубина выводимого стакана в файл (не больше 50);
outfile - файл для печати стакана;
r - включить обратное направление сортировки (параметр используется для инструментов с обратной сортировкой).
Пример p2sys
p2sys - пример авторизации роутера из cgate. Повторяет в цикле следующие действия:
Посылает ошибочный набор (login, pwd), в ответ получает сообщение logon failed;
После этого посылает правильный набор (login, pwd);
На сообщение об успешной авторизации посылается запрос на logout;
Возврат к пункту 1.
Пример send_mt
send_mt - многопоточный пример посылки заявки. (Примечание: компилируется только под компиляторами, поддерживающими C++11.). В треде 1 посылаются заявки.В треде 2 обрабатываются reply на посылаемые заявки.
Дистрибутив Cgate для среды Linux состоит из инсталляционого скрипта и архива tar.gz, в котором находятся загружаемые модули cgate, cgate_java, файлы include, файлы документации и файлы примеров.
Порядок установки:
Выполните команду:
chmod 755 ./install.sh
Выполните команду:
./install.sh ./cgate-1.3.9.8.x86_64.tar.gz
Внимание! Если после выполнения команды
./install.sh ./cgate-1.3.9.8.x86_64.tar.gz
вы получите ответ "Отказано в доступе", выполните команду
chmod 755 ./install.sh
- она добавит необходимые разрешения в атрибуты файла.
В ответ на запрос: "Please, enter cgate install path:" укажите полный путь к каталогу, в который вы хотите распаковать cgate;
В ответ на запрос: "Please, enter P2 login:" укажите логин пользователя;
В ответ на запрос: "Please, enter P2 password:" укажите пароль пользователя.
Внимание! Дальнейшие шаги установки различаются в зависимости от версии ОС Linux, установленной на компьютере!
Debian 6:
Установить пакет liblzo2-2(запуск роутера)
Установить пакет ant
Установить пакет openjdk-6-jdk (компиляция примеров java)
Установить пакет g++ (компиляция примеров C++).
CentOS 6:
Установить пакет lzo (запуск роутера)
Установить пакет gcc
Установить пакет gcc-c++ (компиляция примеров C++)
Установить пакет ant (компиляция примеров java).
Для компиляции примеров C++ необходимо выполнить команду:
make_c_samples.sh
Для запуска примеров C++ необходимо выполнить следующие действия:
Запустить роутер командой
router.sh
Зайти в каталог examples/c/aggrspy или examples/c/basic или examples/c/concurrent или examples/c/orderbook или examples/c/p2sys
Запустить скрипт вида *.sh.
Для компиляции примеров java необходимо выполнить команду:
make_java_samples.sh
Для запуска примеров java необходимо выполнить следующие действия:
Запустить роутер командой
router.sh
Зайти в каталог examples/java
Запустить скрипт runjava.sh с необходимыми параметрами.
Библиотека вводит набор объектов, с помощью которых осуществляется доступ к различным функциям системы. Основными объектами являются:
Описывает рабочее окружение библиотеки. Этот объект существует в единственном экземпляре. Его предназначение состоит в проведении инициализации и деинициализации подсистем, ведении журналов работы и управлении памятью.
Обеспечивает доступ к соединению с рутером Plaza-2
Описывает какое либо сообщение. В виде сообщений представляется вся информацию, отправляемая и получаемая пользователем - уведомления об обновлении данных, приказы в торговую систему, уведомления об исполнении приказов, уведомления об открытии и закрытии потоков данных.
Предоставляет доступ к получению сообщений. Этот интерфейс используется для получения всех сообщений - обновлений потоков данных, ответов об исполнении приказов - если Вы получаете какое-либо сообщение, то Вы делаете это с помощью объекта Listener.
Предоставляет доступ к отправке сообщений. Всё, что Ваш код отправляет, он отправляет с помощью одного из объектов Publisher.
Объекты Listener и Publisher существуют в привязке к какому-либо соединению. Вы можете использовать много соединений, много подписчиков и публикаторов в зависимости от архитектуры Вашего приложения; как правило, соединения для получения обновлений рыночной информации отделяются от соединений, предназначенных для отправки приказов.
Общая схема объектов библиотеки в составе клиентского ПО выглядит следующим образом:
![]() |
В общем окружении может существовать несколько соединений, каждое из которых содержит произвольное количество подписчиков и публикаторов, каждый из которых владеет некоторым количеством сообщений. При практическом использовании, как правило, назначение каждого соединения и соединенных с ним подписчиков и публикаторов продумывается исходя из фактических потребностей приложения.
Объекты Сgate: connection, listener, publisher в настройках url имеют параметр name, который отвечает за именование объекта в системе. Имя объекта должно быть уникальным. В случае попытки создать объект с занятым именем возвращается ошибка CG_ERR_INVALIDARGUMENT. Параметр name не обязателен для задания, по умолчанию Cgate присваивает объектам имена "noname_%d", где %d - некоторое число. Пользователям рекомендуется задавать параметр name для упрощения разборов логов Cgate.
В Cgate за время жизни объекта отвечает пользователь. Методы _new создают объекты. Методы _destroy разрушают объекты. Для избежания утечек памяти и системных ресурсов для каждого созданного объекта должен вызываться парный разрушающий метод.
В Cgate все функции являются реентерабельными, за исключением следующих функций:
cg_lsn_destroy
cg_conn_destroy
cg_pub_destroy
cg_pub_close
cg_env_open
cg_env_close
Вызов lsn_close и conn_close допускается только после получения сообщения CG_MSG_OPEN.
Порядок открытия подписчиков и публикаторов важен, если в callback слушателя используется публикатор mq reply. Публикатор доложен быть открыт в первую очередь, т.к. в противном случае при открытии подписчика мы можем получить сообщение mq и не будем иметь активного публикатора на этот момент времени.
Для начала работы с библиотекой необходимо выполнить инициализацию окружения. Инициализация выполняется с помощью функции env_open:
CG_RESULT cg_env_open( | settings) ; |
const char* settings
;Функция принимает на вход строку, описывающую параметры системы. Строка представляет собой набор пар вида "КЛЮЧ=ЗНАЧЕНИЕ", разделённых точкой с запятой. Поддерживаются следующие параметры:
Путь к файлу инициализации. В этом файле описывается конфигурацию библиотеки - режим журналирования и т.п.
Задание параметра может выглядеть, например, так: "ini=conf/settings.ini", в этом случае библиотека будет загружать конфигурацию из файла conf/settings.ini
Секция [p2syslog] задает настройку логирования p2. (см. "Настройка логов p2")
Инициализируемые подсистемы p2, через запятую.
mq - mq протокол;
replclient - клиент p2 реплики.
Способ логирования.
log = std - выводить логи cgate в stdout;
log = null - выводить в /dev/null;
log = p2;
log = p2:p2syslog - где p2syslog название секции с настройками логирования.
Минимальный уровень логов для вывода (по умолчанию debug).
Принимаемые значения: trace, debug, info, notice, warning, error, critical.
Идентификатор клиентского ПО. Должен быть указан для работы с библиотекой. Ключ используется для получения доступа в систему Plaza-2 - для тестовой системы существует набор предопределенных ключей; для production - ключ получается в результате прохождения процедуры сертификации ПО.
Ошибка инициализации может свидетельствовать об ошибке конфигурации: отсутствует конфигурационный файл, нарушена целостность установки и т.п. В случае такой ошибки нет смысла пытаться повторно инициализировать библиотеки; вместо этого следует остановить ваше ПО и проверить конфигурацию.
Если инициализация провалилась или не была выполнена, работа с другими функциями библиотеки невозможна.
Код инициализация системы может выглядеть следующим образом:
result = cg_env_open("ini=ini/settings.ini;key=72395823576"); if (result != CG_ERR_OK) { // вывести сообщение об ошибке и произвести выход из программы ... return; }
Что означает выполнение инициализации библиотеки с конфигурационным файлом ini/settings.ini и ключом приложения "72395823576". Файл ini/settings.ini должен быть доступен по указанному пути, относительно текущего рабочего каталога в момент запуска ПО.
Деинициализация выполняется перед выходом из программы вызовом функции env_close:
CG_RESULT cg_env_close( | ) ; |
void
;Функция проводит деинициализацию подсистем и закрытие журнала работы. Следует всегда вызывать данную функцию в конце работы ПО.
[p2syslog] logfile=./log/send.log // путь к файлу логов; traceini=./log/send.trace.ini //задает имя ini-файла, куда необходимо заносить все трейсы. logfileperday=0 // флаг "каждый день новый файл" logfilenametype=1 logtime=2 // формат вывода времени logfilecache=1024 // размер файлового кэша; logtoconsole=0 // флаг вывода на консоль; logtosyslog=0 // флаг логирования в syslog; logasync=1 // флаг асинхронности логов; addthreadid=1 // флаг добавления id thread ( при logasync=1 создается дополнительный тред, который осуществляет IO на диск.)
Объект "Соединение" обеспечивает взаимодействие с рутером Plaza-2 для отправки и получения сообщений. Эти объекты могут создаваться в произвольном количестве в любое время работы ПО при инициализированном окружении; тем не менее, рекомендуется создавать соединения при старте ПО, а уничтожать - непосредственно перед выходом.
Создание соединения выполняется вызовом cg_conn_new, например так:
cg_conn_t* conn; result = cg_conn_new("p2tcp://127.0.0.1:4001;app_name=test", &conn);
В этом примере создаётся соединение по протоколу TCP/IP с рутером Plaza-2 на порту 4001, запущенным на той же машине и именем приложения test. Вызов этой функции инициализирует объект соединения, но не приводит к фактической установке соединения.
Установка соединения производится посредством вызова функции conn_open:
result = cg_conn_open(conn, 0);
, где conn - объект, инициализированный вызовом функции cg_conn_new, а 0 в качестве второго параметра означает отсутствие параметров вызова открытия соединения.
Закрытие соединения выполняется вызовом conn_close:
result = cg_conn_close(conn);
При этом связь с рутером Plaza-2 разрывается, но объект остаётся инициализированным и может быть открыт повторно.
Уничтожение объекта выполняется с помощью функции conn_destroy:
result = cg_conn_destroy(conn);
Инициализация соединения может провалиться в случае нарушения целостности установки или неправильной конфигурации, например, были переданы некорректные параметры. В этом случае правильным действием будет остановка ПО и анализ конфигурации.
Открытие соединения может завершаться с ошибкой в силу разных причин, например, неготовности рутера Plaza-2 обслуживать входящие соединения, сбой в канале связи и прочее. Открытие соединения нужно выполнять циклично, так как следующая попытка открытия может оказаться удачной.
Пример описанного поведения:
cg_conn_t* conn; result = cg_conn_new("p2tcp://127.0.0.1:4001;app_name=test", &conn); if (result != CG_ERR_OK) { // инициализация соединения провалилась // дальнейшая работа невозможна // сообщить об ошибке и выйти из программы return; } // в этом месте существует инициализированный объект conn, // с которым можно работать - получать статус, открывать, закрывать while (haveToExit()) // основной цикл программы { uint32_t state; result = cg_conn_getstate(conn, state); // получить статус соединения if (result != CG_ERR_OK) // произошла ошибка получения статуса соединения { // сообщить об ошибке и выйти из программы return; } switch (state) { case CG_STATE_CLOSED: // соединение закрыто, значит пробуем открыть result = cg_conn_open(conn, 0); // сообшить в случае ошибки break; case CG_STATE_ERROR: // соединение в состоянии ошибки, значит надо закрыть result = cg_conn_close(conn); // сообшить в случае ошибки break; case CG_STATE_ACTIVE: // соединение активно, с ним можно работать ... } ... }
Подобный цикл реализует правильную работу с соединением: если соединение закрыто, то будет предпринята попытка его открыть; если соединение перешло в состояние ошибки, то выполняется его закрытие; работа с соединением производится в то время, когда оно активно.
В этом примере используется вызов функции cg_conn_getstate:
uint32_t state; result = cg_conn_getstate(conn, state);
Эта функция возвращает состояние инициализированного объекта "Соединение". Отправку и получение сообщений можно выполнять только в том случае, когда соответствующее соединение находится в состоянии "Активно" (CG_STATE_ACTIVE).
Соединение, находящееся в активном состоянии, нуждается в периодическом вызове функции обработки событий conn_process, в ходе которой выполняется вызов пользовательских функций обратного вызова, а также внутренняя обработка:
case CG_ACTIVE: { result=cg_conn_process(conn, 0, 0); if (result != CG_ERR_OK && result != CG_ERR_TIMEOUT) { // работа соединения нарушена result = cg_conn_close(conn); } ... break; }
Вызов conn_process принимает в качестве второго параметра интервал времени в миллисекундах, в течение которого происходит ожидание появление нового события внутри соединения. При этом, во время ожидания вызов conn_process блокируется. В случае, если в течение указанного времени не было произведено обработки ни одного сообщения, функция вернёт значение CG_ERR_TIMEOUT - это значение не является в данном случае индикатором ошибки и может быть использовано, например, для индикации того, что входящие сообщения отсутствуют и логика ПО может перейти к следующей задаче. Третий параметр зарезервирован.
Примечание! Если задать 0 в качестве значения второго параметра, то блокировка не происходит, при этом может достигаться 100% загрузка ядра CPU.
Получение потоков репликации выполняется с помощью объектов "Подписчик". Объект подписчик создаётся в привязке к соединению вызовом функции cg_lsn_new, например, так:
result = cg_lsn_new(conn, "p2repl://FORTS_FUTTRADE_REPL", dataCB, user_data, &lsn);
В этом примере lsn инициализируется объектом "Подписчик", настроенным на получение потока репликации FORTS_FUTINFO_REPL через соединение conn. Сообщения об обновлениях данных, а также других событиях жизненного цикла потока будут приходить в заданную пользователем функцию обратного вызова dataCB. При создании подписки возможно задание различных параметров, в том числе клиентской схемы репликации; в этом случае инициализация объекта будет происходить так:
result = cg_lsn_new(conn, "p2repl://FORTS_FUTTRADE_REPL;scheme=|FILE|ini/futtrade.ini|FutTrade", dataCB, user_data, &lsn);
, где путь к файлу описания схемы и название секции соответствующего ini-файла задаются в параметре scheme строкой специального формата.
В случае успешного вызова функции cg_lsn_new объект находится в инициализированном, но не активном состоянии. Фактически открытие потока происходит посредством вызова функции cg_lsn_open:
result = cg_lsn_open(lsn, 0);
В этом примере поток репликации открыт без указания параметров, что означает, что он будет открыт с параметрами по умолчанию:
номер жизни схемы данных не установлен (равен 0)
ревизии всех таблиц равны 0, что означает их получение с нуля
режим репликации выбран, как snapshot+online, что приводит к получению среза таблиц (или полной их истории), а затем переходу к получению данных в режиме он-лайн
Параметры задаются в виде строки:
result = cg_lsn_open(lsn, "mode=online");
При этом поток будет открыт в режиме online, что исключает фазу получения начального слепка данных. В режиме online, при разрывах соединения, не гарантируется непрерывность потока данных. Подробное описание возможных параметров см. в описании функции cg_lsn_open.
Функция cg_lsn_open может возвращать код ошибки в разных случаях: временная недоступность потока, нарушение работы канала. Для правильной работы следует обеспечить циклические попытки открытия потоков.
Поток закрывается вызовом функции cg_lsn_close:
result = cg_lsn_close(lsn);
При этом происходит отключение подписчика от получения данных и сообщения по обновлению данного потока прекращают идти через соединение; сам объект остаётся в инициализированном состоянии и может быть открыт повторно, в том числе и с другими параметрами.
Уничтожение объекта происходит посредством вызова cg_lsn_destroy:
result = cg_lsn_destroy(lsn);
После этого объект lsn освобождается и дальнейшая работа с ним невозможна.
Для корректного получения обновлений данных объектом "Подписчик" необходимо вызывать функцию conn_process для соединения, к которому привязан объект. Частота получения данных не превышает частоту вызовов conn_process, поэтому для максимальной скорости получения данных нужно обеспечить максимально возможную частоту вызова conn_process для интересующих соединений. При отсутствии вызова conn_process для соединения в течение timeout = 3 минутам происходит отключение подписчика.
При получении данных, а также в моменты возникновения других событий в жизненном цикле потока репликации происходит вызов задаваемой пользователем в lsn_new функции обратного вызова, имеющей следующий вид:
typedef CG_RESULT (*CG_LISTENER_CB)(cg_conn_t* conn, cg_listener_t* listener, struct cg_msg_t* msg, void* data);
В функцию обратного вызова передаются:
conn - соединение, к которому привязана подписка
listener - объект "Подписчик"
msg - пришедшее сообщение
data - пользовательские данные, переданные в момент вызова функции lsn_new
Сообщение msg, которое приходит в пользовательскую функцию, в общем случае описывается следующей структурой:
struct cg_msg_t { uint32_t type; // Тип сообщения size_t data_size; // Размер данных void* data; // Указатель на данные };
Любое сообщение, приходящее в пользовательскую функцию, гарантированно имеет указанные поля.
Идентификация конкретного вида сообщения выполняется с помощью анализа поля type. При получении потоков репликации используются следующие типы сообщений:
Сообщение приходит в момент активации потока данных. Это событие гарантированно возникает до прихода каких либо данных по данной подписке. Для потоков репликации приход сообщения означает, что схема данных согласована и готова для использования (Подробнее см. Схемы данных) Данное сообщение не содержит дополнительных данных и его поля data и data_size не используются.
Примечание: Методы cg_pub_getscheme, cg_lsn_getscheme можно вызывать только после прихода сообщения CG_MSG_OPEN, до этого момента схема не определена.
Сообщение приходит в момент закрытия потока данных. Приход сообщения означает, что поток был закрыт пользователем или системой. В поле data содержится указатель на int, по указанному адресу хранится информация о причине закрытия подписчика. Возможны следующие причины:
CG_REASON_UNDEFINED - не определена;
CG_REASON_USER - пользователь вернул ошибку в callback подписчика;
CG_REASON_ERROR - внутренняя ошибка;
CG_REASON_DONE - вызван метод cg_lsn_destroy;
CG_REASON_SNAPSHOT_DONE - снэпшот получен.
Означает момент начала получения очередного блока данных. В паре со следующим сообщением может быть использовано логикой ПО для контроля целостности данных. Данное сообщение не содержит дополнительных данных и его поля data и data_size не используются.
Означает момент завершения получения очередного блока данных. К моменту прихода этого сообщения можно считать, что данные полученные по данной подписке, находятся в непротиворечивом состоянии и отражают таблицы в синхронизированном между собой состоянии. Данное сообщение не содержит дополнительных данных и его поля data и data_size не используются.
Сообщение прихода потоковых данных. Поле data_size содержит размер полученных данных, data указывает на сами данные. Само сообщение содержит дополнительные поля, которые описываются структурой rtscg_msg_streamdata_t. Подробнее о получении данных будет рассказано ниже в данном разделе.
Переход потока в состояние online - это означает, что получение начального среза было завершено и следующие сообщения CG_MSG_STREAM_DATA будут нести данные он-лайн. Данное сообщение не содержит дополнительных данных и его поля data и data_size не используются.
Изменен номер жизни схемы. Такое сообщение означает, что предыдущие данные, полученные по потоку, не актуальны и должны быть очищены. При этом произойдёт повторная трансляция данных по новому номеру жизни схемы данных. Поле data сообщения указывает на целочисленное значение, содержащее новый номер жизни схемы; поле data_size содержит размер целочисленного типа. Подробнее про обработку номера жизни схемы в конце данного раздела.
Произошла операция массового удаления устаревших данных. Поле data сообщения указывает на структуру cg_data_cleardeleted_t, в которой указан номер таблицы и номер ревизии, до которой данные в указанной таблице считаются удаленными.
Сообщение содержит состояние потока данных; присылается перед закрытием потока. Поле data сообщения указывает на строку, которая в закодированном виде содержит состояние потока данных на момент прихода сообщения - сохраняются схема данных, номера ревизий таблиц и номер жизни схемы на момент последнего CG_MSG_TN_COMMIT (Внимание: при переоткрытии потока с replstate ревизии, полученные после последнего CG_MSG_TN_COMMIT, будут присланы повторно!) Эта строка может быть передана в вызов cg_lsn_open в качестве параметра "replstate" по этому же потоку в следующий раз, что обеспечит продолжение получения данных с момента остановки потока.
При приходе события CG_MSG_P2REPL_DATA параметр msg пользовательской функции обратного вызова содержит указатель на расширенную структуру данных:
struct cg_msg_streamdata_t { uint32_t type; // Тип сообщения. Всегда CG_MSG_P2REPL_DATA для данного сообщения size_t data_size; // Размер данных void* data; // Указатель на данные size_t msg_index; // Номер описания сообщения в активной схеме uint32_t msg_id; // Уникальный идентификатор типа сообщения const char* msg_name; // Имя сообщения в активной схеме int64_t rev; // Ревизия записи const uint8_t* nulls; // Массив байт, содержащий 1 для каждого поля, являющегося NULL-ом. };
Доступ к расширенной структуре осуществляется следующим способом:
CG_RESULT dataCallback(rtscg_conn_t* conn, rtscg_listener_t* listener, struct rtscg_msg_t* msg, void* data) { switch(msg->type) { case CG_MSG_STREAM_DATA: { // приведение указателя к расширенной структуре cg_msg_streamdata_t* replmsg = (cg_msg_streamdata_t*)msg; // здесь можно использовать расширенную структуру ... } ... } }
С помощью данной структуры можно узнать номер таблицы и её имя в схеме данных - эта информация доступна в полях msg_index и msg_name структуры. Для реплики Plaza-2 поле msg_id не используется и его значение равно 0. Поле rev содержит ревизию (номер обновления) записи в таблице, а поле nulls может содержать указатель на массив байт, значения которых определяют, имеется ли конкретное поле в записи или отсутствует.
Данные, на которые ссылается указатель data сообщения, структурированы в соответствие со схемой данных, используемых в данной подписке. О том, что такое схемы данных и каким образом можно получить доступ к интересующим полям записи, можно узнать в следующем разделе.
Номер жизни - это атрибут схемы данных, который служит для определения актуальности полученных в потоке данных. Номер жизни схемы у источника реплики (сервера) и клиента должны совпадать. Сравнение производится при открытии потока репликации. Если номера жизни не совпадаю, это означает, что предыдущие данные, полученные в потоке, не актуальны и должны быть очищены. Сигналом о таком событии служит специальная нотификация CG_MSG_P2REPL_LIFENUM, содержащая новый номер жизни схемы.
Клиентский номер жизни схемы задается в параметрах функции cg_lsn_open:
cg_lsn_open(lsn, "lifenum=%d"). Допускается задавать "lifenum=0", строка "lifenum=" также является допустимым вариантом и эквивалентна заданию "lifenum=0".
cg_lsn_open(lsn, "replstate=%s") - восстановление из строки состояния потока реплики. Строка состояния - это строка, которая в закодированном виде содержит состояние потока данных на момент его предыдущего закрытия. Под состоянием потока здесь понимается: схема данных, номера ревизий таблиц и номер жизни схемы. Данная строка приходит в нотификации CG_MSG_P2REPL_REPLSTATE перед закрытием потока данных.
Номер жизни не может быть задан одновременно в 'lifenum' и 'replstate'.
Номер жизни схемы всегда десятичное число. Если значение номера жизни не будет десятичным числом, открытие подписки произойдет с ошибкой.
После передачи клиентского номера жизни запускается процесс его верификации. Возможны 3 ситуации:
переданный clientLifeNumber < serverLifeNumber. В этом случае подписка открывается, клиентский код перед CG_MSG_OPEN получает сообщение CG_MSG_P2REPL_LIFENUM, в поле данных которого указан текущий серверный номер жизни. При приходе данного сообщения необходимо очистить все старые данные и получить их заново.
переданный clientLifeNumber = serverLifeNumber. Объект "Подписчик" готов к работе сразу, без уведомлений и очистки данных.
переданный clientLifeNumber > serverLifeNumber. Возвращается ошибка P2ERR_REPL_LIFE_NUMBER_MISMATCH.
Допускается вообще не передавать номер жизни при открытии подписки. В этом случае объект "Подписчик" начнет работу по серверному номеру жизни, получая нотификацию CG_MSG_P2REPL_LIFENUM.
Любые данные, которые принимаются или отправляются в процессе взаимодействия клиентского ПО с торговой системой, специальным образом структурированы. Для описания структуры конкретных сообщений применяются схемы данных.
Схема данных описывает множество возможных сообщений для выбранного канала данных (подписки или публикации), поля и типы этих сообщений, а также задает правила доступа к этим данным. Схема данных описывается следующей структурой:
struct cg_scheme_desc_t { // Тип схемы uint32_t scheme_type; // свойства схемы uint32_t features; // Количество сообщений в схеме size_t num_messages; // Указатель на список описаний сообщений struct cg_message_desc_t* messages; };
В настоящее время поддерживается единственный тип схемы, которому соответствует идентификатор 1 - данные хранятся в бинарном виде с выравниванием 4 байта без поддержки опциональных полей.
Поле features описывает доступную информацию в схеме - по этому полю можно узнать, заданы ли значения по умолчанию для полей в данной схеме, имеют ли поля или сообщения описания и т.п. За это отвечают константы CG_SCHEME_BIN_*.
Поле num_messages задает количество сообщений в схеме, а поле messages указывает на первое из них. Сообщения являются основным объектом, описывающим конкретные структуры данных и используются во всех видах подписки и публикации; например, для реплики Plaza-2 сообщения описывают события обновления данных в таблицах.
Каждое сообщение описывается структурой:
struct cg_message_desc_t { // указатель на следующее сообщение struct cg_message_desc_t* next; // размер блока сообщения size_t size; // Количество полей в сообщении size_t num_fields; // Указатель на массив описаний полей struct cg_field_desc_t* fields; // Идентификатор сообщения // Может быть 0, если идентификатор у сообщения отсутствует uint32_t id; // Указатель на имя сообщения // Может быть NULL - в этом случае у сообщения отсутствует имя char *name; // Указатель на описание сообщения // Может быть NULL - в этом случае у сообщения отсутствует описание char *desc; // строка со свойствами char* hints; // количество индексов сообщения size_t num_indices; // Указатель на первый индекс struct cg_index_desc_t* indices; };
Поле next указывает на следующее сообщение в схеме или содержит значение NULL, что означает, что данное сообщение - последнее. Таким образом, сообщения упорядочены в связанном списке и доступ к ним можно получить с помощью цикла вида:
cg_scheme_desc_t* schemedesc; // инициализированный указатель на схемы данных for (cg_message_desc_t* msgdesc = schemedesc->messages; msgdesc; msgdesc = msgdesc->next) { // здесь можно работать с описанием сообщения, // которое содержится в msgdesc ... }
Поле size структуры описания сообщения задает размер блока в байтах, который требуется для хранения данных сообщения целиком. Поле num_fields содержит количество полей в сообщении, а fields указывает на первое поле сообщения.
Поля id, name и desc содержат идентификатор сообщения, его имя и описание. Идентификатор, имя или описание могут отсутствовать, в случае, если конкретная схема не описывает эти значения для сообщений.
Поле hints содержит параметры, которые могут быть использованы пользователем для автоматической настройки своей программы на определенный вид или способ обновления данных. В настоящее время схема данных, описывающая команды торговой системы FORTS, содержит хинты request и reply, подсказывающие, какие сообщения нужно отправлять, а какие приходят в ответ. Поле hints может содержать несколько хинтов, разделенных символом ";".
Поле num_indices содержит количество индексов, а поле indices указывает на первый индекс. Первый индекс в списке всегда является уникальным primary ключом.
Индексы описываются следующей структурой:
struct cg_index_desc_t { // указатель на следующий индекс struct cg_index_desc_t * next; // количество полей в ключе size_t num_fields; // указатель на описание первого поля в ключе struct cg_indexfield_desc_t* fields; // имя ключа char* name; // описание ключа char* desc; // строка со свойствами char* hints; };
Поле next указывает на следующий индекс в схеме или содержит значение NULL, что означает, что данный индекс - последний.
Поле num_fields указывает на количество полей в индексе.
Поле fields указывает на первое поле в индексе.
Поля name и desc содержат название индекса и его описание.
Поле hints содержит хинты для индекса, например, "unique".
Поля индекса описываются структурой:
struct cg_indexfield_desc_t { // указатель на следующее описание поля ключа struct cg_indexfield_desc_t* next; // указатель на поле struct cg_field_desc_t* field; // порядок сортировки uint32_t sort_order; };
Поле next указывает на следующее поле в индексе или содержит значение NULL, что означает, что данное поле - последнее.
Поле field указывает на структуру - описатель поля схемы.
Поле sort_order задает порядок сортировки 0 - по возрастанию, 1 - по убыванию.
Поля сообщения описываются следующей структурой:
// Описание поля сообщения struct cg_field_desc_t { // указатель на следующее поле struct cg_field_desc_t* next; // Идентификатор поля // Может быть 0, если идентификатор поля отсутствует uint32_t id; // Имя поля // Может быть NULL - в этом случае у поля отсутствует имя char* name; // Описание поля // Может быть NULL - в этом случае у поля отсутствует описание char* desc; // Тип поля char* type; // Длина значения данного поля size_t size; // Смещение относительно начала сообщения size_t offset; // Указатель на значение поля по умолчанию. // Указывает на буфер размером size, в котором хранятся данные в формате type // Если null, то значение по-умолчанию отсутствует void* def_value; // Указатель на список значений, принимаемых полями struct cg_field_value_desc_t* values; };
Поле next указывает на описание следующего поля сообщения или содержит NULL в случае последнего поля. Поля id, name и desc задают идентификатор, имя и описание поля; для различных схем сообщений эти поля могут содержать пустые значения. Поле type содержит название типа поля, по которому можно определить способы работы с этим полем. Наиболее часто используемыми типами полей являются следующие типы:
Целочисленные беззнаковые значения размером 1, 2, 4 и 8 байт соответственно
Целочисленные беззнаковые значения размером 1, 2, 4 и 8 байт соответственно
Строка с максимальной длиной NN (завершаемая байтом со значением 0)
Число в двоично-десятичном формате с общим количеством знаков MM и количеством знаков после запятой NN
Блок с неформатированными двоичными данными размера NN
Структура, описывающая дату и время
Поле size содержит размер значения поля, а поле offset - смещение данного поля в байтах от начала блока данных. Эта информация позволяет однозначно идентифицировать расположение и размер интересующего поля в блоке данных сообщения.
Поле def_value содержит указатель на значение по умолчанию. Тип и размер значения полностью совпадают с типом и размером поля, таким образом, инициализация поля значением по-умолчанию может быть выполнена простым копированием. Значение NULL поля def_value соответствует отсутствию значения по умолчанию.
Поле values содержит указатель на первое значение списка допустимых значений. Значение NULL поля values означает, что поле может принимать любое значение из области определения типа.
struct cg_field_value_desc_t { // указатель на следующее значение struct cg_field_value_desc_t* next; // название значения char* name; // описание значения char* desc; // указатель на допустимое значение void* value; // для полей типа integer (i[1-8], u[1-8]) маска, // определяющая диапазон занимаемых значением бит void* mask; };
Поле next указывает на следующее значение списка допустимых значение поля или содержит значение NULL, что означает, что данное значение - последнее.
Поля name и desc содержат наименование и описание значения.
Поле value содержит указатель на значение поля, при этом размер и тип значения совпадают с размером и типом самого поля.
Поле mask используется для группировки взаимоисключающих значений, при этом значения с разными масками могут комбинироваться.
Предположим, что мы имеем дело с подпиской на получение потока репликации Plaza-2 со следующей схемой данных:
[dbscheme:FutTrade] table=orders_log table=heartbeat [table:FutTrade:orders_log] field=replID,i8 field=replRev,i8 field=replAct,i8 field=id_ord,i8 field=sess_id,i4 [table:FutTrade:heartbeat] field=replID,i8 field=replRev,i8 field=replAct,i8 field=server_time,t
Подобный формат описания схем в виде ini-файлов принят в системе Plaza-2.
Эта схема описывает две таблицы (два сообщения) с некоторым набором полей в каждой из них. Предположим, что нас интересует получение номеров заявок из таблицы orders_log и событий синхронизации серверного времени из таблицы heartbeat - эти значения содержатся в поле id_ord сообщения orders_log и поле server_time сообщения heartbeat, соответственно.
Существуют два способа разбора получаемых данных - статический, с использованием заранее заготовленных структур данных и динамический, с вычислением смещений интересующих полей в момент получения схемы.
Статический подход состоит в том, что для интересующих потоков на этапе разработки фиксируются схемы данных, которые будут использованы в дальнейшем; затем по схемам данных вручную или автоматически, например, с помощью утилиты schemetool, генерируются описания структур языка C, соответствующие форматам бинарных блоков данных для каждого из принимаемых сообщений (для языков типа Java или .NET вместо структур генерируется код, который разбирает бинарные блоки сообщений). В процессе работы данные пришедшего сообщения отображаются на структуру, соответствующую типу сообщения и осуществляется требуемая обработка данных.
Такой подход позволяет упростить разработку с одной стороны, с другой - фиксирует определённый формат схем данных, что потребует повторной подготовки структур данных или кода разбора бинарных блоков, в случае изменения схем данных - старые структуры могут перестать отображаться на новые форматы сообщений, что в некоторых случаях может привести к сложнообнаруживаемым ошибкам.
В случае использования заранее заготовленных структур для отображения данных, следует использовать клиентскую схему при инициализации потока. При изменении схемы получаемых данных, структуры следует сгенерировать заново.
Заранее заготовленные структуры данных или код для разбора бинарных блоков можно сгенерировать с использованием утилиты schemetool.
Выглядеть это может следующим образом:
// Описание структур, полученное с использованием // утилиты schemetool #pragma pack(push, 4) // Scheme "FutTrade" description struct orders_log { signed long long replID; signed long long replRev; signed long long replAct; signed long long id_ord; signed int sess_id; }; const int orders_log_index = 0; struct heartbeat { signed long long replID; signed long long replRev; signed long long replAct; struct cg_time_t server_time; }; const int heartbeat_index = 1; #pragma pack(pop) // в обработчике подписки case CG_MSG_STREAM_DATA: { cg_msg_streamdata_t* replmsg = (cg_msg_streamdata_t*)msg; if (replmsg->msg_index == orders_log_index) { orders_log* ordlog = (orders_log *)replmsg->data; printf ("Order ID = %lld\n", ordlog->id_ord); } else if (replmsg->msg_index == heartbeat_index) { heartbeat* hb = (heartbeat *)replmsg->data; printf ("Server time = %d:%d:%d.%d\n", hb->server_time.hour, hb->server_time.min, hb->server_time.sec, hb->server_time.ms); } }
Динамический подход предполагает отсутствие явно зафиксированной схемы данных, напротив - схема данных каждый раз получается из источника схемы (например, с сервера репликации), а код пользователя анализирует её и осуществляет поиск интересующих сообщений и полей в них.
Подобный подход позволяет создать более универсальную систему, которая сможет переживать не критичные изменения схем данных; с другой стороны динамический анализ схемы является более сложным в реализации.
Первым шагом такого подхода является подготовка информации об интересующих полях - нужно проанализировать используемую схему потока данных и запомнить номера интересующих сообщений и смещения интересующих полей:
// переменные, которые будут содержать нужную для анализа // поступающих данных информацию size_t index_orders_log; // индекс сообщения orders_log в схеме size_t offset_id_ord; // смещение поля id_ord в блоке size_t index_hearbeart; // индекс сообщения heartbeat в схеме size_t offset_server_time; // смещение поля server_time в блоке
Этой информации достаточно, для того, чтобы в момент прихода данных идентифицировать тип сообщения и найти нужное поле в бинарном блоке. Заполнение этих полей выполняется следующим образом:
cg_scheme_desc_t* scheme; // инициализированное описание схемы данных size_t msgidx = 0; for (cg_message_desc_t* msgdesc = schemedesc->messages; msgdesc; msgdesc = msgdesc->next, msgidx ++) { size_t fieldindex = 0; if (strcmp(msgdesc->name, "orders_log") == 0) { index_orders_log = msgidx; for (cg_field_desc_t* fielddesc = msgdesc->fields; fielddesc; fielddesc = fielddesc->next, fieldidx ++) if (strcmp(fielddesc->name, "id_ord") == 0 && strcmp(fielddesc->type, "i8") == 0) offset_id_ord = fieldidx; } if (strcmp(msgdesc->name, "heartbeat") == 0) { index_heartbeat = msgidx; for (cg_field_desc_t* fielddesc = msgdesc->fields; fielddesc; fielddesc = fielddesc->next, fieldidx ++) if (strcmp(fielddesc->name, "server_time") == 0 && strcmp(fielddesc->type, "t") == 0) offset_server_time = fieldidx; } }
В приведенном коде осуществляется последовательный перебор всех сообщений схемы и поиск нужных полей для интересующих сообщений. При этом осуществляется проверка типов полей в соответствие с ожиданиями.
Обработка получаемых данных выполняется следующим образом:
// в обработчике подписки case CG_MSG_STREAM_DATA: { cg_msg_streamdata_t* replmsg = (cg_msg_streamdata_t*)msg; // приведение к char*, чтобы затем правильно прибавлять offset в байтах char* data = (char*)replmsg->data; if (replmsg->msg_index == index_orders_log) { int64_t id_ord = *((int64_t*)(data + offset_id_ord)); printf ("Order ID = %lld\n", id_ord); } else if (replmsg->msg_index == index_heartbeat) { cg_time_t *srvtime = (cg_time_t*)(data + offset_server_time); printf ("Server time = %d:%d:%d.%d\n", srvtime->hour, srvtime->min, srvtime->sec, srvtime->ms); } }
Этот пример будет выводить на экран идентификатор заявки в момент прихода данных по изменению состояния заявки и серверное время в момент прихода соответствующего сообщения.
Показанный пример демонстрирует следующие полезные практики при создании кода:
Контроль типов данных при анализе схемы - обеспечивает корректную диагностику ошибок при изменении схем
Использование численных идентификаторов сообщений вместо строк - положительно влияет на производительность, так вместо более дорогой операции сравнения строк можно обойтись сравнением двух чисел
Отсутствие копирования данных - не нужно обращаться к каждому полю вызовом специальной функции; данные доступны непосредственно в буфере сообщения
Поддержка эволюции схем данных - код, анализирующий схему при открытии потока, сможет работать с разными вариантами схем данных, без необходимости изменения зашитых идентификаторов и перекомпиляции
Отправка транзакций FORTS и получение ответов об их исполнении выполняется с помощью объектов «Публикатор», «Подписчик». Объект публикатор создаётся в привязке к соединению вызовом функции cg_pub_new, например, так:
result = cg_pub_new(conn, "p2mq://FORTS_SRV;category=FORTS_MSG;" "name=PUB;scheme=|FILE|ini/forts_scheme_messages.ini|message ", &pub);
В этом примере pub инициализируется объектом "Публикатор", настроенным на отправку транзакций FORTS по схеме, хранящейся в подкаталоге ini с именем файла forts_scheme_messages.ini и именем схемы “message” через соединение conn. Публикатору присвоено имя “PUB”, на которое будет ссылаться подписчик.
В случае успешного вызова функции cg_pub_new объект находится в инициализированном, но не активном состоянии. Дальнейшая работа с публикатором возможна после вызова функции cg_pub_open:
result = cg_pub_open(pub, 0);
Параметры открытия для объекта публикатор в настоящее время не предусмотрены, поэтому в качестве второго параметра передаётся пустой указатель.
После того, как публикатор создан и открыт, можно создавать и отправлять транзакции. Для создания транзакции можно воспользоваться функцией cg_pub_msgnew.
result = cg_pub_msgnew(pub, CG_KEY_NAME, “FutAddOrder”, &msgptr);
В данном случае будет создано сообщение для постановки заявки FORTS (транзакция FutAddOrder) по имени, и указатель на него будет записан в переменную msgptr. При помощи функции cg_pub_msgnew можно так же создавать сообщения по его номеру в активной схеме и идентификатору.
Сообщение представляет собой указатель на структуру cg_msg_data_t:
struct cg_msg_data_t { uint32_t type; // Тип сообщения = CG_MSG_P2REPL_DATA size_t data_size; // Размер данных void* data; // Указатель на данные size_t msg_index; // Номер сообщения в активной схеме uint32_t msg_id; // Уникальный идентификатор сообщения const char* msg_name; // Имя сообщения в схеме uint32_t user_id; // Пользовательский номер сообщения const char* addr; // Адрес получателя struct cg_msg_data_t* ref_msg; // Связанное сообщение (сейчас не используется) };
Поле data структуры указывает на буфер в памяти соответствующего размера, который необходимо заполнить согласно активной схеме. Проще всего это сделать приведя этот указатель к правильной структуре. Например, так:
ord = (struct AddOrder*)msgptr->data; strcpy(ord->broker_code, "HB00");
Создать описание структуры из схемы можно при помощи утилиты schemetool.
После того, как сообщение создано и заполнено, его нужно отправить при помощи функции cg_pub_post:
result = cg_pub_post(pub, msgptr, CG_PUB_NEEDREPLY);
Флаг CG_PUB_NEEDREPLY означает, что мы хотим получать ответы в соответствующий подписчик lsnreply.
После того, как сообщение отправлено, его можно уничтожить при помощи функции cg_pub_msgfree:
result = cg_pub_msgfree(pub, msgptr);
При отсылке однотипных заявок, более эффективно использовать созданное сообщение повторно.
Публикатор закрывается вызовом функции cg_pub_close:
result = cg_pub_close(pub);
При этом происходит отключение публикатора от объекта соединение; сам объект остаётся в инициализированном состоянии и может быть открыт повторно. Уничтожение объекта происходит посредством вызова cg_pub_destroy:
result = cg_pub_destroy(pub);
После этого объект pub освобождается и дальнейшая работа с ним невозможна.
Подписчик для получения ответов на команды создаётся следующим образом:
result = cg_lsn_new(conn, “p2mqreply://;ref=PUB”, replyCB, user_data, &lsnreply);
Этот вызов инициализирует переменную lsnreply специальным объектом-подписчиком для получения ответов на отправленные публикатором сообщения. Связь между подписчиком и публикатором осуществляется по имени, в данном случае это имя “PUB”, параметр “ref=PUB” строки инициализации устанавливает эту связь. С одним публикатором можно сопоставить один подписчик. Имена соответствующих пар должны быть уникальны. Сообщения, содержащие ответы на транзакции, а также других событиях публикатора будут приходить в функцию replyCB. Жизненный цикл данного объекта «подписчик» ничем не отличается от жизненного цикла подписчика реплики, рассмотренного в соответствущем разделе, за исключением того, что в replyCB приходят не сообщения системы репликации, а простые единичные сообщения MQ, описываемые структурой cg_msg_data_t, которые ссылаются на данные, описываемые схемой соответствующего публикатора, а так же нотификация CG_MSG_P2MQ_TIMEOUT, в случае, если был превышен интервал ожидания ответа на сообщение. При закрытии соединения, на все отправленные mq запросы, на которые не был получен ответ приходят сообщения с нотификацией CG_MSG_P2MQ_TIMEOUT. При возврате ошибки из callback пользователя подписчик закрывается. Подписчик p2mqreply должен создаваться после создания публикатора mq, в противном случае ссылка на объект ref=PUB будет не валидной. Порядок разрушения этих связанных объектов не важен.
Пользовательский обработчик ответов может выглядеть следующим образом:
CG_RESULT ClientMessageCallback(cg_conn_t* conn, cg_listener_t* listener, struct cg_msg_t* msg, void* data) { switch (msg->type) { case CG_MSG_DATA: { uint32_t* data = msg->data; printf("Client received reply [id:%d, data: %d, user-id: %d, name: %s]\n", ((struct cg_msg_data_t*)msg)->msg_id, *((uint32_t*)msg->data), ((struct cg_msg_data_t*)msg)->user_id, ((struct cg_msg_data_t*)msg)->msg_name); { struct scheme_desc_t* scheme; size_t bufSize; if (cg_lsn_getscheme(listener, &scheme) != CG_ERR_OK) scheme = 0; if (cg_msg_dump(msg, scheme, 0, &bufSize) == CG_ERR_BUFFERTOOSMALL) { char* buffer = malloc(bufSize+1); bufSize++; if (cg_msg_dump(msg, scheme, buffer, &bufSize) == CG_ERR_OK) printf("client dump: %s\n", buffer); free(buffer); } } break; } case CG_MSG_P2MQ_TIMEOUT: { printf("Client reply TIMEOUT\n"); break; } default: printf("Message 0x%X\n", msg->type); } return CG_ERR_OK; }
Этот пользовательский обработчик либо выводит дамп сообщений с помощью вспомогательной функции cg_msg_dump, либо, в случае превышения ожидания ответа, отслеживает эту ситуацию и выводит на экран соответствующие сообщения.
Для осуществления связи между отправленными сообщениями и ответами на них, следует использовать поле user_id структуры cg_msg_data_t: задание user_id у отправляемого сообщения обеспечивает получение ответного сообщения с тем же user_id.
При установке соединения p2sys подписчик получает 2 сообщения типа CG_MSG_DATA:
ConnectoinConnected (msgid = 3). Поле данных содержит переменную state типа int32 со статусом операции, равным 2;
RouterDisconnected (msgid = 2). Поле данных также содержит переменную state типа int32 со значением 1.
В случае успеха пользователь может послать исходящий запрос
аутентификации. Для этого он должен создать сообщение RouterLogin (msgid = 1) типа CG_MSG_DATA. В поле
данных этого сообщения должна находиться строка формата
"USERNAME=%имя_пользователя%;PASSWORD=%пароль%
".
Если логин и пароль являются верными, подписчик примет сообщение RouterConnected (msgid = 1). В поле данных содержится пользовательский логин в виде строки. Если же аутентификация отклонена, подписчик примет сообщение LogonFailed (msgid = 5). В поле данных также содержится статус операции равный 1.
Для отключения от системы Plaza-II необходимо послать сообщение RouterLogout (msgid = 2). Поле данных в этом сообщении игнорируется. В ответ подписчик должен получить оповещение RouterDisconnected со статусом, равным 1.
По окончании работы необходимо закрыть объекты стандартным способом: сначала публикатор и подписчик, затем соединение.
Программный интерфейс библиотеки построен с учетом ряда соглашений:
Каждая функция API возвращает код ошибки
Выходные параметры задаются в качестве указателей на переменные, куда следует поместить возвращаемое функцией значение и располагаются в конце списка параметров
Функции имеют префиксы, как правило, состоящие из двух частей, первая - "cg_" означает принадлежность функции библиотеке Client Gate, вторая идентифицирует класс объектов, с которым работает та или иная функция
env_ - функции работы с общим окружением работы системы
conn_ - функции работы с соединением
lsn_ - функции работы с подписками
pub_ - функции работы с отправкой сообщений
log_ - функции работы с журналом работы
, при этом существует несколько функций, обладающих только префиксом "cg_" - это вспомогательные и сервисные функции, которые не относятся к какой либо конкретной группе.
Функции вида lsn_new, pub_new и т.п. создают и инициализируют объекты, которые затем должны быть освобождены соответствующими вызовами lsn_destroy, pub_destroy и т.п. В случае, если объекты не будут явно уничтожены, возникнут утечки памяти.
Объекты, доступ к которым предоставляется библиотекой, имеют жизненный цикл, описываемый следующей схемой:
![]() |
Объекты в течение своего жизненного цикла существуют в следующих состояниях:
CG_STATE_CLOSED
Закрытое состояние. В этом состоянии объект создаётся (после вызова cg_OBJ_new) или переходит в него после вызова cg_OBJ_close. Объект может перейти в состояние CG_STATE_CLOSED в случае ошибки.
CG_STATE_OPENING
Состояние перехода из закрытого в активное состояние. В этом состоянии объект существует после вызова cg_OBJ_open и до перехода в состояние CG_STATE_ACTIVE или, в случае возникновения ошибки открытия объекта, в состояние CG_STATE_ERROR.
CG_STATE_ACTIVE
Активное состояние - основное рабочее состояние объекта. В этом состоянии возможна работа с объектом - обработка событий соединения, отправка или получение сообщений. В это состояние объект попадает после успешного завершения процесса открытия из состояния CG_STATE_OPENING. Из этого состояние объект может перейти либо в состояние CG_STATE_CLOSED посредством вызова функции cg_OBJ_close, либо в состояние CG_STATE_ERROR в случае возникновения ошибки. Connection может перейти из CG_STATE_ACTIVE в CG_STATE_OPENING при разрыве соединения между своим и вышестоящим роутером.
Примечание: объект connection при закрытии закрывает все связанные с ним объекты ( подписчики и публикаторы).
CG_STATE_ERROR
Состояние ошибки. В нём объект оказывается, если в процессе его открытия или работы произошла ошибка. Из этого состояния объект можно перевести в закрытое состояние вызовом cg_OBJ_close или уничтожить объект вызовом cg_OBJ_destroy, если дальнейшая работа с ним не требуется.
Такая схема состояний используется для следующих объектов:
Соединения cg_conn_t
Подписчики cg_listener_t
Публикаторы cg_publisher_t
Библиотека CGate может быть использована в многопоточном окружении, но не является потокобезопасной. Это означает, что для корректной работы с библиотекой из нескольких потоков необходимо соблюдать специальные правила:
Работа с объектом "Соединение" в каждый момент времени должна вестить только из одного потока.
При этом корректным является создание соединения из одного потока, а работа с ним из другого - главное, чтобы несколько потоков не выполняли действия с соединением в одно и то же время. Если существует необходимость разделять соединение между несколькими потоками одновременно, следует воспользоваться примитивами синхронизации ОС для синхронизации доступа к объекту "Соединение".
Работа с объектами "Подписчик" и "Публикатор" в каждый момент времени должна вестись только из одного потока, аналогично объекту "Соединение"
Объект "Подписчик" привязан к конкретному соединению(тому, которое было задано при их создании) и работа с ним должна вестись из того же потока, из которого ведется работа с соединением. Объект "Публикатор" также привязан к конкретному соединению(тому, которое было задано при их создании), но работа с ним допускается из другого потока.
Объект "Соединение" обеспечивает взаимодействие с рутером Plaza-2 для отправки и получения сообщений. Эти объекты могут создаваться в произвольном количестве в любое время работы ПО при инициализированном окружении; тем не менее, рекомендуется создавать соединения при старте ПО, а уничтожать - непосредственно перед выходом.
Создание соединения выполняется вызовом:
CG_RESULTcg_conn_new( | settings, | |
connptr) ; |
const char* settings
;cg_conn_t** connptr
;Параметрами являются строка инициализации соединения и указатель, в
который будет занесен указатель на созданное соединение. Строка создания
соединения задаётся в формате URL следующего вида:
"TYPE://HOST:PORT;param1=value1;param2=value;...;paramN=valueN"
,
где
Тип соединения. В настоящее время поддерживаются два вида соединений:
Соединение с рутером Plaza-2 посредством протокола TCP/IP. Медленнее, удобно для отладки, может связываться с рутером, установленным на другой машине
Соединение с рутером Plaza-2 посредством разделяемой памяти. Быстрее, оптимально для production, работает исключительно в рамках одной машины.
Специальное соединение для управление роутером.
Примечание: В случае p2lrpcq соединение должно всегда закрываться корректно, т.к. в противном случае в роутере соединение не деинициализируется, поэтому повторное соединение к роутеру под этим же именем будет не возможно без перезапуска роутера.
Адрес, с которым устанавливается соединение. В случае типа соединения p2tcp - это адрес машины, на которой запущен интересующий процесс P2MQRouter, в случае p2lrpcq - 127.0.0.1.
Номер порта, по которому производится соединение. Должен быть указан как для p2tcp, так и для p2lrpcq; в последнем случае порт будет использован в качестве управляющего канала для установки соединения через разделяемую память.
Параметры допустимые при задании соединений p2tcp и p2lrpcq:
Имя приложения Plaza-2. В пределах одного рутера Plaza-2 каждое соединение с ним должно обладать уникальным именем. Этот идентификатор используется для маршрутизации сообщений в соответствующие обработчики.
Пароль для соединения с рутером Plaza-2, если рутер сконфигурирован на проверку открываемых соединений паролем.
Время в миллисекундах, в течение которого ожидается установка соединения с рутером в процессе вызова conn_open(...). В случае превышения времени ожидания соединения вызов conn_open(...) вернёт ошибку.
Время в миллисекундах, в течение которого ожидается ответ от рутера Plaza-2 при использовании соединения p2lrpcq.
имя объекта в cgate;
Пароль для подключения к удалённому роутеру.
Размер буфера lrpcq в байтах.
Пример вызова функции:
const char* conn_str = "p2lrpcq://127.0.0.1:4001;app_name=myapp"; cg_conn_t* conn; result = cg_conn_new(conn_str, *conn); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to initialize connection: 0x%X\n", result); return; }
Примеры строки соединения:
p2lrpcq://127.0.0.1:4001;appName=example;timeout=2000;local_timeout=500;lrpcq_buf=0;name=p2lrpcq_example; p2tcp://192.168.1.1:4003;appName=example2;timeout=2000;local_pass=123;name=p2tcp_example; p2sys://127.0.0.1:4001;appName=example3;timeout=2000;name=p2sys_example;
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Предпринята попытка открыть соединение в то время, когда оно не может быть открыто, т.к. либо уже активно, либо находится в состоянии ошибки
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Возврат функцией значения CG_ERR_OK не означает, что соединение было успешно открыто - об этом факте можно судить только по изменению статуса соединения (cg_conn_getstate). Успешное исполнение данной функции означает, что процесс открытия соединения был начат успешно и через некоторое время соединение может перейти в состояние CG_STATE_ACTIVE в случае успеха или в состояние CG_STATE_ERROR в случае неудачи открытия соединения.
Открытие соединения выполняется вызовом:
CG_RESULT cg_conn_open( | conn, | |
settings) ; |
cg_conn_t* conn
;const char* settings
;Параметрами являются указатель на объект соединения и строка открытия соединения. Строка открытия соединения в настоящее время не используется и должна быть либо пустой, либо NULL.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Предпринята попытка открыть соединение в то время, когда оно не может быть открыто, т.к. либо уже активно, либо находится в состоянии ошибки
Возвращается при невозможности проверки пользовательского ключа, при этом в лог выводится сообщение "Certificate check failed".
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Возврат функцией значения CG_ERR_OK не означает, что соединение было успешно открыто - об этом факте можно судить только по изменению статуса соединения (cg_conn_getstate). Успешное исполнение данной функции означает, что процесс открытия соединения был начат успешно и через некоторое время соединение может перейти в состояние CG_STATE_ACTIVE в случае успеха или в состояние CG_STATE_ERROR в случае неудачи открытия соединения.
Пример вызова функции:
cg_conn_t* conn; // указатель на инициализированный вызовом conn_new объект result = cg_conn_open(conn, NULL); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to open connection: 0x%X\n", result); // Надо предпринять попытку повторного открытия соединения }
Закрытие соединения выполняется вызовом:
CG_RESULT cg_conn_close( | conn) ; |
cg_conn_t* conn
;Параметром является указатель на объект соединения.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Предпринята попытка закрыть соединение в то время, когда оно закрыто.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
После закрытия соединения, оно может быть повторно открыто вызовом cg_conn_open.
Пример вызова функции:
cg_conn_t* conn; // указатель на инициализированный вызовом conn_new объект result = cg_conn_close(conn); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to close connection: 0x%X\n", result); return; }
Уничтожение соединения выполняется вызовом:
CG_RESULT cg_conn_destroy( | conn) ; |
cg_conn_t* conn
;Параметром является указатель на объект соединения.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Предпринята попытка уничтожить соединение в то время, когда оно не было корректно закрыто.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Данный вызов уничтожает объект, на который указывает параметр conn и освобождает все связанные с ним ресурсы. После вызова этой функции объект больше не может быть использован. Эта функция должна быть вызвана для каждого объекта, созданного вызовом cg_conn_new, вне зависимости от того, выполнялась работа (открытие, получение данных, отправка сообщений) с данным объектом или нет. При вызове cg_conn_destroy для активного conn внутри cgate происходит закрытие соединения, а потом его разрушение.
Пример вызова функции:
cg_conn_t* conn; // указатель на объект, который был закрыт вызовом conn_close result = cg_conn_destroy(conn); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to destroy connection: 0x%X\n", result); return; }
Обработка сообщений соединения выполняется вызовом:
CG_RESULT cg_conn_process( | conn, | |
timeout, | ||
reserved) ; |
cg_conn_t* conn
;uint32_t timeout
;void* reserved
;Параметрами является указатель на объект соединения и время ожидания событий. Последний параметр reserved в настоящее время не используется и должен быть равен NULL.
Возвращаемые значения:
Успешное выполнение.
За указанное время не было обработано ни одного события системы
Функции были переданы некорректные аргументы.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Данный вызов осуществляет итерацию работы с соединением, которая включает в себя опрос очереди входящих сообщений, анализ пришедших данных, вызов пользовательских функций обратного вызова. Эта функция должна вызываться из кода пользователя с частотой, соответствующей максимальной желаемой частоте получения данных.
Пользовательские функции обратного вызова для подписчиков, привязанных к данному соединению будут вызваны в процессе работы этой функции из того же потока исполнения.
В случае, если значения параметра timeout отличается от 0, вызов будет заблокирован на timeout миллисекунд в ожидании событий. Если в момент вызова функции очередь входящих сообщений не пуста, функция не будет ничего ожидать и сразу же перейдёт к обработке входящих сообщений. Если функцию не вызывать более 3 минут, возникает timeout подписчика, а потом timeout соединения, после чего соединения и подписчики закрываются.
Пример вызова функции:
cg_conn_t* conn; // указатель на соединение в активном состоянии // разбираем входящие сообщения в цикле, но не более 100 за итерацию for (int callidx = 0; callidx < 100; ++ callidx) { result = cg_conn_process(conn, 0, NULL); if (result == CG_ERR_TIMEOUT) // сообщений нет break; // перейти к дальнейшей логике работы ПО else if (result != CG_ERR_OK) { // попытка обработки соединения завершилась ошибкой // вывести сообщение и закрыть соединение fprintf(stderr, "Failed to process connection: 0x%X\n", result); result = cg_conn_close(conn); // if (result != CG_ERR_OK) { // закрытие соединения провалилось, выйти из программы fprintf(stderr, "Failed to close connection: 0x%X\n", result); return; } break; } }
Объект "Подписчик" обеспечивает получение сообщений через указанное соединение. Правила, по которым получаются сообщения зависят от типа подписчика - это могут быть как сообщения peer-to-peer, так и сообщения publish-subscribe, такие как реплика.
Работами с объектами "Подписчик" в API производятся посредством указателя cg_listener_t*.
Создание подписчика выполняется вызовом:
CG_RESULT cg_lsn_new( | conn, | |
settings, | ||
callback, | ||
data, | ||
lsnptr) ; |
cg_conn_t* conn
;const char* settings
;CG_LISTENER_CB callback
;void* data
;cg_listener_t** lsnptr
;Параметрами являются: указатель на инициализированный объект
соединения, в котором создаётся подписчик, строка инициализации
подписчика, указатель на функцию обратного вызова, которая будет
вызываться при возникновении событий, произвольный указатель, который
будет передаваться в функцию обратного вызова и указатель, в который будет
занесен указатель на созданный подписчик. Строка создания соединения
задаётся в формате URL следующего вида:
"TYPE://[STREAM][;param1=value1[;param2=value[;...[;paramN=valueN]]]]"
,
где
Тип подписки. Поддерживаются следующие типы подписки:
Получение табличного потока репликации Plaza-2
Получение ответов на ранее отправленные сообщения
Получение активных заявок с использованием срезов стаканов для начальной синхронизации, а затем переход на он-лайн поток
Получение статуса: соединения, роутера, авторизации.
Остальные параметры зависят от типа подписки.
Параметры, поддерживаемые типом подписки p2repl:
Задаёт имя потока табличной репликации.
Путь к используемой схемы данных потока. См. Схемы данных.
Список требуемых таблиц из серверной схемы, разделенных запятой. Не допускается одновременное задание параметров "tables" и "scheme"
Параметры, поддерживаемые типом подписки p2ordbook:
Задаёт имя он-лайн потока с журналом действий над заявками (FORTS_FUTTRADE_REPL или FORTS_OPTTRADE_REPL)
Имя потока со срезами активных заявок (FORTS_FUTORDERBOOK_REPL или FORTS_OPTORDERBOOK_REPL).
Путь к используемой схемы данных он-лайн потока. Схема должна содержать таблицу orders_log.
Путь к используемой схемы данных снапшот потока. Схема должна содержать таблицы orders и info.
Имя таблицы с заявками для online потока. Значение по умолчанию "orders_log".
Имя таблицы с заявками для snapshot потока. Значение по умолчанию "orders".
Имя таблицы и поля с ревизией, по которому осуществляется сшивка потоков. Значение по умолчанию "info.logRev".
Параметры, поддерживаемые типом подписки p2mqreply:
Содержит имя публикатора, который был использован для отправки сообщений, ответы на которые требуется получать в данном подписчике. На момент создания подписчика p2mqreply должен существовать и связанный с ним по ref публикатор.
Подписчик "p2mqreply" использует в качестве схемы данных схему, заданную в связанном публикаторе. Именна эта схема данных будет возвращена вызовом cg_lsn_getscheme.
Подписчик "p2ordbook" использует в качестве схемы объединенную схему срезов и он-лайн потоков. При этом данные в момент прихода среза будут соответствовать сообщениям из схемы со срезами данных, а после перехода в онлайн будут приходить сообщения из он-лайн схемы. При использовании статических структур данных для работы с сообщениями данного потока, нужно иметь описания структур как для срезов, так и для он-лайн данных, причём следует обращать внимания на индексы соответствующих таблиц. При использовании динамического подхода к работе со схемами, следует применять стандартные практики - запомнить номера интересующих сообщений и полей и использовать их во время прихода данных.
Параметр callback функции указывает на пользовательскую функцию обратного вызова, которая имеет следующий вид:
CG_RESULT callback(cg_conn_t* conn, cg_listener_t* listener, struct cg_msg_t* msg, void* data);
Эта функция вызывается в момент возникновения какого либо события по данной подписке: открытие подписки, закрытие, приход сообщения и т.п. В качестве параметров функция обратного вызова получает указатель на соединение, в котором создана подписка, указатель на объект подписки, в котором возникло событие, указатель на сообщение и пользовательский указатель data, который был передан в вызов cg_lsn_new. Код возврата пользовательского обработчика должен быть установлен в 0 в случае успеха обработки сообщения или в другое значение в случае ошибки. В случае возврата ошибки из callback подписчик будет закрыт, и в callback придут последовательно сообщения: replstate - с состоянием подписчика на последний CG_MSG_TN_COMMIT, CG_MSG_CLOSE.
Вызов функции cg_lsn_new выполняет только инициализацию объекта подписки, но не приводит к фактическому началу получения данных; для начала получения данных необходимо перевести подписку в активное состояние вызовом cg_lsn_open.
В пользовательский callback могут приходить следующие сообщения:
Тип подписчика | Тип сообщения | Описание |
---|---|---|
p2repl, p2mqreply, p2sys | CG_MSG_OPEN | Сообщение приходит в момент активации потока данных. Это событие гарантированно возникает до прихода каких либо данных по данной подписке. Для потоков репликации приход сообщения означает, что схема данных согласована и готова для использования (Подробнее см. Схемы данных) Данное сообщение не содержит дополнительных данных и его поля data и data_size не используются. |
p2repl, p2mqreply, p2sys | CG_MSG_CLOSE | Сообщение приходит в момент закрытия потока данных.
Приход сообщения означает, что поток был закрыт пользователем
или системой. В поле data содержится указатель на int, по
указанному адресу хранится информация о причине закрытия
подписчика. Возможны следующие причины:
|
p2repl | CG_MSG_TN_BEGIN | Означает момент начала получения очередного блока данных. В паре со следующим сообщением может быть использовано логикой ПО для контроля целостности данных. Данное сообщение не содержит дополнительных данных и его поля data и data_size не используются. |
p2repl | CG_MSG_TN_COMMIT | Означает момент завершения получения очередного блока данных. К моменту прихода этого сообщения можно считать, что данные полученные по данной подписке, находятся в непротиворечивом состоянии и отражают таблицы в синхронизированном между собой состоянии. Данное сообщение не содержит дополнительных данных и его поля data и data_size не используются. |
p2repl | CG_MSG_STREAM_DATA | Сообщение прихода потоковых данных. Поле data_size содержит размер полученных данных, data указывает на сами данные. Само сообщение содержит дополнительные поля, которые описываются структурой rtscg_msg_streamdata_t. Подробнее о получении данных см. раздел Получение потоков репликации |
p2repl | CG_MSG_P2REPL_ONLINE | Переход потока в состояние online - это означает, что получение начального среза было завершено и следующие сообщения CG_MSG_P2REPL_DATA будут нести данные он-лайн. Данное сообщение не содержит дополнительных данных и его поля data и data_size не используются. |
p2repl | CG_MSG_P2REPL_LIFENUM | Изменен номер жизни схемы. Такое сообщение означает, что предыдущие данные, полученные по потоку, не актуальны и должны быть очищены. При этом произойдёт повторная трансляция данных по новому номеру жизни схемы данных. Поле data сообщения указывает на целочисленное значение, содержащее новый номер жизни схемы; поле data_size содержит размер целочисленного типа. |
p2repl | CG_MSG_P2REPL_CLEARDELETED | Произошла операция массового удаления устаревших данных. Поле data сообщения указывает на структуру cg_data_cleardeleted_t, в которой указан номер таблицы и номер ревизии, до которой данные в указанной таблице считаются удаленными. |
p2repl | CG_MSG_P2REPL_REPLSTATE | Сообщение содержит состояние потока данных; присылается перед закрытием потока. Поле data сообщения указывает на строку, которая в закодированном виде содержит состояние потока данных на момент прихода сообщения - сохраняются схема данных, номера ревизий таблиц и номер жизни схемы. Эта строка может быть передана в вызов cg_lsn_open в качестве параметра "replstate" по этому же потоку в следующий раз, что обеспечит продолжение получения данных с момента остановки потока. |
p2mqreply, p2sys | CG_MSG_DATA | Сообщение содержит ответ на ранее отосланное состояние. Поле data указывает на данные, а поле data_size содержит размер блока данных. Сообщение описывается структурой cg_msg_data_t и содержит дополнительные поля, позволяющие идентифицировать исходное сообщение, а также информацию о схеме данных. Подробнее см. раздел Отправка команд и получение ответов. |
p2mqreply | CG_MSG_P2MQ_TIMEOUT | Сообщение приходит в том случае, если ответ на отправленное ранее сообщение не был получен в течение указанного в соответствующем publisher времени. Сообщение описывается структурой cg_msg_data_t и содержит значение user_id, задаваемое при отправке исходного сообщения. |
Примеры url:
p2sys://;name=p2sys_lsn
p2repl://FORTS_FUTINFO_REPL;name=repl_sample1;format=p2binfmt
p2repl://FORTS_ORDLOG_REPL;scheme=|FILE|./ini/ordlog_repl.ini|scheme;name=repl_sample2
p2ordbook://FORTS_ORDLOG_REPL;snapshot=FORTS_ORDBOOK_REPL;name=ordbook_sample1
p2ordbook://FORTS_FUTTRADE_REPL;snapshot=FORTS_FUTORDERBOOK_REPL;scheme=|FILE|ini/futtrade.ini|FutTrade;name=ordbook_sample2
p2ordbook://FORTS_FUTTRADE_REPL;snapshot=FORTS_FUTORDERBOOK_REPL;scheme=|FILE|ini/futtrade.ini|FutTrade;snapshot.scheme=|FILE|ini/orderbook.ini|CustReplScheme;name=ordbook_sample3
p2mqreply://;ref=pub_name;name=mqreply_sample
Пример создания подписчика на получение потока репликации:
cg_conn_t* conn; // указатель на инициализированный объект "Соединение" const char* lsn_str = "p2repl://FORTS_FUTINFO_REPL"; cg_listener_t* lsn; result = cg_lsn_new(conn, lsn_str, callback, 0, *lsn); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to initialize listener: 0x%X\n", result); return; }
Пример создания подписчика на получение ответов на отправленные команды:
cg_conn_t* conn; // указатель на инициализированный объект "Соединение" // строка инициализации публикатора отправки команд // указан параметр name=TN1 const char* pub_str = "p2mq://FORTS_SRV;category=FORTS_MSG;name=TN1"; cg_publisher_t* pub; // строка инициализации подписчика получения ответов // указан параметр ref=TN1, который обеспечивает связь с публикатором const char* lsn_str = "p2mqreply://;ref=TN1"; cg_listener_t* lsn; result = cg_lsn_new(conn, lsn_str, callback, 0, *lsn); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to initialize listener: 0x%X\n", result); return; }
Открытие подписки выполняется вызовом:
CG_RESULT cg_lsn_open( | lsn, | |
settings) ; |
cg_listener_t* lsn
;const char* settings
;Параметрами являются указатель на объект подписки и строка открытия подписки. Строка параметров открытия задаётся в формате "param1=value1;param2=value2;....;paramN=valueN", причем названия и значения параметров зависят от типа подписки.
Параметры открытия подписки p2repl:
Определяет режим получения данных и может принимать следующие значения:
Поток открывается в режиме получения среза данных. При этом данные в режиме он-лайн транслироваться не будут
Поток открывается в режиме получения онлайн-данных. Срез данных получен не будет, данные будут идти с момента открытия потока
Поток открывается в режиме получения снапшота, а затем перехода в режим получения он-лайн.
Задаёт состояние потока, с которого следует произвести открытие. Значение этого параметра должно соответствовать строке, полученной в сообщении CG_MSG_P2REPL_REPLSTATE в момент предыдущего закрытия потока.
Задаёт номер жизни схемы. Данный параметр может быть использован для подключения к потоку данных, если по каким либо причинам возможности, предоставляемые параметром "replstate" не подходят. Если задан параметр "replstate", то значение данного параметра будет проигнорировано.
Задаёт начальную ревизию таблицы TABLE_NAME. Вместо TABLE_NAME следует подставить имя интересующей таблицы. Данный параметр может быть использован для подключения к потоку данных, если по каким либо причинам возможности, предоставляемые параметром "replstate" не подходят. Если задан параметр "replstate", то значение данного параметра будет проигнорировано. Возможно указание этого параметра несколько раз для разных таблиц в потоке, например "rev.orders_log=234445;rev.deal=55". Запрещено задавать ревизию таблицы TABLE_NAME без указания lifenum=%d (ревизия без номера жизни не имеет смысла).
Параметры "replstate" и ("lifenum" + "rev.TABLE_NAME") являются взаимоисключающими. Также запрещено одновременно задавать значения параметров "replstate" и "rev.TABLE_NAME". Таким образом, возможны только следующие комбинации параметров:
replstate
lifenum
lifenum + rev.TABLE_NAME
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Предпринята попытка открыть подписку в то время, когда она не может быть открыта, т.к. либо уже активна, либо находится в состоянии ошибки.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Возврат функцией значения CG_ERR_OK не означает, что подписка была успешно открыта - об этом факте можно судить только по изменению статуса подписки (cg_lsn_getstate). Успешное исполнение данной функции означает, что процесс открытия подписки был начат успешно и через некоторое время подписка может перейти в состояние CG_STATE_ACTIVE в случае успеха или в состояние CG_STATE_ERROR в случае неудачи открытия.
Пример вызова функции:
cg_listener_t* lsn; // указатель на инициализированный вызовом cg_lsn_new объект const char* lsn_open_str = "mode=online"; result = cg_lsn_open(lsn, lsn_open_str); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to open listener: 0x%X\n", result); // Надо предпринять попытку повторного открытия подписчика }
Закрытие подписки выполняется вызовом:
CG_RESULT cg_lsn_close( | lsn) ; |
cg_listener_t* lsn
;Параметром является указатель на объект подписчика.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Предпринята попытка закрыть подписчика в то время, когда окружение было некорректно инициализировано.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
После закрытия подписчика, он может быть повторно открыт вызовом cg_lsn_open.
Пример вызова функции:
cg_listener_t* lsn; // указатель на открытую подиску result = cg_lsn_close(lsn); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to close listener: 0x%X\n", result); return; }
Уничтожение подписчика выполняется вызовом:
CG_RESULT cg_lsn_destroy( | lsn) ; |
cg_listener_t* lsn
;Параметром является указатель на объект подписки.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Предпринята попытка уничтожить подписчика в то время, когда когда окружение было некорректно инициализировано.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Данный вызов уничтожает объект, на который указывает параметр lsn и освобождает все связанные с ним ресурсы. После вызова этой функции объект больше не может быть использован. Эта функция должна быть вызвана для каждого объекта, созданного вызовом cg_lsn_new, вне зависимости от того, выполнялась работа (открытие, получение данных, отправка сообщений) с данным объектом или нет.
При разрушении активного подписчика cgate закрывает подписчика, после чего производит его разрушение.
Пример вызова функции:
cg_listener_t* lsn; // указатель на объект, который был закрыт вызовом cg_lsn_close result = cg_lsn_destroy(lsn); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to destroy listener: 0x%X\n", result); return; }
Получение статуса подписчика выполняется вызовом:
CG_RESULT cg_lsn_getstate( | lsn, | |
state) ; |
cg_listener_t* lsn
;uint32_t* state
;Параметрами является указатель на объект подписки и указатель на значение размером 4 байта, куда будет записан текущий статус подписчика.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Данный вызов должен быть использован для периодического получения статуса подписчика, для того, чтобы можно было выполнить действия, связанные с переходом объекта подписки в разные состояния - например, выполнить закрытие подписки, если она перешла в состояние ошибки. Более подробно статуса объектов описаны в разделе Жизненный цикл объектов.
Пример вызова функции:
cg_listener_t* lsn; // указатель на объект подписки uint32_t state; // Сюда будет записан статус result = cg_lsn_getstate(lsn, &state); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to query listener state: 0x%X\n", result); return; } switch (state) { case CG_STATE_ERROR: /* ... */ case CG_STATE_CLOSED: /* ... */ }
Получение схемы подписчика выполняется вызовом:
CG_RESULT cg_lsn_getscheme( | lsn, | |
schemeptr) ; |
cg_listener_t* lsn
;cg_scheme_desc_t**
schemeptr
;Параметрами является указатель на объект подписки и указатель на переменную, в которую будет записан указатель на описание схемы.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Вызов используется для получения схемы данных объекта подписки (подробнее см. раздел Работа со схемами данных). Схема данных доступна для получения с момента прихода события OPEN для подписки. В случае, если при создании подписки схема данных не была явно задана, между двумя сессиями работы с подпиской схема может измениться, т.е. в общем случае нельзя рассчитывать на то, что в цепочке вызовов open/close, open/close схема после первого open будет аналогична схеме после вызова второго open. Это может решаться либо указанием клиентской схемы данных, в тех случаях, когда это поддерживается типом подписки, либо анализом схемы каждый раз в момент прихода события OPEN.
Пример вызова функции:
cg_listener_t* lsn; // указатель на объект подписки cg_scheme_desc_t* schemedesc; // Сюда будет записан указатель на описание схемы result = cg_lsn_getscheme(lsn, &schemedesc); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to query listener scheme: 0x%X\n", result); return; } // напечатать кол-во сообщений в схеме printf("Number of messages: %d\n", schemedesc->num_messages);
Объект "Публикатор" обеспечивает отправку сообщений через указанное соединение. Правила, по которым отправляются сообщения зависят от типа публикатора и соединения.
Работами с объектами "Публикатор" в API производятся посредством указателя cg_publisher_t*.
Создание подписчика выполняется вызовом:
CG_RESULTcg_pub_new( | conn, | |
settings, | ||
pubptr) ; |
cg_conn_t* conn
;const char* settings
;cg_publisher_t** pubptr
;Параметрами являются: указатель на инициализированный объект
соединения, в котором создаётся публикатор, строка инициализации
публикатора и указатель, в который будет занесен указатель на созданный
подписчик. Строка создания соединения задаётся в формате URL следующего
вида:
"TYPE://[NAME][;param1=value1[;param2=value[;...[;paramN=valueN]]]]"
,
где
Тип публикатора. Поддерживаются следующие типы:
Отправка произвольных сообщений Plaza-2
Определяет уникальное имя публикатора. Может быть использован для связи между парными публикаторами и подписчиками (например, публикатора mq и подписчика mqreply).
Остальные параметры зависят от типа подписки.
Параметры, поддерживаемые типом публикатора p2mq:
Задаёт имя сервиса, на который будут отправляться сообщения через данный публикатор.
Путь к используемой схемы данных. См. Схемы данных. Используемая схема данных должна содержать описания запросов и ответов - связанный подписчк p2mqreply будет использовать эту схему данных при разборе сообщений.
Категория отправляемых сообщений. Для отправки команд в торговую систему FORTS данный параметр должен быть зафиксирован как "FORTS_MSG"
Время ожидания ответа на отправленное сообщение в миллисекундах.
.
Вызов функции cg_pub_new выполняет только инициализацию объекта публикатора, но не приводит к фактическому разрешению отправки сообщений; для начала отправки сообщений необходимо перевести публикатор в активное состояние вызовом cg_pub_open.
Пример создания подписчика на отправку данных в торговую систему:
cg_conn_t* conn; // указатель на инициализированный объект "Соединение" const char* pub_str = "p2mq://FORTS_SRV;category=FORTS_MSG;name=TN1"; cg_publusher_t* pub; result = cg_pub_new(conn, pub_str, *pub); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to initialize publisher: 0x%X\n", result); return; }
Пример того, как можно получить ответы на отправленные через публикатор команды, можно найти в разделе описания функции cg_lsn_new.
Открытие публикатора выполняется вызовом:
CG_RESULT cg_pub_open( | pub, | |
settings) ; |
cg_publisher_t* pub
;const char* settings
;Параметрами являются указатель на объект публикатора и строка открытия. В настоящий момент публикаторы не требуют задания строки параметров и этот параметр должен быть NULL или пустой строкой.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Предпринята попытка открыть публикатор в то время, когда он не может быть открыт, т.к. либо уже активен, либо находится в состоянии ошибки
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Возврат функцией значения CG_ERR_OK не означает, что публикатор была успешно открыт - об этом факте можно судить только по изменению статуса публикатора (cg_pub_getstate). Успешное исполнение данной функции означает, что процесс открытия публикатора был начат успешно и через некоторое время подписка может перейти в состояние CG_STATE_ACTIVE в случае успеха или в состояние CG_STATE_ERROR в случае неудачи открытия.
Пример вызова функции:
cg_publisher_t* pub; // указатель на инициализированный вызовом cg_pub_new объект result = cg_pub_open(pub, 0); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to open publisher: 0x%X\n", result); // Надо предпринять попытку повторного открытия публикатора }
Закрытие публикатора выполняется вызовом:
CG_RESULT cg_pub_close( | pub) ; |
cg_publisher_t* pub
;Параметром является указатель на объект публикатора.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Предпринята попытка закрыть публикатор в то время когда окружение некорректно инициализировано.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
После закрытия подписчика, он может быть повторно открыт вызовом cg_pub_open.
Пример вызова функции:
cg_publisher_t* pub; // указатель на открытый публикатора result = cg_pub_close(pub); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to close publisher: 0x%X\n", result); return; }
Уничтожение публикатора выполняется вызовом:
CG_RESULT cg_pub_destroy( | pub) ; |
cg_publisher_t* pub
;Параметром является указатель на объект публикатор.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Предпринята попытка уничтожить публикатор в то время, когда окружение не было корректно инициализировано.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Данный вызов уничтожает объект, на который указывает параметр pub и освобождает все связанные с ним ресурсы. После вызова этой функции объект больше не может быть использован. Эта функция должна быть вызвана для каждого объекта, созданного вызовом cg_pub_new, вне зависимости от того, выполнялась работа (открытие, отправка сообщений) с данным объектом или нет.
При вызове cg_pub_destroy для активного публикатора, сперва происходит закрытие публикатора, а потом его разрушение.
Примеры:
p2sys://;name=p2sys_pub p2mq://FORTS_SRV;category=FORTS_MSG;name=srvlink;timeout=5000;scheme=|FILE|forts_messages.ini|message
Пример вызова функции:
cg_publisher_t* pub; // указатель на объект, который был закрыт вызовом cg_pub_close result = cg_pub_destroy(pub); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to destroy publisher: 0x%X\n", result); return; }
Получение статуса публикатора выполняется вызовом:
CG_RESULT cg_lsn_getstate( | lsn, | |
state) ; |
cg_listener_t* lsn
;uint32_t* state
;Параметрами является указатель на объект публикатора и указатель на значение размером 4 байта, куда будет записан текущий статус публикатора.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Данный вызов должен быть использован для периодического получения статуса публикатора, для того, чтобы можно было выполнить действия, связанные с переходом объекта подписки в разные состояния - например, выполнить закрытие публикатора, если он перешла в состояние ошибки. Более подробно статусы объектов описаны в разделе Жизненный цикл объектов.
Эта функция доступна для вызова в любое время между вызовами cg_pub_new и cg_pub_destroy.
Пример вызова функции:
cg_publisher_t* pub; // указатель на объект публикатор uint32_t state; // Сюда будет записан статус result = cg_pub_getstate(pub, &state); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to query publisher state: 0x%X\n", result); return; } switch (state) { case CG_STATE_ERROR: /* ... */ case CG_STATE_CLOSED: /* ... */ }
Получение схемы публикатора выполняется вызовом:
CG_RESULT cg_pub_getscheme( | pub, | |
schemeptr) ; |
cg_publisher_t* pub
;cg_scheme_desc_t**
schemeptr
;Параметрами является указатель на объект пубщикатора и указатель на переменную, в которую будет записан указатель на описание схемы.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Вызов используется для получения схемы данных объекта подписки (подробнее см. раздел Работа со схемами данных). Схема данных доступна с момента перехода публикатора в состояние ACTIVE. В случае, если при создании публикатора схема данных не была явно задана, между двумя сессиями работы с подпиской схема может измениться, т.е. в общем случае нельзя рассчитывать на то, что в цепочке вызовов open/close, open/close схема после первого open будет аналогична схеме после вызова второго open. Это может решаться либо указанием клиентской схемы данных, в тех случаях, когда это поддерживается типом подписки, либо анализом схемы каждый раз в момент прихода события OPEN.
Пример вызова функции:
cg_publisher_t* pub; // указатель на объект публикатор cg_scheme_desc_t* schemedesc; // Сюда будет записан указатель на описание схемы result = cg_pub_getscheme(pub, &schemedesc); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to query publisher scheme: 0x%X\n", result); return; } // напечатать кол-во сообщений в схеме printf("Number of messages: %d\n", schemedesc->num_messages);
Создание нового сообщения для отправки выполняется вызовом:
CG_RESULT cg_pub_msgnew( | pub, | |
id_type, | ||
id, | ||
msgptr) ; |
cg_publisher_t* pub
;uint32_t id_type
;const void* id
;struct cg_msg_t** msgptr
;Параметрами является указатель на объект публикатора, тип ключа сообщения, указатель на значения ключа сообщения и указатель на переменную, в которую будет записан указатель на созданное сообщение.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Данный вызов инициализирует сообщение для отправки через данный публикатор. Желаемое сообщение идентифицируется типом и значением ключа в схеме данных публикатора. Поддерживаются следующие виды ключей:
Ключом является номер сообщения в схеме. Параметр id указывает на значение типа uint32_t, в котором хранится желаемый номер сообщения
Ключом является уникальный числовой идентификатор сообщения в схеме. Параметр id указывает на значение типа uint32_t, в котором хранится желаемый идентификатор сообщения
Ключом является имя сообщения в схеме. Параметр id указывает на строку, в которой записано имя желаемого сообщения. Строка должна завершаться нулём.
Сообщение, создаваемое данной функцией, является сообщением типа CG_MSG_DATA и описывается расширенной структурой:
struct cg_msg_data_t { // Тип сообщения. Всегда CG_MSG_DATA для данного сообщения uint32_t type; // Размер данных size_t data_size; // Указатель на данные void* data; // Номер описания сообщения в активной схеме size_t msg_index; // Уникальный идентификатор типа сообщения uint32_t msg_id; // Имя сообщения в активной схеме const char* msg_name; // Пользовательский номер сообщения uint32_t user_id; // Адрес противоположной стороны const char* addr; // Указатель на связанное сообщение struct cg_msg_data_t* ref_msg; };
Поле data_size содержит размер выделенного блока памяти для запрошенного формата сообщения, а поле data указывает на этот блок памяти. Поля msg_index, msg_id и msg_name заполнены данными в соответствие с используемой схемой данных. Поле user_id может быть использовано для задания пользовательского номера сообщения - этот же user_id будет указан в ответном сообщении, что позволяет связать запрос и ответ.
Пользовательский код должен сверить размер блока в поле data_size, выделенного для сообщения со своими ожиданиями относительно размера этого блока с целью избежать ошибок с заполнением сообщения. Затем следует заполнить блок по указателю data данными. После этого сообщение готово к отправке.
Пример вызова функции:
cg_publisher_t* pub; // указатель на объект публикатор cg_msg_data* msg; result = cg_pub_msgnew(pub, CG_KEY_NAME, "FutDelOrder", &msg); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to allocate message: 0x%X\n", result); } else { FutDelOrder* delord; if (msg->data_size != sizeof(*delord)) { fprintf(stderr, "Block sizes do not match: %d expected, but got %d \n", sizeof(*delord), msg->data_size); } else { delord = (FutDelOrder*)msg->data; delord->order_id = ...; // номер удаляемой заявки result = cg_pub_post(pub, msg, CG_PUB_NEEDREPLY); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to post message: 0x%X\n", result); } } }
Отправка сообщения выполняется вызовом:
CG_RESULT cg_pub_post( | pub, | |
msg, | ||
flags) ; |
cg_publisher_t* pub
;struct cg_msg_t* msg
;uint32_t flags
;Параметрами является указатель на объект публикатора, указатель на сообщение и флаги отправки сообщения.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Предпринята попытка отправить сообщение в то время, как соединение не активно.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Вызов предпринимает попытку отправки сообщения. Сообщение для отправки должно быть предварительно инициализировано вызовом cg_pub_msgnew и заполнено данными пользователя. В качестве флагов можно указывать значение CG_PUB_NEEDREPLY, что информирует систему о необходимости ожидания ответа на отправленное сообщение.
Ответные сообщения могут быть получены с помощью подписки типа p2mqreply, подробнее см. описание функции cg_lsn_new.
Пример вызова функции:
cg_publisher_t* pub; // указатель на объект публикатор cg_msg_data* msg; // указатель на инициализированное сообщение result = cg_pub_post(pub, msg, CG_PUB_NEEDREPLY); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to post message: 0x%X\n", result); } cg_pub_msgfree(pub, msg);
Освобождение сообщения выполняется вызовом:
CG_RESULT cg_pub_msgfree( | pub, | |
msg) ; |
cg_publisher_t* pub
;struct cg_msg_t* msg
;Параметрами является указатель на объект публикатора и указатель на сообщение, которое требуется освободить.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Внутренняя ошибка. Может свидетельствовать о нарушении конфигурации или среды исполнения. Для более подробной диагностики следует обратиться к анализу журналов библиотеки.
Вызов уничтожает ранее выделенное сообщение. После вызова данной функции сообщение, на которое указывает параметр msg становится недоступным для дальнейшего использования и все ресурсы, связанные с ним, освобождаются. Функция должна быть вызвана для любого сообщения, созданного функций cg_pub_msgnew после того, как сообщение было отправлено и работа с ним завершена.
Пример вызова функции:
cg_publisher_t* pub; // указатель на объект публикатор cg_msg_data* msg; // указатель на инициализированное сообщение result = cg_pub_msgfree(pub, msg); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to post message: 0x%X\n", result); }
Для аутентификации пользователя в системе Plaza-II в Cgate предусмотрен специальный протокол соединения p2sys. Данный протокол содержит в себе три объекта: соединение, подписчик и публикатор. Рассмотрим подробнее каждый из них.
Соединение p2sys является особым видом соединения к роутеру Plaza-II, предназначеным только для отправки аутентификационных запросов и получения ответов на них. Соединение может быть создано и установлено следующим образом:
cg_conn_t* conn; result = cg_conn_new("p2sys://127.0.0.1:4001;app_name=test_p2sys", &conn); result = cg_conn_open(conn, 0);
Закрытие соединения происходит стандартным способом:
conn_close(conn);
Подписчик p2sys отвечает за статус соединения с роутером Plaza-II и оповещает пользователя о его изменении. Каждому статусу соответствует сообщение типа CG_MSG_DATA с уникальным msgid.
Статусы соединения с роутером делятся на 2 категории:
статус соединения: показывает состояние соединения клиента с роутером. Если соединение установлено, подписчик получает статус ConnectionConnected (msgid = 3), иначе - ConnectionDisconnected (msgid = 4);
статус роутера: признак аутентификации пользователя в системе. Сначала подписчик получает статус RouterDisconnected (msgid = 2). Если клиент отправил правильные данные аутентификации, подписчик получает статус RouterConnected (msgid = 1), иначе - LogonFailed (msgid = 5). Если в ini-файле роутера указаны правильные имя пользователя и пароль, роутер сразу принимает статус RouterConnected.
Создание и открытие подписчика происходит следующим образом:
listener_t* lsn = 0; result = lsn_new(conn, "p2sys://;name=p2sys_lsn", &MessageCallback, 0, &lsn); result = lsn_open(lsn, 0);
где функция обратного вызова MessageCallback содержит обработчик приходящих сообщений.
Закрывается подписчик следующим образом:
lsn_close(lsn);
Публикатор p2sys предназначен для отправки запросов аутентификации или выхода из системы. Публикатор может отправлять 2 вида сообщения типа CG_MSG_DATA:
RouterLogin (msgid = 1). Запрос
на аутентификацию. В поле данных содержит строку в формате
"USERNAME=%имя_пользователя%;PASSWORD=%пароль%
"
RouterLogout (msgid = 2). Запрос на отключение. Не содержит каких-либо данных.
Создание и открытие публикатора происходят следующим образом:
publisher_t* pub = 0; result = pub_new(conn, "p2sys://;name=p2sys_pub", &pub); result = pub_open(pub, 0);
Закрытие публикатора происходит стандартным способом:
pub_close(pub);
Функция позволяет получить BCD-число в виде двух компонент - целой части и положения десятичной точки.
CG_RESULT cg_bcd_get( | bcd, | |
intpart, | ||
scale) ; |
void* bcd
;int64_t* intpart
;int8_t* scale
;В качестве параметров функция принимает указатель на число в BCD-формате bcd, указатель на переменную, в которую будет помещено значение числа в виде целого и указатель на переменную, в которую будет помещено положение десятичной точки относительно конца числа.
Например, для исходного числа 123.45 функция запишет в переменную intpart значение 12345, а в переменную scale значение 2.
Максимальное количество знаков, представимых в виде 64-х битного целого равно 19-ти. Для получения значений BCD-чисел, по размерности превосходящих 19 знаков, следует использовать вызов cg_getstr для представления чисел в виде строк.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Переданное число слишком велико для представления в виде 64-х битного целого.
Пример вызова функции:
void* bcd; // указатель на BCD-число int64_t value; // сюда будет записано число в виде целого int8_t scale; // сюда будет записано положение точки result = cg_bcd_get(bcd, &value, &scale); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to convert decimal: 0x%X\n", result); } // напечатать значение в виде числа с плавающей точкой printf("Value is: %f\n", (double)value/pow(10.0, scale));
Функция позволяет получить строковое представление произвольного типа.
CG_RESULT cg_getstr( | type, | |
data, | ||
buffer, | ||
buffer_size) ; |
char* type
;void* data
;char* buffer
;size_t* buffer_size
;В качестве параметров функция принимает тип поля в формате Plaza-2 (см. раздел Работа со схемами данных) в виде строки type, указатель на место в памяти, где содержится значение data, указатель на буфер, куда будет записано строковое представление buffer и указатель на переменную, которая содержит размер буфера buffer_size.
В случае, если размер буфера слишком мал для записи строкового представления, функция вернет код ошибки CG_ERR_BUFFERTOOSMALL и запишет в buffer_size требуемый размер буфера.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Переданный буфер слишком мал для строкового представления типа.
Пример вызова функции:
void* bcd; // указатель на BCD-число char buf[32]; size_t bufsize = sizeof(buf); result = cg_getstr("d26.2", bcd, buf, &bufsize); if (result == CG_ERR_BUFFERTOOSMALL) { char* buf2 = new char[bufsize]; result = cg_getstr("d26.2", bcd, buf2, &bufsize); if (result != CG_ERR_OK) fprintf(stderr, "Failed to convert value: 0x%X\n", result); else printf("Value is %s\n", buf2); delete[] buf2; } else if (result != CG_ERR_OK) { printf("Value is %s\n", buf2); } else { fprintf(stderr, "Failed to convert value: 0x%X\n", result); }
Функция позволяет получить текстовый дамп произвольного сообщения.
CG_RESULT cg_msg_dump( | msg, | |
schemedesc, | ||
buffer, | ||
buffer_size) ; |
struct cg_msg_t* msg
;struct cg_scheme_desc_t*
schemedesc
;char* buffer
;size_t* buffer_size
;В качестве параметров функция принимает указатель на сообщение msg, указатель на описание схемы schemedesc, указатель на буфер, куда будет записан текстовый дамп buffer и указатель на переменную, которая содержит размер буфера buffer_size.
В случае, если размер буфера слишком мал для записи строкового представления, функция вернет код ошибки CG_ERR_BUFFERTOOSMALL и запишет в buffer_size требуемый размер буфера.
Возвращаемые значения:
Успешное выполнение.
Функции были переданы некорректные аргументы.
Переданный буфер слишком мал для дампа сообщения.
Если параметр schemedesc не равен NULL, то функция предпримет попытку разобрать сообщение с использованием переданной схемы. Если параметр schemedesc равен NULL или сообщение отсутствует в схеме или его размер не совпадает с указанным в схеме, функция выведет шестнадцатеричный дамп сообщения.
Эту функцию удобно использовать для отладки.
Пример вызова функции:
cg_msg_t* msg; // указатель на сообщение size_t bufsize = 0; result = cg_msg_dump(msg, 0, 0, &bufsize); if (result == CG_ERR_BUFFERTOOSMALL) { char* buf = new char[bufsize]; result = cg_msg_dump(msg, 0, buf, &bufsize); if (result != CG_ERR_OK) { fprintf(stderr, "Failed to dump message: 0x%X\n", result); } else { printf("%s\n", buf); } delete[] buf; } else fprintf(stderr, "Failed to dump message: 0x%X\n", result);
Утилита schemetool предназначена для работы со схемами данных.
В настоящее время поддерживается функция формирования структур данных на языках программирования, соответствующих формату сообщений потоков данных.
Режим makesrc предназначен для формирования исходного кода с описанием структур сообщений. Полученные структуры могут быть использованы для доступа к полям сообщений.
Формирование схемы производится следующим вызовом:
schemetool makesrc [options] [SOURCE SCHEME]
, где:
Источник схемы. Описание схемы может быть получено из INI-файла, в этом случае в качестве SOURCE следует передать путь к ini-файлу. Также схема может быть получена из потока репликации - в этом случае в качестве SCHEME_SOURCE надо передать два параметра: --conn CONN_STR --stream STREAM_NAME; при этом CONN_STR задаёт строку соединения с рутером P2MQRouter в формате URL, а STREAM_NAME задаёт имя интересующего потока репликации
Имя интересущей схемы; должно задаваться явно.
а options - это параметры:
-o FILENAME
Имя выходного файла. В этот файл будут записаны результаты работы утилиты. В случае, если данный параметр не указан, будет использован стандартный вывод stdout.
--output-format FORMAT
Формат описания структур. В настоящее время поддерживаются следующие форматы:
c - структуры на языке C
java - классы для Java
cs - классы для C#
pas - структуры на Pascal
Используется для формата "c". Указание данного ключа приведет к тому, что к названиям структур сообщений будут добавлены префиксы - названия схем сообщений. Этот режим может использоваться для того, чтобы избежать конфликтов имен при использовании нескольких схем в одном INI-файле в том случае, если в разных схемах существуют сообщения с одинаковыми именами.
Используется для формата "c". Указание данного ключа приведет к формированию namespace с именем схемы для каждой из схем INI-файла. Может быть использовано для разрешения конфликта имен как альтернатива предыдущему варианту, если для компиляции ПО применяется компилятор C++.
Генерирует typedef для каждой таблицы
Генерировать строковое представление схемы
Задать тип TYPE для wchar_t строк
Пользовательский ключ сертификации
Выводить логи.
Используется для формата "java". Позволяет задать имя генерируемого класса Java верхнего уровня.
Используется для формата "java". Позволяет задать имя пакета Java для генерируемого класса.
Используется для формата "java". Поля, содержащие значения типа дата-время, будут сконвертированы в java.util.Date (по умолчанию)
Используется для формата "java". Поля, содержащие значения типа дата-время, будут сконвертированы в значение типа long, содержащее кол-во миллисекунд прошедшее с 00:00:00 1.01.1970 г.
Используется для формата "java". Поля, содержащие значения типа BCD, будут сконвертированы в java.math.BigDecimal (по умолчанию)
Используется для формата "java". Поля, содержащие значения типа BCD, будут сконвертированы в long
Используется для формата "cs". Позволяет задать имя пространства имен .NET для генерируемого класса.
Используется для формата "cs". Поля, содержащие значения типа дата-время, будут сконвертированы в DateTime (по умолчанию)
Используется для формата "cs". Поля, содержащие значения типа дата-время, будут сконвертированы в значение типа long, содержащее кол-во миллисекунд прошедшее с 00:00:00 1.01.1970 г.
Используется для формата "cs". Поля, содержащие значения типа BCD, будут сконвертированы в decimal (по умолчанию)
Используется для формата "cs". Поля, содержащие значения типа BCD, будут сконвертированы в long
Примеры использования утилиты:
schemetool makesrc -o futinfo.h forts_scheme.ini FUTINFO
- этот пример формирует в файле futinfo.h описания структур на языке C схемы FUTINFO из файла forts_scheme.ini.
schemetool makesrc -o futinfo.pas --output-format pas forts_scheme.ini FUTINFO
- этот пример формирует в файле futinfo.pas описания структур на языке Pascal схемы FUTINFO из файла forts_scheme.ini.
schemetool makesrc -o futinfo.h --output-format c \ --conn p2tcp://localhost:4001;app_name=stool \ --stream FORTS_FUTINFO_REPL
- этот пример формирует в файле futinfo.h описания структур на языке C схемы данных потока FORTS_FUTINFO_REPL, доступного через соединение с рутером Plaza-2, запущенным на этой же машине на порту 4001.
schemetool makesrc -o messages.h forts_messages.ini message
- этот пример формирует в файле messages.h описания структур сообщений торговой системы FORTS из файла forts_messages.ini
В поставку P2 CGate входят следующие интерфейсные библиотеки:
cgate_java
Библиотека, реализующая интерфейс с платформой Javа
cgate_net
Библиотека, реализующая интерфейс с платформой .NET
Обе библиотеки построены по сходным правилам и оперируют похожими объектами, в силу этого, описание API будет приводиться одновременно для Java и .NET.
Поддержка CGate для Java реализуется с помощью интерфейса JNI. В поставку P2 CGate входят следующие компоненты, относящиеся к поддержке Java:
интерфейсная библиотека cgate_jni (cgate_jni.dll для Windows, libcgate_jni.so для Linux; каталог CGATE_HOME/p2bin)
библиотека классов Java cgate.jar (каталог CGATE_HOME/sdk/lib)
примеры использования P2 CGate на Java (каталог CGATE_HOME/sdk/samples/java)
Для использования P2 CGate из Java нужно:
использовать библиотеку cgate.jar при компиляции проекта
при запуске проекта
иметь cgate.jar в classpath
иметь библиотеку cgate_jni в пути, используемом для загрузки динамических библиотек (задаётся свойством java.library.path)
иметь набор библиотек P2 CGate доступным для загрузки (содержимое каталога CGATE_HOME/p2bin)
Существует возможность явного указания используемой библиотеки cgate_jni и пути к ней с помощью следующих свойств:
ru.micexrts.cgate.name
Задаёт имя файла библиотеки
ru.micexrts.cgate.path
Задаёт каталог, в котором находится файл библиотеки
Например:
java -cp .;lib/cgate.jar -Dru.micexrts.cgate.name=libcgate_jni.so.1 -Dru.micexrts.cgate.path=. MyApp
В этом примере запускается приложение пользователя из класса MyApp, при этом используется библиотека cgate.jar из подкаталога lib; интерфейсная библиотека cgate_jni будет взята из файла ./libcgate_jni.so.1.
Поддержка CGate для платформы .NET реализована с помощью С++/CLI. В поставку P2 CGate входят следующие компоненты, относящиеся к поддержке .NET:
сборка cgate_net.dll (каталог CGATE_HOME/p2bin)
примеры использования P2 CGate на .NET (каталог CGATE_HOME/sdk/samples/net)
Для использования P2 CGate из .NET нужно:
использовать сборку cgate_net.dll при компиляции проекта
при запуске проекта
иметь cgate_net.dll доступной для загрузки платформой .net
иметь набор библиотек P2 CGate доступным для загрузки (содержимое каталога CGATE_HOME/p2bin)
Запуск библиотеки cgate_net под платформой Mono не поддерживается.
Объект Connection обеспечивает доступ к набору функцию соединения (см. Соединение).
Описание | Java | .NET | Функция CGate API |
---|---|---|---|
Создание объекта соединения | Connection(String settings) | Connection(string settings) | cg_conn_new |
Уничтожение объекта соединения | void dispose() | void Dispose() | cg_conn_destroy |
Открытие соединения | void open(String settings) | void Open(string settings) | cg_conn_open |
Закрытие соединения | void close() | void Close() | cg_conn_close |
Обработка сообщений соединения | void process(int timeout) | void Process(int timeout) | cg_conn_process |
Получение состояние соединения | int getState() | State | cg_conn_getstate |
После завершения работы с соединением должен быть вызван метод dispose(), который явным образом освобождает ресурсы, связанные с соединением.
Инициализирует новый экземпляр класса.
Синтаксис Java:
public Connection(String settings) throws CGateException
Синтаксис C#:
public Connection(string settings)
Где:
Строка инициализации соединения (см. cg_conn_new)
Возможные исключения:
Ошибка создания соединения
Очистка ресурсов соединения выполняется вызовом метода dispose().
Синтаксис Java:
public void dispose() throws CGateException
Синтаксис C#:
public void Dispose()
Возможные исключения:
Ошибка уничтожения соединения
Открытие соединения выполняется вызовом метода open().
Синтаксис Java:
public void open(String settings) throws CGateException
Синтаксис C#:
public void Open(string settings)
Возможные исключения:
Ошибка открытия соединения
Открытие соединения выполняется вызовом метода close().
Синтаксис Java:
public void close() throws CGateException
Синтаксис C#:
public void close()
Возможные исключения:
Ошибка закрытия соединения
Обработка сообщений соединения выполняется вызовом метода process().
Синтаксис Java:
public int process(int timeout)
Синтаксис C#:
public int Process(int timeout)
Возможные исключения: отсутсвуют
Возвращаемые значения:
Успешное завершение операции
Недопустимое состояние соединения
Внутренняя ошибка
Обработка сообщений соединения выполняется вызовом метода process().
Синтаксис Java:
public int getState() throws CGateException
Синтаксис C#:
public State State { get; }
Возможные исключения:
Ошибка закрытия соединения
Возвращаемые значения:
Соединение закрыто
Соединение в состоянии ошибки
Соединение в процессе открытия
Соединение активно
Объект Listener обеспечивает доступ к набору функций подписчика (см. Подписчик).
Описание | Java | .NET | Функция CGate API |
---|---|---|---|
Создание объекта подписчика | Listener(Connection conn, String settings, ISubscriber subscriber) | Listener(Connection conn, string settings) | cg_lsn_new |
Уничтожение объекта подписчика | void dispose() | void Dispose() | cg_lsn_destroy |
Открытие подписчика | void open(String settings) | void Open(string settings) | cg_lsn_open |
Закрытие подписчика | void close() | void Close() | cg_lsn_close |
Получение состояние соединения | int getState() | State | cg_lsn_getstate |
Получение схемы подписчика | int getScheme() | Scheme | cg_lsn_getscheme |
Установка обработчика | - | Handler | - |
После завершения работы с подписчиком должен быть вызван метод dispose(), который явным образом освобождает ресурсы, связанные с подписчиком.
Инициализирует новый экземпляр класса.
Синтаксис Java:
public Listener(Connection conn, String settings, ISubscriber subscriber) throws CGateException
Синтаксис C#:
public Listener(Connection conn, string settings)
Где:
Соединение, в привязке к которому создаётся подписчик
Строка инициализации подписки (см. cg_lsn_new)
Пользовательский обработчик сообщений (только Java; для .NET следует использовать свойства Handler)
Возможные исключения:
Ошибка создания подписки
Для Java параметр subscriber указывает на экземпляр класса, реализующего интерфейс ISubscriber:
public interface ISubscriber { public int onMessage(Connection conn, Listener listener, Message message); }
При возникновении какого либо события подписчика, например, приход нового сообщения или изменение состояния подписчика, будет вызван метод onMessage объекта, переданного в параметре subscriber.
В качестве параметров будут переданы:
Соединение, к которому привязан подписчик
Подписчик, в котором произошло событие
Сообщение
Для .NET параметр subscriber отсутсвует; вместо него введено специальное свойтство Handler, которое позволяет устанавливать обработчик сообщений естественным для среды .NET образом.
Очистка ресурсов подписчика выполняется вызовом метода dispose().
Синтаксис Java:
public void dispose() throws CGateException
Синтаксис C#:
public void Dispose()
Возможные исключения:
Ошибка уничтожения подписчика
Предпринимает попытку открытия подписчика.
Синтаксис Java:
public void open(String settings) throws CGateException
Синтаксис C#:
public void Open(string settings)
Возможные исключения:
Ошибка открытия подписчика
Закрывает подписку.
Синтаксис Java:
public void close() throws CGateException
Синтаксис C#:
public void close()
Возможные исключения:
Ошибка закрытия подписчика
Возвращает текущее состояние подписчика.
Синтаксис Java:
public int getState() throws CGateException
Синтаксис C#:
public State State { get; }
Возможные исключения:
Ошибка получения состояния подписчика
Возвращаемые значения:
Подписчик закрыт
Подписчик в состоянии ошибки
Подписчик в процессе открытия
Подписчик активен
Возвращает текущую схему данных подписчика.
Синтаксис Java:
public Scheme getScheme() throws CGateException
Синтаксис C#:
public Scheme Scheme { get; }
Возможные исключения:
Ошибка получения схемы данных
Возвращаемое значение - это описание текущей схемы данных подписчика или null, если подписчик работает в режиме без схемы.
Схема данных подписчика доступна с момента получения сообщения OPEN до момента закрытия подписчика или его перехода в состояние ошибки.
Схема данных подписчика может изменяться между двумя событиями CLOSE и OPEN; т.е. после повторного открытия подписчика, его схема может отличаться от той, которая была действительна во время прошлой сессии активности.
Позволяет устанавливать пользовательский обработчик сообщений подписчика.
Синтаксис C#:
public MessageHandler Handler { get; set; }
Пользовательские обработчики должны соответствовать следующему виду:
delegate int MessageHandler(Connection conn, Listener listener, Message msg);
, где в качестве параметров будут переданы:
Соединение, к которому привязан подписчик
Подписчик, в котором произошло событие
Сообщение
Объект Publisher обеспечивает доступ к набору функций публикатора (см. Публикатор).
Описание | Java | .NET | Функция CGate API |
---|---|---|---|
Создание объекта публикатора | Publisher(Connection conn, String settings) | Publisher(Connection conn, string settings) | cg_pub_new |
Уничтожение объекта публикатора | void dispose() | void Dispose() | cg_pub_destroy |
Открытие публикатора | void open(String settings) | void Open(string settings) | cg_pub_open |
Закрытие публикатора | void close() | void Close() | cg_pub_close |
Получение состояния публикатора | int getState() | State | cg_pub_getstate |
Получение схемы публикатора | int getScheme() | Scheme | cg_pub_getscheme |
Создание сообщения для отправки | Message newMessage(int idType, Object id) | Message NewMessage(MessageFlag idType, Object id); | cg_pub_msgnew |
Отправка сообщения | void post(Message msg, int flags) | Message Post(Message msg, PublisherFlag flags); | cg_pub_post |
После завершения работы с публикатором должен быть вызван метод dispose(), который явным образом освобождает ресурсы, связанные с публикатором.
Инициализирует новый экземпляр класса.
Синтаксис Java:
public Publisher(Connection conn, String settings) throws CGateException
Синтаксис C#:
public Publisher(Connection conn, string settings)
Где:
Соединение, в привязке к которому создаётся публикатор
Строка инициализации публикатора (см. cg_pub_new)
Возможные исключения:
Ошибка создания публикатора
Очистка ресурсов публикатора выполняется вызовом метода dispose().
Синтаксис Java:
public void dispose() throws CGateException
Синтаксис C#:
public void Dispose()
Возможные исключения:
Ошибка уничтожения публикатора
Предпринимает попытку открытия публикатора.
Синтаксис Java:
public void open(String settings) throws CGateException
Синтаксис C#:
public void Open(string settings)
Возможные исключения:
Ошибка открытия публикатора
Закрывает публикатор.
Синтаксис Java:
public void close() throws CGateException
Синтаксис C#:
public void close()
Возможные исключения:
Ошибка закрытия публикатора
Возвращает текущее состояние публикатора.
Синтаксис Java:
public int getState() throws CGateException
Синтаксис C#:
public State State { get; }
Возможные исключения:
Ошибка получения состояния публикатора
Возвращаемые значения:
Публикатор закрыт
Публикатор в состоянии ошибки
Публикатор в процессе открытия
Публикатор активен
Возвращает текущую схему данных публикатора.
Синтаксис Java:
public Scheme getScheme() throws CGateException
Синтаксис C#:
public Scheme Scheme { get; }
Возможные исключения:
Ошибка получения схемы данных
Возвращаемое значение - это описание текущей схемы данных публикатора или null, если публикатор работает в режиме без схемы.
Схема данных публикатора может изменяться между двумя событиями CLOSE и OPEN; т.е. после повторного открытия публикатора, его схема может отличаться от той, которая была действительна во время прошлой сессии активности.
Создаёт новое сообщение для отправки.
Синтаксис Java:
public void newMessage(int idType, Object id) throws CGateException
Синтаксис C#:
public void NewMessage(MessageFlag idType, Object id)
, где:
Тип идентификатора сообщения. Одно из значений:
KEY_INDEX - параметр id является номером требуемого сообщения в схеме
KEY_ID - параметр id является уникальным числовым идентификатором требуемого сообщения в схеме
KEY_NAME - параметр id является строкой - именем требуемого сообщения в схеме
Идентификатор сообщения (Integer или String, в зависимости от значения параметра idType)
Возможные исключения:
Ошибка создания сообщения
Созданное сообщение содержит буфер, по размеру соответствующий описанию сообщения в схеме данных.
Отправляет сообщение.
Синтаксис Java:
public void post(Message msg, int flags) throws CGateException
Синтаксис C#:
public void Post(Message msg, PublisherFlag flags)
, где:
Сообщения для отправки
Флаги отправки сообщения. В настоящее время поддерживается единственный флаг NEED_REPLY, который означает необходимость получения ответа на отправленное сообщение.
Возможные исключения:
Ошибка отправки сообщения
Отправленное сообщение после вызова метода post() не используется и может быть удалено или использовано для повторной отправки.
Объект Publisher может отправлять только те сообщения, которые были созданы этим же экземпляром объекта.
Объект Message обеспечивает доступ к сообщениям.
Описание | Java | .NET | CGate API |
---|---|---|---|
Уничтожение объекта сообщения | void dispose() | void Dispose() | cg_pub_msgfree |
Получение типа сообщения | int getType() | Type | поле type структуры cg_msg_t |
Получение буфера с данными | ByteBuffer getData() | Data | поле data структуры cg_msg_t |
Получение отладочного представления сообщения | String toString() | string ToString() | cg_msg_dump |
Пользователь отвечает за уничтожение созданных им сообщений для отправки явным вызовом метода dispose(). Сообщения, которые пользователь получает в обработчик подписки не должны уничтожаться, так как владельцем таких сообщений является библиотека P2 CGate.
Очистка ресурсов сообщения выполняется вызовом метода dispose().
Синтаксис Java:
public void dispose() throws CGateException
Синтаксис C#:
public void Dispose()
Возможные исключения:
Ошибка уничтожения сообщения
Возвращает тип сообщения.
Синтаксис Java:
public int getType()
Синтаксис C#:
public MessageType Type { get; }
Возвращает буфер данных сообщения
Синтаксис Java:
public java.nio.ByteBuffer getData()
Синтаксис C#:
public System.IO.UnmanagedMemoryStream Data { get; }
Размер буфера с данными доступен через соответствующий вызов объекта, возвращаемого свойством. Формат буфера соответствует используемой схеме данных.
Свойство Data может возвращать null - это означает, что сообщение не содержит данных.
Возвращает текствое представление сообщения.
Синтаксис Java:
public String toString()
Синтаксис C#:
public string ToString()
Данное представление может использоваться в отладочных нуждах.
Для более комфортной работы с P2 CGate введены классы, описывающие конкретные типы сообщений. Такие классы содержат дополнительную информацию. Пользователь может получить доступ к дополнительным свойствам сообщения выполнив преобразования типа объекта (каст), основанное на анализе свойства Message.Type.
Описывает сообщений типа CG_MSG_OPEN - открытие подписчика.
Объект не содержит дополнительных полей.
Описывает сообщений типа CG_MSG_CLOSE - закрытие подписчика.
Описание | Java | .NET | CGate API |
---|---|---|---|
Причина закрытия объекта | int getReason() | Reason CloseReason() | - |
Описывает сообщений типа CG_MSG_DATA - сообщение с данными.
Дополнительные свойства объекта:
Описание | Java | .NET | CGate API |
---|---|---|---|
Номер сообщения в схеме данных | int getMsgIndex() | MsgIndex | поле msg_index структуры cg_msg_data_t |
Числовой идентификатор сообщения в схеме данных | int getMsgId() | MsgId | поле msg_id структуры cg_msg_data_t |
Имя сообщения в схеме данных | int getMsgName() | MsgName | поле msg_name структуры cg_msg_data_t |
Адрес отправителя/получателя сообщения | string getAddress() | Address | поле addr структуры cg_msg_data_t |
Пользовательский номер сообщения | int getUserId()/void setUserId(int val) | MsgName | поле user_id структуры cg_msg_data_t |
Список полей сообщения | Value[] getFields() | Fields | - |
Получение поля по имени | Value] getField(String name) | Field[string] | - |
Описывает сообщений типа CG_MSG_STREAM_DATA - сообщение с потоковыми данными.
Дополнительные свойства объекта:
Описание | Java | .NET | CGate API |
---|---|---|---|
Номер сообщения в схеме данных | int getMsgIndex() | MsgIndex | поле msg_index структуры cg_msg_streamdata_t |
Числовой идентификатор сообщения в схеме данных | int getMsgId() | MsgId | поле msg_id структуры cg_msg_streamdata_t |
Имя сообщения в схеме данных | int getMsgName() | MsgName | поле msg_name структуры cg_msg_streamdata_t |
Номер сообщения в потоке | long getRev() | Rev | поле rev структуры cg_msg_streamdata_t |
Список полей сообщения | Value[] getFields() | Fields | - |
Получение поля по имени | Value] getField(String name) | Field[string] | - |
Описывает сообщений типа CG_MSG_TN_BEGIN - идентифицирует начало транзакции для потоковых данных.
Объект не содержит дополнительных полей.
Описывает сообщений типа CG_MSG_TN_COMMIT - идентифицирует завершение транзакции для потоковых данных.
Объект не содержит дополнительных полей.
Описывает сообщений типа CG_MSG_P2MQ_TIMEOUT - сообщение о превышении времени ожидания ответа на отправленное сообщение.
Дополнительные свойства объекта:
Описание | Java | .NET | CGate API |
---|---|---|---|
Пользовательский номер сообщения | int getUserId()/void setUserId(int val) | MsgName | поле user_id структуры cg_msg_data_t |
Описывает сообщений типа CG_MSG_P2REPL_LIFENUM - сообщение об изменении номера жизни схемы данных.
Дополнительные свойства объекта:
Описание | Java | .NET | CGate API |
---|---|---|---|
Новый номер жизни схемы данных | int getLifeNumber() | LifeNumber | значение *data сообщения |
Описывает сообщений типа CG_MSG_P2REPL_CLEARDELETED - сообщение об удалении диапазона данных по указанной таблице.
Дополнительные свойства объекта:
Описание | Java | .NET | CGate API |
---|---|---|---|
Номер таблицы | int getTableIdx() | TableIdx | поле table_idx структуры cg_data_cleardeleted_t |
Номер ревизии, ниже которого данные удаляются | long getTableRev() | TableRev | поле table_rev структуры cg_data_cleardeleted_t |
Описывает сообщений типа CG_MSG_P2REPL_ONLINE - сообщение о переходе потока данных в состояние ONLINE.
Объект не содержит дополнительных полей.