Компания IBM
Опубликован: 14.12.2004 | Доступ: свободный | Студентов: 1531 / 139 | Оценка: 4.36 / 3.98 | Длительность: 16:32:00
ISBN: 978-5-9556-0031-4
Специальности: Системный архитектор
Лекция 12:

Дополнительные особенности программирования для WebSphere MQ

< Лекция 11 || Лекция 12: 1234 || Лекция 13 >

Channel-exit программы

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

Иногда возникает потребность применять Channel- exits программы, например, для того чтобы проследить прохождение сообщений и выполнить их логирование, выявить возникшие проблемы. Допустим, что стандартное ПО этого не делает, "вклиниваться" в него не представляется возможным, так как все входящие сообщения считывает из очереди программа-обработчик. В этом случае можно написать простую Channel- exits программу в виде библиотечной функции для UNIX или как DLL (Dynamic Linl Library) для Windows. Программе следует присвоить имя, к примеру, mqexit.dll с точкой входа MsgExit. Для работы программы, ее надо прописать в том канале, через который идут сообщения:

Message Exit Name: mqexit(MsgExit)
Message Exit Data: \mydir\mqexit.ini

С помощью программы 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.

  1. Начало программы следует определить точками входа 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
    }
  2. При компиляции добавить в проект как исходный файл MQMVX.LIB. В настройках проекта для генерации C/C++ кода изменить выпадающее меню с "Use Run-Time Library" на "Multithreaded" для "Multithreaded using DLL".
  3. Добавить в проект свой .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 \text{\textregistered}, сокращенно WBI Message Broker или просто WBI Broker (ранее - IBM MQSeries Integrator \text{\textregistered}) для управления и преобразования потоков сообщений. Этот продукт компании IBM будет рассмотрен далее.

< Лекция 11 || Лекция 12: 1234 || Лекция 13 >