| Россия |
Дополнительные особенности программирования для WebSphere MQ
Channel-exit программы
Channel - exits программы выполняются канальными агентами. Эти программы первыми и последними встречают и провожают сообщения. Именно поэтому их чаще всего используют для шифрования, проверки идентификации и аутентификации сообщений в целях безопасности.
Иногда возникает потребность применять Channel- exits программы, например, для того чтобы проследить прохождение сообщений и выполнить их логирование, выявить возникшие проблемы. Допустим, что стандартное ПО этого не делает, "вклиниваться" в него не представляется возможным, так как все входящие сообщения считывает из очереди программа-обработчик. В этом случае можно написать простую Channel- exits программу в виде библиотечной функции для UNIX или как DLL (Dynamic Linl Library) для Windows. Программе следует присвоить имя, к примеру, mqexit.dll с точкой входа MsgExit. Для работы программы, ее надо прописать в том канале, через который идут сообщения:
С помощью программы RUNMQSC это может быть сделано командой:
alter chl(mychannel) chltype(mychannel_type)
msgexit(' mqexit(MsgExit)')
msgdata('\mydir\mqexit.ini')Программа mqexit.dll и настроечный файл mqexit.ini помещаются в стандартной директории (mydir ) для Channel exits программ (для Windows это C:\Program Files\IBM\WebSphere MQ\Exits\, для UNIX HP_UX это /var/mqm/exits/, аналогичные пути существуют для других платформ).
Настроечный файл mqexit.ini может содержать имя лог файла, имя буферного файла для записи входящего сообщения; имя очереди, в которую перекладывается содержимое буферного файла; имя менеджера, ведь менеджеров может быть несколько на одном сервере.
В учебных целях стоит упростить задачу, не использовать mqexit.ini-файл и записать имя лог-файла непосредственно в Message Exit Data (например, C:\TEMP\mqexit.log ), а с сообщениями пусть разбирается прежняя программа-обработчик, читающая входящие сообщения из очереди. При этом предполагается, что используется менеджер очередей по умолчанию. В этом случае программа mqexit.dll для Windows выглядит следующим образом.
/* Листинг программы mqexit.dll */
/************************************************************************/
/* Program name: mqexit */
/* Description: This is a sample message exit function record all messages */
/* This function will work on any channels, e.g. send, receive, requester, etc. */
/* This function logs all channel activities into the Channel Log file. */
/* Please see Intercommunication documentation to specify the Channel Message Exit */
/* Authors: Vladimir Makushkin, Moscow, Russia */
/* email: vmakushkin@mail.ru */
/* Disclaimer: this program has been tested under HP_UX and Windows to the */
/* authors' satisfaction. You may use this program at your own risk. Author are not */
/* responsible for any unexpected results generated by this program. */
/************************************************************************/
/* standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <locale.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <time.h>
/* MQSeries headers */
#include <cmqc.h>
#include <cmqxc.h>
char timebuf??(130??);
char Channel_Logfile??(129??);
char MsgBufFile??(129??);
char ini_filename??(129??);
FILE * OST = 0;
#define DBGPRINTF(x) { \
OST=fopen(Channel_Logfile,"a+"); \
if(OST) fprintf x; \
fclose(OST); \
}
void writer (long *, char *); /* prototype for file writer function */
void getINI( void );
void MQENTRY MQStart(void) {;}
void MQENTRY MsgExit( PMQCXP pChannelExitParams,
PMQCD pChannelDefinition,
PMQLONG pDataLength,
PMQLONG pAgentBufferLength,
PMQBYTE AgentBuffer,
PMQLONG pExitBufferLength,
PMQPTR pExitBufferAddr)
{
short i;
struct timeb t;
char millisec??(25??);
time_t clock = time( (time_t*) NULL);
struct tm *tmptr = localtime(&clock);
strcpy(timebuf, asctime(tmptr));
ftime( &t );
memset( millisec, 0, sizeof( millisec ) );
sprintf( millisec, " Time:%ld.%d", t.time, t.millitm );
strcat( timebuf, millisec );
if ( strlen(pChannelExitParams->ExitData) )
{
memset( ini_filename, 0, sizeof( ini_filename ) );
strncpy( ini_filename, pChannelExitParams->ExitData, MQ_EXIT_DATA_LENGTH );
/*------------------------*/
/* remove space from data */
/*------------------------*/
for ( i = MQ_EXIT_DATA_LENGTH - 1; i > 0; i-- )
{
if ( ini_filename??(i??) != ' ' && ini_filename??(i??) )
break;
ini_filename??(i??) = 0;
}
}
getINI();
void writer(long *lngth, char *bf)
{
long msgsize;
int n;
FILE *fp;
getINI();
fp = fopen(MsgBufFile, "ab");
msgsize = *lngth;
n = fwrite(&msgsize, sizeof(msgsize), 1, fp); /* put record length */
n = fwrite(bf, msgsize, 1, fp); /* and message buffer */
fclose(fp);
}
/*---------------------------------------------------------
getINI() - read information from INI file
-----------------------------------------------------------*/
void getINI( void )
{
FILE *ini_fp;
char *ptr, *name_ptr;
char field_val??(129??), Ini_s??(129??), fn??(129??);
short len;
memset( Ini_s, 0, sizeof( Ini_s ) );
memset( field_val, 0, sizeof( field_val ) );
memset( MsgBufFile, 0, sizeof ( MsgBufFile ) );
memset( Channel_Logfile, 0, sizeof( Channel_Logfile ) );
if ( strlen( ini_filename ) ) /* if Channel Exit defined INI filename */
strcpy( fn, ini_filename ); /* use it */
else /* otherwise use default INI filename */
strcpy( fn, INI_FILENAME );
if ( (ini_fp = fopen( fn, "r" )) == NULL )
{
fprintf(stderr, "\nUnable to open %s. Error #: %d", fn, errno );
return;
}
/*-----------------------------*/
/* read the INI file until eof */
/*-----------------------------*/
while ( (ptr = fgets( Ini_s, sizeof(Ini_s) - 1, ini_fp )) != NULL )
{
len = strlen( Ini_s );
if ( Ini_s??(len -1??) == LINEFEED )
Ini_s??(len-1??) = 0; /* null out '\n' */
if ( (name_ptr = strchr( Ini_s, EQUAL )) == NULL ) /* no '=' found */
continue;
ptr = name_ptr + 1;
*name_ptr = 0; /* set null for s[] */
strcpy( field_val, ptr );
fclose( ini_fp );
return;
}
Листинг
11.1.
Листинг программы mqexit.c
В качестве комментария к программе надо отметить, что обязательным является соблюдение трех рекомендаций для Windows из документа [ 8 ] - Intercommunication.
- Начало программы следует определить точками входа MQStart и ChannelExit программы mqexit.c:
#include <cmqc.h> #include <cmqxc.h> void MQStart() {;} /* dummy entry point - for consistency only */ void MQENTRY ChannelExit ( PMQCXP pChannelExitParms, PMQCD pChannelDefinition, PMQLONG pDataLength, PMQLONG pAgentBufferLength, PMQVOID pAgentBuffer, PMQLONG pExitBufferLength, PMQPTR pExitBufferAddr) { ... Insert code here } - При компиляции добавить в проект как исходный файл MQMVX.LIB. В настройках проекта для генерации C/C++ кода изменить выпадающее меню с "Use Run-Time Library" на "Multithreaded" для "Multithreaded using DLL".
- Добавить в проект свой .DEF файл ( mqexit.def ):
LIBRARY mqexit DESCRIPTION 'Provides Retry and Channel exits' HEAPSIZE 4096 STACKSIZE 8192 EXPORTS ChannelExit
И после этого проходящие по каналу сообщения начинают записываться в файл, определенный в Message Exit Data, включая заголовок и данные сообщения. Скорость прохождения сообщений с использованием Channel exits программ уменьшится за счет команд записи на диск. Читателю предлагается исследовать самостоятельно во сколько раз изменится скорость работы программы и найти пути её повышения.
В заключение лекции следует отметить, что остались механизмы, которые не нашли отражение в этой книге и могли бы представлять интерес для читателя-программиста, а именно:
- Разработка программ на основе интерфейсов JMS и AMI [ 21 ] ;
- PCF - команды (Programmable Command Format) и работа с ними;
- встроенные средства мониторинга событий WebSphere MQ.
С этими вопросами читателю предлагается ознакомиться самостоятельно по документации.
Ключевым моментом интеграции приложений является использование
WebSphere Business Integration Message Broker
, сокращенно WBI
Message Broker или просто WBI Broker (ранее - IBM MQSeries
Integrator
) для управления и преобразования потоков сообщений. Этот
продукт компании IBM будет рассмотрен далее.