English

Freewareで習得するIBM MQの基本

メッセージ記述子(MQMD)(1)

 本連載では、当社で作成/提供しているフリーウェアであるmqpgf/mqpcfを使用したIBM MQの機能検証を通して、WebSphere MQ/IBM MQの基本について解説します。 mqpgfはMQが提供するAPIであるMQIを利用して様々なテストが実施できるプログラムです。 エージェントを介してキューマネージャーとやり取りをします。

※本連載は最新のmqpgf/mqpcfに基づいて改定されることがあります。常に最新バージョンをダウンロードしてご使用ください。

fig 1.1

mqpcfはMQの管理APIであるMQAIを使用して、コマンドサーバーとPCFコマンドを送受信し、MQオブジェクトへの操作を実行、その状態を確認することができるプログラムです。

fig 1.2

必要に応じて、mqpgfユーザーズ・ガイドmqpcfユーザーズ・ガイドやMQ のKnowledge Centerも併せてご参照ください。 mqpgf/mqpcfは本サイトからダウンロード可能で、インストールも特になく、ダウンロードしたアーカイブを解凍して、コマンドをコピーするのみです。詳細はダウンロードしたアーカイブに含まれるドキュメントを参照してください。 尚、MQのインストールについては、本連載では説明しませんので、製品のマニュアルをご参照ください。 IBM MQのライセンスを持っていない場合でも、「無料評価版(90日間)」や、一定の条件で「WebSphere MQ Advanced for development」も利用することができます。 本連載は、主にMQ9.x、MQ8.xで確認を行っていますが、MQ5.3以上のバージョンでメッセージ・プロパティ等、一部の機能を除き問題なく実施できるはずです。

※MQ for HP NonStop製品の場合は、本連載で記載されているオペレーションと一部異なる場合があります。


mqpgfとmqpcfの指定可能なオプション

最初に、mqpgfとmqpcfの指定可能なオプションの表示方法についてご紹介しておきます。


1)mqpgf

mqpgfは引数なしで、実行すると指定可能なオプションが表示されます。

$ mqpgf USAGE: -qm : queue manager name(e.g. -qm "qm1,qm2,...") -q : queue name -m : input message -mx : input message(hexadecimal notation e.g. 09af..) -f : input file name -o : output file name -oq : output queue name(for queue to queue)('*': MQMD.ReplyToQ) -iq : input queue name(for send and receive) -d : input directory name -g : output directory name -r : get repeatedly -b : force backout -l : message length for writing -n : message count for writing or reading -i : interval(ms) for writing or reading -sz : max message size for reading(byte)(default 12KByte) -ds : max message display size(byte)(default 128Byte) (all: entire message) -br : browse message -brv : browse message(verbose) -dp : dump message -dpv : dump message(verbose) -raw : raw mode output -hex : dump hexadecimal -s : stop before MQI call (e.g. -s MQCMIT) -p : process name -nl : namelist -pcf : pcf format file name -ss : switch to parameters for secondary -sp : switch to parameters for primary -mc : get the message with the same CorrelId as MsgId sent -im : Inherit MQMD -as : segmentation size -dl : delimiter for logical messages -nt : number of threads -ni : number of threads that call MQCONN/MQDISC internally -tr : enable api trace -sf : the file for synchronization start -c : connection loop count -sd : skip MQDISC MQI functions : -set : MQSET (e.g. MQIA_INHIBIT_GET:MQQA_GET_ALLOWED,..:..) -inq : MQINQ (e.g. MQCA_ALTERATION_DATE,MQIA_CLWL_Q_PRIORITY,..) -smp : MQSETMP (e.g. MQTYPE_STRING:property name:value,..:..) MQCD fields (use MQCONNX) : -x : ConnectionName (e.g. -x "localhost(1414)") -ch : ChannelName MQMD fields : -ex : Expiry(par 100ms) -ec : Encoding -cc : CodedCharSetId -pr : Priority -mi : MsgId -ci : CorrelId -rq : ReplyToQ -rm : ReplyToQMgr -ui : UserIdentifier -at : AccountingToken -ap : ApplIdentityData -pn : PutApplName -pd : PutDate -pt : PutTime -ao : ApplOriginData MQMD Version 2 fields : -gi : GroupId -ms : MsgSeqNumber -of : Offset -ol : OriginalLength MQRFH2 fields: -re : Encoding( or MQENC_*) -rc : CodedCharSetId( or MQCCSI_*) -rf : Format(e.g. -rf MQFMT_STRING) -fg : Flags -nc : NameValueCCSID( or MQCCSI_*) -nd : NameValueData(e.g. -nd "data1,data2,data3") MQCSP fields: -cu : CSPUserId -cp : CSPPassword MQOD fields: -om : ObjectQMgrName -au : AlternateUserId -or : ObjectRec(MQOR)(e.g. ObjectName:ObjectQMgrName,..:..,...) -dq : DynamicQName(for receive queue, e.g. "DQ*", "*" or 33bytes full name) MQPMO fields: -mr : PutMsgRec(MQPMR)(e.g. :::MQFB_xx:,..) MQGMO fields: -wi : WaitInterval(ms) MQIMPO fields: -pe : RequestedEncoding( or MQENC_*) -pc : RequestedCCSID( or MQCCSI_*) MQCB fields : -op : Operation (e.g. -op MQOP_REGISTER -op MQOP_SUSPEND ...) MQCBD fields: -cf : CallbackFunction (e.g. EventHandler) Constants: MQMD : MQMD_*, MQRO_*, MQMT_*, MQEI_*, MQFB_*, MQENC_*, MQCCSI_*, MQFMT_*, MQPRI_*, MQPER_*, MQMI_*, MQCI_*, MQACT_*, MQACTT_*, MQAT_* MQMDV2 : MQGI_*, MQMF_*, MQOL_* MQRFH2 : MQRFH_* MQCONN(X) : MQCNO_*, MQCSP_* MQOPEN : MQOO_*, MQOT_*, MQOD_* MQPUT : MQPMO_*, MQPMRF_ MQGET : MQGMO_*, MQWI_*, MQMO_* MQCLOSE : MQCO_* MQSETMP : MQPD_* MQINQMP : MQIMPO_* MQCRTMH : MQCMHO_* MQCB : MQCBT_*

※"-v" を指定するとバージョン情報が表示されます。 $ mqpgf -v ・・・・ version 1.4.2.4 2018/10/23

※さらに"all"を指定すると指定可能なMQコンスタントの一覧が表示されます。 $ mqpgf -v all .... MQMD_VERSION_1 MQMD_VERSION_2 MQMD_CURRENT_VERSION MQRO_EXCEPTION ....


2)mqpcf

mqpcfは引数なしで、実行すると指定可能なオプションが表示されます。

※"-v" を指定するとバージョン情報も表示されます。


$ mqpcf -v USAGE : mqpcf qmgr -qm Qmgr mqpcf qms -qm Qmgr mqpcf que -qm Qmgr mqpcf cque -qm Qmgr mqpcf ques -qm Qmgr mqpcf queh -qm Qmgr mqpcf chl -qm Qmgr mqpcf chs -qm Qmgr mqpcf lsnr -qm Qmgr mqpcf lsst -qm Qmgr mqpcf cqmgr -qm Qmgr mqpcf con -qm Qmgr mqpcf pngm -qm Qmgr mqpcf ping -qm Qmgr -c Channel mqpcf {put | get} {enable | disable} -qm Qmgr -q Queue mqpcf clr -qm Qmgr -q Queue mqpcf rst -qm Qmgr -c Channel mqpcf rslv -qm Qmgr -c Channel {commit | backout} mqpcf sta -qm Qmgr -c Channel mqpcf stp -qm Qmgr -c Channel mqpcf stalsn -qm Qmgr -ln Listener mqpcf stplsn -qm Qmgr -ln Listener mqpcf mqsc -qm Qmgr {-f MqscFile | -s 'Mqcmd'} -rc : repeat count -i : repeat interval(sec) -t : display time select parameters to display(e.g. mqpcf chs .. SUBSTATE MCASTAT) version 1.4.0.4 2018/06/26

また、実行するコマンドのみを指定すると、そのコマンドで指定可能なオプションが表示されます。 $ mqpcf put USAGE : mqpcf {put | get} {enable | disable} -qm Qmgr -q Queue

このページの先頭へ

メッセージ記述子(MQMD)概要

 MQメッセージには、必ずメッセージ記述子(MQMD: MQ Messege Descriptor)という構造体が付加されます。 この構造体の各フィールドを設定、参照することで様々なMQの機能が利用できます。 このことをよく理解しないままメッセージやシステムの連携を設計したために、その機能の恩恵に授かることができず、MQが提供するものと全く同じ様な機能をアプリケーションやシステム側に実装している例を多く見かけます。 MQ連携の設計を開始し、メッセージのフォーマットを決定する前に、必ずその機能を抑えておきます。

fig 1.3

下記が、MQMDのフィールドの一覧です。 MQMDにはVersion1とVersion2が存在します。 Version2ではいくつかのフィールド/機能が追加されています。


フィールド 説明
StrucId 構造体 ID
Version 構造体のバージョン番号
Report レポート・メッセージのオプション
MsgType メッセージ・タイプ
Expiry メッセージ存続時間
Feedback フィードバックまたは理由コード
Encoding メッセージ・データの数値エンコード
CodedCharSetId メッセージ・データの文字セット ID
Format メッセージ・データの形式名
Priority メッセージ優先度
Persistence メッセージの持続性
MsgId メッセージ ID
CorrelId 相関 ID
BackoutCount バックアウトのカウンター
ReplyToQ 応答キューの名前
ReplyToQMgr 応答キュー・マネージャーの名前
UserIdentifier ユーザー ID
AccountingToken アカウンティング・トークン
ApplIdentityData ID に関連するアプリケーション・データ
PutApplType メッセージを書き込んだアプリケーションのタイプ
PutApplName メッセージを書き込んだアプリケーションの名前
PutDate メッセージを書き込んだ日付
PutTime メッセージを書き込んだ時刻
ApplOriginData 発生元に関係するアプリケーション・データ

*下記は MQMD_VERSION_2 で追加されたフィールドです。
GroupId グループ ID
MsgSeqNumber グループ中の論理メッセージの順序番号
Offset 物理メッセージのデータの、論理メッセージの開始点からの相対位置
MsgFlags メッセージ・フラグ
OriginalLength 元のメッセージの長さ


mqpgfはユーザーに許可されている全てのMQMDのフィールドを設定/参照できます。 特に指定をしない場合は、mqpgfはMQMDにデフォルトの値を設定します。MQはMQMD構造体の初期値をMQMD_DEFAULTで定義しています。 MQMD構造体の初期値の具体的な値については、後にご紹介しますが、必要に応じて製品のマニュアルもご参照ください。


テスト用のキューマネージャーの作成と基本的なテストの実施

それでは、実際にキューにメッセージをPUTし、そのメッセージのMQMDを確認してみます。

まず、テスト用のキューマネージャーとキューを一つ作成し、コマンド・サーバーを起動します。

fig 1.4

mqmグループに属するMQ管理ユーザーを使用して作業を行います。

キューマネージャー SampleQM を作成します。

※MQ for HP NonStopでは、crtmqm に渡すパラメータが他のプラットフォームと相違します。 詳しくは製品マニュアルをご参照お願いします。

$ crtmqm SampleQM
WebSphere MQ queue manager created.
....

作成したキューマネージャーを開始します。

$ strmqm SampleQM
IBM MQ queue manager 'SampleQM' starting.
IBM MQ queue manager 'SampleQM' started using V8.0.0.0.


※キューマネージャーの終了は "endmqm キューマネージャー名" です。

mqpcfはコマンド・サーバーを使用します。 新しいMQのバージョンではデフォルトでキューマネージャーの起動停止とこのコマンド・サーバーが同期しており、キューマネージャーを開始すればコマンド・サーバーも起動します。 もし、WebSphere MQ for HP NonStop 5.3 など古いレベルのMQを使用している場合や、ご利用の環境のキューマネージャーが意図的にコマンドサーバーを起動していない場合は、コマンドサーバーを手動で起動する必要があります。

$ strmqcsv SampleQM
IBM MQ command server started.


参考)キューマネージャーのSCMDSERVプロパティが"MANUAL"になっている場合"QMGR"(デフォルト)に変更するとQMGRの開始と同時にコマンドサーバーも起動するようになります。

   $ runmqsc SampleQM
   
   MQSC > dis qmgr scmdserv
   5 : dis qmgr scmdserv
   AMQ8408: Display Queue Manager details.
   QMNAME(SampleQM) SCMDSERV(MANUAL)
   
   MQSC > alter qmgr scmdserv(QMGR)
    6 : alter qmgr scmdserv(QMGR)
   AMQ8005: IBM MQ queue manager changed.
   MQSC > end
   $

テスト用のキュー SampleQ を作成します。

$ runmqsc SampleQM
....
MQSC > def ql('SampleQ')
1 : def ql('SampleQ')
AMQ8006: WebSphere MQ queue created.
MQSC > end
$

※MQSCコマンドで英小文字を使用する場合は、シングルクォートで文字列を囲むことが必要です。 そうしない場合は、全て英大文字に変換されてコマンドが実行されてしまいます。


Ex. 1.1 PUT/GETの実施およびメッセージのダンプ表示

それでは、mqpgfを使用してテストメッセージをPUTします。

$ mqpgf -qm SampleQM -q SampleQ -m "sample message"
[18/01/24 11:00:28] 1: message length: 14 put message : sample message

*オプションの説明
-qm: キューマネージャー
-q: ターゲット・キュー名
-m: PUTするメッセージ

※HP NonStopの場合は、デフォルトで要求が作業単位内(MQPMO_SYNCPOINT)で機能します。 それ以外のプラットフォームでは作業単位外(MQPMO_NO_SYNCPOINT)がデフォルトです。 その為、HP NonStopでPUT/GETを実行すると、mqpgfはMQCMIT() APIを呼び出し、PUT/GET要求をコミットします。 下記のメッセージが追加で表示されます。

MQCMIT success : CompCd=00 ReasonCd=00

次にPUTしたメッセージをブラウズモード(MQOO_BROWSE)でGETし、メッセージをダンプします。 ブラウズモードではメッセージを読み込んだ後、キューからメッセージを消去しません。

fig 1.5


テスト結果1.1

$ mqpgf -qm SampleQM -q SampleQ -br
message number: 1
*StrucId[MD ] Version[2] Report[0] MsgType[8] Expiry[-1] Feedback[0] Encoding[273] CodedCharSetId[819] Format[ ] Priority[0] Persistence[0] MsgId[0x414D512053616D706C65514D202020205A67E3D520002805] CorrelId[0x000000000000000000000000000000000000000000000000] BackoutCount[0] ReplyToQ[ ] ReplyToQMgr[SampleQM ] UserIdentifier[mqm ] AccountingToken[0x0534343033310000000000000000000000000000000000000000000000000006] ApplIdentityData[ ] PutApplType[13] PutApplName[mqpgf ] PutDate[20180124] PutTime[04085314] ApplOriginData[ ]
GroupId[0x000000000000000000000000000000000000000000000000] MsgSeqNumber[1] Offset[0] MsgFlags[0] OriginalLength[-1]
data length: 14
00000000: 7361 6D70 6C65 206D 6573 7361 6765 'sample message '

*オプションの説明
-br: ブラウズ・モードでメッセージをGET

-br指定時はMQMDに関してはフィールド毎に表示され、それ以外は16進ダンプ表示と可視文字のキャラクターが表示されます。 ここで表示されているMQMDがMQMD_DEFAULTを使用してPUTした時に設定された値です。

それぞれのフィールドについての説明では、タイプ、サイズ、初期値と、フィールドが入出力のどちらであるかも記載します。 ここでの入出力の意味について、混乱される場合があるので予め若干ご説明しておきます。

下記は、MQPUT()、MQGET() APIの呼び出し構文です。

MQPUT (Hconn, Hobj, MsgDesc, PutMsgOpts, BufferLength, Buffer, CompCode, Reason)
MQGET (Hconn, Hobj, MsgDesc, GetMsgOpts, BufferLength, Buffer, DataLength, CompCode, Reason)

MQPUT()、MQGET()のどちらもMsgDesc(MQMD)を引数に持っており、そしてどちらも入出力パラメータです。 そして、さらにMQMDのフィールド毎に入出力が決まっています。 これはAPIから見た入出力です。 例えば、MQMDはPutTimeというフィールドを持っています。 MQPUT()を呼び出した時、このフィールドはデフォルトでは出力フィールドで、入力(APIを呼び出し時に指定した値)は無視され、プット後に、メッセージが書き込まれた時刻がGMT(グリニッジ標準時)で設定されてアプリケーションに戻されます(出力)。 入力固定のフィールドの場合は、MQGET()を呼び出した後に示されている値は、呼び出し前に指定(入力)された値のままで、メッセージ上の値を示している(出力している)のではありません。

このページの先頭へ

MQMDのフィールド

それでは、MQMDのフィールドについて一つ々々説明します。

[ StrucId ]

タイプ: MQCHAR4
サイズ: 4バイト
初期値: MQMD_STRUC_ID_ARRAY("MD ")
入出力: 入力

MQMDの構造体のIDで、"MD "固定です。
MQの各構造体は、先頭にその構造体を示すIDフィールドが用意されています。

[ Version ]

タイプ: MQLONG
サイズ: 4バイト
初期値: MQMD_VERSION_1(1)
入出力: 入力

先にご説明した通り、現在MQMDにはMQMD_VERSION_1とMQMD_VERSION_2の2つがあります。 メッセージを作成元の相手先システムによって使用するバージョンが異なる場合がある為に、よくこのフィールドを読みだして確認できないかと聞かれることがあります。 しかし、残念ながらこのフィールドは最初にご説明した通り常に入力フィールドですので、メッセージ上の値を確認するということはできません。 MQGET()呼び出し後に設定されている値は、呼び出し前に設定した値と同じ値です。 ここで、「テスト結果1.1」を確認すると、"Version[2]"と表示されています。 mqpgfをデフォルトでPUTで使用した場合、MQMD_DEFAULTを使用し、その値はMQMD_VERSION_1です。 ただし、ダンプ表示をする時("-br", "-brv", "-dp"もしくは"-dpv"を指定した場合)、例外的にデフォルトの値ではなく、MQMD_VERSION_2を使用しています。 ですので、「テスト結果1.1」には入力で指定された値が表示されているだけです。


Ex. 1.2 MQMDのバージョンを指定してGET

特別にMQMD_VERSION_1を指定して、MQGET()を呼び出したい場合は、下記の様にコマンドライン引数に「MQMD_VERSION_1」を指定します。


テスト結果1.2

$ mqpgf -qm SampleQM -q SampleQ -br MQMD_VERSION_1
message number: 1
*StrucId[MD ] Version[1] Report[0] MsgType[8] Expiry[-1] Feedback[0] Encoding[273] CodedCharSetId[819] Format[ ] Priority[0] Persistence[0] MsgId[0x414D512053616D706C65514D202020205A67E3D520002805] CorrelId[0x000000000000000000000000000000000000000000000000] BackoutCount[0] ReplyToQ[ ] ReplyToQMgr[SampleQM ] UserIdentifier[mqm ] AccountingToken[0x0534343033310000000000000000000000000000000000000000000000000006] ApplIdentityData[ ] PutApplType[13] PutApplName[mqpgf ] PutDate[20180124] PutTime[04085314] ApplOriginData[ ]

GroupId[0x000000000000000000000000000000000000000000000000] MsgSeqNumber[1] Offset[0] MsgFlags[0] OriginalLength[-1]

data length: 14
00000000: 7361 6D70 6C65 206D 6573 7361 6765 'sample message '

*オプションの説明
MQMD_VERSION_1: MQMDのVer1を使用します。

これは、「テスト結果1.1」と同じメッセージをブラウズしたものです。 それはMsgIdの値が同じであることで確認できます(MsgIdについては後述)。 しかし、Versionは"Version[1]"になっています。 MQMD_VERSION_1を指定してメッセージをGETした場合、MQMD_VERSION_2固有のフィールドである、GroupId、MsgSeqNumber、Offset、MsgFlags、OriginalLengthを読みだそうとするとデフォルトの値が戻されます。 もしも、MQGET()でMQMD_VERSION_1が指定された時に、Version 2のフィールドが使用されていた(デフォルトの値ではなかった)場合、MQMDE(拡張メッセージ記述子)ヘッダが生成され、そのヘッダ内にMQMD_VERSION_2固有のフィールドの値が設定されます。 MQMDEの詳細についてはここでは省略します。 キュー上にMQMD_VERSION_1とMQMD_VERSION_2のメッセージが混在する場合は、常にMQMD_VERSION_2を指定してMQGET()を呼び出すこともできます。 MQMD_VERSION_1のメッセージをMQMD_VERSION_2を指定して読み出した場合、MQMD_VERSION_2固有のフィールドにはデフォルト値が設定されてアプリケーションに戻されます。

メッセージの
MQMD Version
メッセージの
V2フィールドの値
MQGET時指定
MQMD Version
V2フィールド
に返される値
MQMDE
MQMD_VERSION_1 - MQMD_VERSION_1 デフォルト値 なし
MQMD_VERSION_1 - MQMD_VERSION_2 デフォルト値 なし
MQMD_VERSION_2 デフォルト MQMD_VERSION_1 デフォルト値 なし
MQMD_VERSION_2 デフォルト以外 MQMD_VERSION_1 デフォルト値 生成*
MQMD_VERSION_2 任意 MQMD_VERSION_2 メッセージの値 なし
*MQMD V2フィールドの値が設定される。

fig 1.6

[ Report ]

タイプ: MQLONG
サイズ: 4バイト
初期値: MQRO_NONE(0)
入出力: MQGET()時:出力、MQPUT()時:入力

レポートオプションは、メッセージが正常に転送/処理されたかどうかを確認するためのレポート・メッセージを要求する為に使用します。 下記の種類があります。


レポートの種類 生成元
例外 MCA
有効期限 キューマネージャー
到着確認 (COA) キューマネージャー
送達時に確認 (COD) キューマネージャー
肯定アクション通知 (PAN) 受信側アプリケーション
否定アクション通知 (NAN) 受信側アプリケーション

PAN/NAN以外は、MCAまたはキューマネージャーが自動的にレポート・メッセージを生成します。 レポートメッセージの内容/結果は、後述する"Feedback"フィールドに示されます。 レポート・メッセージと送信元のメッセージの対応付けの為には、「相関 ID オプション」を使用します。

「レポートの種類」に、「到着確認 (COA)(MQRO_COA)」と「送達時に確認 (COD)(MQRO_COD_WITH_FULL_DATA)」を指定し、「相関 ID オプション」として MQRO_COPY_MSG_ID_TO_CORREL_ID(デフォルト)を使用する例を示します。 また、メッセージ・タイプには MQMT_REQUEST(応答を必要とするメッセージ)を指定します。

MQRO_COA、MQRO_COD_WITH_FULL_DATAはMQMD.ReportフィールドにそれぞれのORで設定します。 mqpgfは引数にこの2つを指定すると自動的にそれを行います。 MQRO_COPY_MSG_ID_TO_CORREL_IDは値が0x00000000で定義されておりMQRO_PASS_CORREL_IDを設定しない場合に有効になる為、直接指定はしません。


対向側キューマネージャーとの接続の作成

テスト用に対向側のキューマネージャーとキュー、リスナー、チャネルを作成します。 キューマネージャーは環境がなければ同一のマシンに作成して構いません。

fig 1.7

対向側のキューマネージャー RemoteQM を作成します。

※MQ for HP NonStopでは、crtmqm に渡すパラメータが他のプラットフォームと相違します。 詳しくは製品マニュアルをご参照お願いします。

$ crtmqm RemoteQM
WebSphere MQ queue manager created.
....

作成したキューマネージャーを開始します。

$ strmqm RemoteQM
IBM MQ queue manager 'RemoteQM' starting.
IBM MQ queue manager 'RemoteQM' started using V8.0.0.0.

※コマンドサーバーが起動されていない場合はSampleQMと同様に起動しておきます。

テスト用のキュー RemoteQ を作成します。

$ runmqsc RemoteQM
....
MQSC > def ql('RemoteQ')
1 : def ql('RemoteQ')
AMQ8006: IBM MQ queue created.

それぞれのキューマネージャーでリスナーを作成、開始します。 RemoteQMを別のマシンに作成した場合は、ポートはSampleQMと同じ1414(デフォルト)で構いません。 リスナー定義のパラメータをcontrol(qmgr)にすると、キューマネージャーの起動/停止に合わせてリスナーも起動/停止するようになります。

※WebSphere MQ5.3 for HP NonStopの場合、リスナーは通常Pathwayのサーバー・クラスとして構成します。

<< SampleQMでの作業 >>

リスナーを作成します。

MQSC > def listener(listener) trptype(tcp) port(1414) control(qmgr)
1 : def listener(listener) trptype(tcp) port(1414) control(qmgr)
AMQ8626: IBM MQ listener created.

作成したリスナーを開始します。

$ mqpcf stalsn -qm SampleQM -ln LISTENER
Listener Start Success. Listener Name : LISTENER

*オプションの説明
stalsn: "Start Channel Listener"コマンドを実行
-ln: リスナー名

※WebSphere MQ5.3 for HP NonStopの場合は、runmqscからデフォルトのTCP/IPリスナーを起動します。
$ runmqsc SampleQM
MQSC >sta listener
1 : sta listener
AMQ8021: WebSphere MQ Listener program started.
MQSC >end

リスナーが開始したことを確認します。

$ mqpcf lsst -qm SampleQM -ln LISTENER STATUS
1: LISTENER(LISTENER) STATUS(RUNNING)

*オプションの説明
lsst: "Inquire Channel Listener Status"コマンドを実行
STATUS: STATUSフィールドの表示

※mqpcfは、表示するフィールド名(上記では"STATUS")をオプション無しで指定することができます。 その場合、そのPCFコマンドで必ず返されるパラメータと指定したフィールド名のみが表示されます。


<< RemoteQMでの作業 >>

MQSC > def listener(listener) trptype(tcp) port(1415) control(qmgr)
1 : def listener(listener) trptype(tcp) port(1415) control(qmgr)
AMQ8626: IBM MQ listener created.

以下、SampleQMと同様にリスナーを開始してステータスが"RUNNING"になることを確認します。

次に2つのキューマネージャー間にメッセージ・チャネルを双方向に作成します。 チャネル名は、"Sample.TO.Remote"と"Remote.TO.Sample"にします。 チャネルの両端は同じ名前であることが必要です。 下記の様に構成します。 作成するチャネルのタイプは送信側が"SDR"、受信側が"RCVR"です。

SampleQM RemoteQM
Sample.TO.Remote(SDR) -> Sample.TO.Remote(RCVR)
Remote.TO.Sample(RCVR) <- Remote.TO.Sample(SDR)

<< SampleQMでの作業 >>

チャネル伝送用のキュー(伝送キュー)を作成します。 ここでは相手先のキューマネージャー名と同じ名前にします。

MQSC > def ql('RemoteQM') usage(xmitq)
4 : def ql('RemoteQM') usage(xmitq)
AMQ8006: IBM MQ queue created.

送信側チャネルを作成します。 connameには相手先のIPアドレスまたはホスト名と、リスナー作成時に指定したポートを指定します。

MQSC > def chl('Sample.TO.Remote') chltype(sdr) conname('localhost(1415)') xmitq('RemoteQM')
8 : def chl('Sample.TO.Remote') chltype(sdr) conname('localhost(1415)') xmitq('RemoteQM')
AMQ8014: IBM MQ channel created.

受信側チャネルを作成します。

MQSC > def chl('Remote.TO.Sample') chltype(rcvr)
11 : def chl('Remote.TO.Sample') chltype(rcvr)
AMQ8014: IBM MQ channel created.

リモートキューのローカル定義、つまりRemoteQM上のキューRemoteQを指す定義をSampleQM上に作成します。

MQSC > def qr('RemoteQ') rqmname('RemoteQM') rname('RemoteQ')
10 : def qr('RemoteQ') rqmname('RemoteQM') rname('RemoteQ')
AMQ8006: IBM MQ queue created.

リモートキューのローカル定義は、XMITQというパラメータを持っていますが、ここでは指定しません。 指定しない場合、ターゲット・キュー・マネージャーと同じ名前の伝送キューが使用されます。(今回伝送キュー名は相手先のキューマネージャーと同じ名前で作成しています。)

<< RemoteQMでの作業 >>

チャネル伝送用のキュー(伝送キュー)を作成します。 相手先のキューマネージャー名と同じ名前にします。

MQSC > def ql('SampleQM') usage(xmitq)
4 : def ql('SampleQM') usage(xmitq)
AMQ8006: IBM MQ queue created.

送信側チャネルを作成します。

MQSC > def chl('Remote.TO.Sample') chltype(sdr) conname('localhost(1414)') xmitq('SampleQM')
5 : def chl('Remote.TO.Sample') chltype(sdr) conname('localhost(1414)') xmitq('SampleQM')
AMQ8014: IBM MQ channel created.

受信側チャネルを作成します。

MQSC > def chl('Sample.TO.Remote') chltype(rcvr)
6 : def chl('Sample.TO.Remote') chltype(rcvr)
AMQ8014: IBM MQ channel created

作成できたら、それぞれの送信側からチャネルを開始し、ステータスが"RUNNING"になることを確認します。

<< SampleQMでの作業 >>

$ mqpcf sta -qm SampleQM -c Sample.TO.Remote
Channel Start Success. Channel Name : Sample.TO.Remote

*オプションの説明
sta: "Start Channel"コマンドを実行
-c: チャネル名

$ mqpcf chs -qm SampleQM -c Sample.TO.Remote STATUS
1: CHLINSTYPE(CURRENT) CHANNEL(Sample.TO.Remote) STATUS(RUNNING) CHLTYPE(SDR) CONNAME(127.0.0.1(1415)) RQMNAME(RemoteQM) STOPREQ(NO) SUBSTATE(MQGET) XMITQ(RemoteQM)

*オプションの説明
chs: "Inquire Channel Status"コマンドを実行

<< RemoteQMでの作業 >>

同様に'Remote.TO.Sample'を開始し、ステータスを確認します。

$ mqpcf sta -qm RemoteQM -c Remote.TO.Sample
Channel Start Success. Channel Name : Remote.TO.Sample

$ mqpcf chs -qm RemoteQM -c Remote.TO.Sample STATUS
1: CHLINSTYPE(CURRENT) CHANNEL(Remote.TO.Sample) STATUS(RUNNING) CHLTYPE(SDR) CONNAME(127.0.0.1(1414)) RQMNAME(SampleQM) STOPREQ(NO) SUBSTATE(MQGET) XMITQ(SampleQM)

リモートキューのローカル定義が正しく定義されており、'Sample.TO.Remote'でメッセージが正常に転送できるか確認します。 SampleQM上のリモートキューのローカル定義である RemoteQ へ任意のメッセージをPUTします。

$ mqpgf -qm SampleQM -q RemoteQ -m "transfer message"
[18/01/24 18:12:28] 1: message length: 16 put message : transfer message

RemoteQM上のローカルキューである RemoteQ 上のメッセージ数 (CURDEPTH) が"1"になっており、転送が正常に実行されたことを確認します。

$ mqpcf ques -qm RemoteQM -q RemoteQ CURDEPTH
1: QUEUE(RemoteQ) TYPE(QUEUE) CURDEPTH(1)

*オプションの説明
ques: "Inquire Queue Status"コマンドを実行
CURDEPTH: CURDEPTHフィールドの表示

メッセージの到着が確認できたら、一旦、メッセージをクリアしておきます。

$ mqpcf clr -qm RemoteQM -q RemoteQ
Clear Queue Success. Queue Name : RemoteQ

*オプションの説明
clr: "Clear Queue"コマンドを実行

最後に、レポートメッセージの受信用のキューを作成します。

<< SampleQMでの作業 >>

$ runmqsc SampleQM
....
MQSC > def ql('ReportQ')
1 : def ql('ReportQ')
AMQ8006: IBM MQ queue created.

RemoteQ側には、レポート・メッセージ送信用のリモートキューのローカル定義は必要ありません。 リモートキューのローカル定義が存在しない場合、ターゲット・キュー・マネージャーと同じ名前を持つ伝送キューが選択されます。


Ex. 1.3 レポート・メッセージのリクエストと受信

それでは、早速テストしてみます。 下記のコマンドを実行してください。 「相関 ID オプション」のMQRO_COPY_MSG_ID_TO_CORREL_IDは前述した通り値0x00000000なので指定は省略します。

$ mqpgf -qm SampleQM -q RemoteQ -m "mqmd.Report test" -rq ReportQ MQRO_COA MQRO_COD_WITH_FULL_DATA MQMT_REQUEST
[18/01/26 14:31:54] 1: message length: 16 put message : mqmd.Report test

*オプションの説明
-rq: MQMD.ReplyToQを指定
MQRO_COA: 到着確認 (COA)(元データをレポートデータに組み込まない)
MQRO_COD_WITH_FULL_DATA: 送達時に確認 (COD)(全ての元データをレポートデータに組み込む)
MQMT_REQUEST: 応答を必要とするメッセージ

ターゲット・キューマネージャーのRemoteQへメッセージが到着したことを確認します。

$ mqpcf ques -qm RemoteQM -q RemoteQ -t CURDEPTH
[18/01/26 14:32:11] 1: QUEUE(RemoteQ) TYPE(QUEUE) CURDEPTH(1)

*オプションの説明
-t: コマンド実行時間を表示

送信元には、レポート・メッセージ「到着確認 (COA)(MQRO_COA)」が送信されています。内容は後で確認します。

$ mqpcf ques -qm SampleQM -q ReportQ -t CURDEPTH
[18/01/26 14:32:17] 1: QUEUE(ReportQ) TYPE(QUEUE) CURDEPTH(1)

まず、ターゲット・キューマネージャーのRemoteQのメッセージをダンプしてみます。


テスト結果1.3.1

$ mqpgf -qm RemoteQM -q RemoteQ -brv
message number: 1
*StrucId[MD ] Version[2] Report[14592] MsgType[1] Expiry[-1] Feedback[0] Encoding[273] CodedCharSetId[819] Format[ ] Priority[0] Persistence[0] MsgId[0x414D512053616D706C65514D202020205A6AB4A020002902] CorrelId[0x000000000000000000000000000000000000000000000000] BackoutCount[0] ReplyToQ[ReportQ ] ReplyToQMgr[SampleQM ] UserIdentifier[mqm ] AccountingToken[0x0534343033310000000000000000000000000000000000000000000000000006] ApplIdentityData[ ] PutApplType[13] PutApplName[mqpgf ] PutDate[20180126] PutTime[05315438] ApplOriginData[ ]

GroupId[0x000000000000000000000000000000000000000000000000] MsgSeqNumber[1] Offset[0] MsgFlags[0] OriginalLength[-1]

data length: 16
00000000: 6D71 6D64 2E52 6570 6F72 7420 7465 7374 'mqmd.Report test'

*オプションの説明
-brv: 詳細ブラウズ・モードでメッセージをGET

Reportには 14592 が設定されています。これは16進数の0x3900です。 これは、指定した下記パラメータの"OR"に相当します。

MQRO_COA 0x00000100 MQRO_COD_WITH_FULL_DATA 0x00003800 MQRO_COPY_MSG_ID_TO_CORREL_ID 0x00000000

MsgTypeには、指定した通り MQMT_REQUEST に対応する下記の値"1"が設定されています。

MQMT_REQUEST 1

ReplyToQは、レポートを受け取るキューで、引数で指定した通り"ReportQ"が設定されています。 ReplyToQMgrは、レポートを受け取るキューマネージャーで、特に指定しなかったので、ローカルキューマネージャーである"SampleQM"が設定されています。

ここで、MsgIdに設定されている値を確認しておきます。

今度はRemoteQMのRemoteQのメッセージを、ブラウズではなく、MQGETします。

$ mqpgf -qm RemoteQM -q RemoteQ
[18/01/26 14:32:30] 1: message length: 16 get message : mqmd.Report test

SampleQMが「送達時に確認 (COD)(MQRO_COD_WITH_FULL_DATA)」を受信したか確認します。

$ mqpcf ques -qm SampleQM -q ReportQ -t CURDEPTH
[18/01/26 14:32:35] 1: QUEUE(ReportQ) TYPE(QUEUE) CURDEPTH(2)

CURDEPTHが2件になっています。

「到着確認 (COA)」は相手先のキューに到着した時に生成され、「送達時に確認 (COD)」は相手先のキューからメッセージが処理(MQGET)された時に生成されることが分かったと思います。

それではSampleQMが受け取った2つのレポート・メッセージを確認します。

mqpgfに"-r"オプションを指定すると、キュー上のメッセージを繰り返し(全て)GETします。


テスト結果1.3.2

$ mqpgf -qm SampleQM -q ReportQ -brv -r
message number: 1
*StrucId[MD ] Version[2] Report[0] MsgType[4] Expiry[-1] Feedback[259] Encoding[273] CodedCharSetId[819] Format[ ] Priority[0] Persistence[0] MsgId[0x414D512052656D6F7465514D202020205A6AB4B220002306] CorrelId[0x414D512053616D706C65514D202020205A6AB4A020002902] BackoutCount[0] ReplyToQ[ ] ReplyToQMgr[RemoteQM ] UserIdentifier[mqm ] AccountingToken[0x0534343033310000000000000000000000000000000000000000000000000006] ApplIdentityData[ ] PutApplType[7] PutApplName[RemoteQM ] PutDate[20180126] PutTime[05315443] ApplOriginData[ ]

GroupId[0x000000000000000000000000000000000000000000000000] MsgSeqNumber[1] Offset[0] MsgFlags[0] OriginalLength[-1]

data length: 0
00000000: ' '

message number: 2
*StrucId[MD ] Version[2] Report[0] MsgType[4] Expiry[-1] Feedback[260] Encoding[273] CodedCharSetId[819] Format[ ] Priority[0] Persistence[0] MsgId[0x414D512052656D6F7465514D202020205A6AB4B220002806] CorrelId[0x414D512053616D706C65514D202020205A6AB4A020002902] BackoutCount[0] ReplyToQ[ ] ReplyToQMgr[RemoteQM ] UserIdentifier[mqm ] AccountingToken[0x0534343033310000000000000000000000000000000000000000000000000006] ApplIdentityData[ ] PutApplType[7] PutApplName[RemoteQM ] PutDate[20180126] PutTime[05323011] ApplOriginData[ ]

GroupId[0x000000000000000000000000000000000000000000000000] MsgSeqNumber[1] Offset[0] MsgFlags[0] OriginalLength[-1]

data length: 16
00000000: 6D71 6D64 2E52 6570 6F72 7420 7465 7374 'mqmd.Report test'

no message available : ReportQ CompCd=02 ReasonCd=2033

*オプションの説明
-r: キュー上のメッセージを繰り返しGET

2件とも MsgTypeは"4"に設定されています。 これは下記MQMT_REPORTにあたり、レポート・メッセージであることを示しています。

MQMT_REPORT 4

Feedbackには、1件目は"259"、2件目は"260"が設定されています。 これは、下記の値に対応しており1件目はCOA、2件目はCODで生成されたことを示しています。

MQFB_COA 259
MQFB_COD 260

次に送信メッセージ「テスト結果1.3.1」のMsgIdとレポートメッセージのCorrelIdを確認します。

Send Messge MsgId :[0x414D512053616D706C65514D202020205A6AB4A020002902] Report Message(1) CorrelId:[0x414D512053616D706C65514D202020205A6AB4A020002902] Report Message(2) CorrelId:[0x414D512053616D706C65514D202020205A6AB4A020002902]

デフォルトの MQRO_COPY_MSG_ID_TO_CORREL_ID の挙動は、送信メッセージのMsgIdをレポートメッセージのCorrelIdにコピーすることです。 その通りに同じ値がコピーされていることが確認できます。 詳細は後述しますが、MQGET()は特定のCorrelIdを持つメッセージのみを待機してGETすることができます。 そのことと合わせてこの仕組みは送信メッセージと応答メッセージの紐づけの為に頻繁に利用されるMQの機能です。

最後にアプケーション・データですが、MQRO_COAを指定し元データを要求しなかった1件目は"data length: 0"となっており、MQRO_COD_WITH_FULL_DATAを指定して全ての元データをレポートデータに組み込む様に指定した2件目はそのまま('mqmd.Report test')がレポートメッセージにも付加されてます。 "_WITH_DATA"をつけると、100バイトのみ、"_WITH_FULL_DATA"をつけると全てのアプリケーション・データ付きのレポート・メッセージが作成されます。

fig 1.7

[ MsgType ]

タイプ: MQLONG
サイズ: 4バイト
初期値: MQMT_DATAGRAM(8)
入出力: MQGET()時:出力、MQPUT()時:入力

下記の種類があります。

MQMT_DATAGRAM 8 応答が不要なメッセージ
MQMT_REQUEST 1 応答が必要なメッセージ
MQMT_REPLY 2 要求に対する応答メッセージ
MQMT_REPORT 4 レポートメッセージ

既に「テスト結果1.1, 1.2」ではMQMT_DATAGRAM(8)、「テスト結果1.3.1」ではMQMT_REQUEST(1)、「テスト結果1.3.2」ではMQMT_REPORT(4)と異なるMsgTypeを使用して(されて)います。

実際運用されているシステムのMQメッセージには、これらの値が正確に指定されていない場合が時々見られます。 混乱を防ぐためにも、MQPUT()時には、そのメッセージを正確に表すMsgTypeを指定するようにします。

このページの先頭へ

このページの先頭へ