実践習得 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を指定するようにします。