実践習得 IBM MQの基本
メッセージ記述子(MQMD)(1)
※本連載は最新のmqpgf/mqpcfに基づいて改定されることがあります。 常に最新バージョンをダウンロードしてご使用ください。
本連載では、当社で作成/提供しているmqpgf/mqpcfを使用したIBM MQの機能検証を通して、WebSphere MQ/IBM MQの基本について解説します。
mqpgfはMQが提供するAPIであるMQIを利用して様々なテストが実施できるプログラムです。 エージェントを介してキューマネージャーとやり取りをします。
mqpcfはMQの管理APIであるMQAIを使用して、コマンドサーバーとPCFコマンドを送受信し、MQオブジェクトへの操作を実行、その状態を確認することができるプログラムです。
必要に応じて、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)('*': ReplyToQ, '**': + ReplyToQMgr)
-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
-wp : wait time to next processing
-ca : continue processing after MQCONN(X) fails
-ac : applend the counter to message automatically
-cr : The number of connection retry
-y : Invoke yield function after every MQI call
Platform-specific options :
-gt : Using Global UOW for NSK
-gti : Using Global UOW for NSK(TMFAPI: per PUT/GET)
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 -la : LocalAddress
-cl : CertificateLabel -cs : SSLCipherSpec
-er : SSLPeerName
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(
※"-v" を指定するとバージョン情報が表示されます。 $ mqpgf -v ・・・・ [ License information ] Expires 2021.10.31 version 1.4.2.8 2021/03/10 library version 1.0.0.1 2021/03/10
※さらに"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 -wi : The maximum time(sec) that the MQAI waits for each reply message -cu : UserId -ci : Password select parameters to display(e.g. mqpcf chs .. SUBSTATE MCASTAT) [ License information ] Expires 2021.11.30 version 1.4.0.11 2021.09.10 library version 1.0.0.1 2021/03/10
また、実行するコマンドのみを指定すると、そのコマンドで指定可能なオプションが表示されます。 $ mqpcf put USAGE : mqpcf {put | get} {enable | disable} -qm Qmgr -q Queue
メッセージ記述子(MQMD)概要
MQメッセージには、必ずメッセージ記述子(MQMD: MQ Messege Descriptor)という構造体が付加されます。
この構造体の各フィールドを設定、参照することで様々なMQの機能が利用できます。
このことをよく理解しないままメッセージやシステムの連携を設計したために、その機能の恩恵に授かることができず、MQが提供するものと全く同じ様な機能をアプリケーションやシステム側に実装している例を多く見かけます。
MQ連携の設計を開始し、メッセージのフォーマットを決定する前に、必ずその機能を抑えておきます。
下記が、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を確認してみます。
まず、テスト用のキューマネージャーとキューを一つ作成し、コマンド・サーバーを起動します。
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し、メッセージをダンプします。
ブラウズモードではメッセージを読み込んだ後、キューからメッセージを消去しません。
テスト結果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 | メッセージの値 | なし |
[ 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を設定しない場合に有効になる為、直接指定はしません。
対向側キューマネージャーとの接続の作成
テスト用に対向側のキューマネージャーとキュー、リスナー、チャネルを作成します。 キューマネージャーは環境がなければ同一のマシンに作成して構いません。
対向側のキューマネージャー 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"をつけると全てのアプリケーション・データ付きのレポート・メッセージが作成されます。
[ 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を指定するようにします。