Python MQ接口
Python MQ接口(PyMQI)是IBM®WebSphere®MQ的开源Python扩展库。 PyMQI通过提供易于使用的Python界面扩展了MQI库。 ,它包括一个用C编写的用于访问MQI C库的低级库,以及一个位于低级库之上的,面向Python程序员的高级面向对象的接口。 PyMQI使开发人员可以在WebSphere MQ工具和解决方案中使用强大的Python语言,从而为所有WebSphere MQ开发人员提供Python的好处。 Python主页上的一句话引述了这一点:
“ Python是一种动态的面向对象的编程语言...带有大量的标准库,并且可以在几天之内学会...程序员报告了可观的生产率提高...该语言鼓励开发更高质量,更易维护的代码”。
编译PyMQI
PyMQI是作为源分发的,因此在将包下载并解压缩到目录后,您需要做的第一件事就是对其进行编译。 通常,Python扩展使用与Python本身相同的编译器进行编译。 Python发行版是使用Microsoft®Visual Studio构建的,如果安装了正确的版本,则可以使用命令python setup.py build server
(对于WebSphere MQ Server V5)或python setup.py build client
(对于WebSphere MQ Client)来构建PyMQI。 V5)
如果您没有Microsoft Visual Studio并且使用的是WebSphere MQ V6,则在使用PyMQI之前,编译需要其他步骤:
- 为Windows®C编译器安装MinGW32(极简GNU)。
- 修改WebSphere MQ C头文件。
- 编译PyMQI。
- 安装PyMQI作为Python扩展。
编译要求在您的计算机中安装Windows,Python V2.5.1和WebSphere MQ V5或V6 Server或Client。 对于本文,环境包括Windows XP 2003,WebSphere MQ V6 Server和Python V2.5.1。
安装MinGW32
下载MinGW-5.1.3.exe并执行以开始安装。 安装程序会从Web下载所需的软件包并进行安装。 完整安装会安装所有编译器,尽管最低安装可能就足够了。 安装MinGW之后,将MinGW \ bin目录添加到PATH环境变量中。
修改WebSphere MQ C头文件
如果使用的是WebSphere MQ V6,则需要对MQ C头文件进行一些小的更改,因为MinGW无法理解几个64位类型定义。
在文本编辑器中打开头文件<MQ_INSTALL_DIR>\Tools\c\include\cmgc.h
,然后找到清单1中的代码:
清单1.要替换的Typedef
typedef _int64 MQINT64;
typedef unsigned _int64 MQUINT64;
删除或注释掉清单1中的typedef。 然后添加清单2中所示的新的typedef,并保存文件。
清单2.要替换的Typedef
typedef long long _int64;
typedef unsigned long long _uint64;
typedef _int64 MQINT64;
typedef _uint64 MQUINT64;
编译PyMQI
在提取PyMQI源文件的目录中打开命令提示符,并使用命令setup.py build -cmingw32 server
编译PyMQI。 该命令编译PyMQI扩展,以准备将其安装为Python扩展。
将PyMQI安装为Python扩展
要将PyMQI安装为Python扩展,请使用命令setup.py install --skip-build
。 PyMQI现在已安装并可以使用。
用PyMQI编程
PyMQI具有多个一起使用的模块:
- CMQC和CMQCFC定义MQI常数。
- pymqe是用C编写的MQI的低级Python扩展接口。
- pymqi是使用pymqe的MQ的高级Python接口。
实际上,在开发WebSphere MQ应用程序时使用pymqi。 清单3显示了将消息放入队列的最少代码:
清单3.将消息放入队列
import pymqi
qmgr = pymqi.QueueManager()
putQ = pymqi.Queue(qmgr, 'QNAME')
putQ.put('Hello world!')
从队列中获取消息也很简单:
清单4.从队列获取消息
import pymqi
qmgr = pymqi.QueueManager()
getQ = pymqi.Queue(qmgr, 'QNAME')
print 'Message:', getQ.get()
PyMQI支持主要的MQI调用,例如MQCONN/MQCONNX, MQDISC, MQOPEN, MQCLOSE, MQPUT, MQGET,
等。 PCF命令以及事务也受支持。
下一部分包括一些用PyMQI编写的有用工具:PyPut,PyGet和PyBrowse。 在执行任何程序之前,将创建一个名为TEST_QM的WebSphere MQ队列管理器和一个名为TESTQ的本地队列。
PyMQI实用程序
本节包含PyMQI的示例,并为WebSphere MQ开发人员和管理员提供有用的工具。 PyPut是一种将一个或多个消息(指定为参数或文件)放入队列的工具。 PyGet从队列中获取消息,并将其打印到系统中,或者一次发送一个消息,或一次将所有消息保存到文件中。 PyBrowse浏览消息-它也可以浏览队列中的特定消息或以后进先出(LIFO)顺序浏览消息,而不是常规的先进先出(FIFO)顺序。
您可以下载示例代码并按原样使用-只需将代码复制并粘贴到文件中并执行即可。
PyPut
清单5包含PyPut的代码。 除了pymqi,PyPut还使用Python模块OptionParser定义命令行选项:
清单5. PyPut.py
from pymqi import *
import sys, os
from optparse import OptionParser
usage='Usage: %s [options] QMGRNAME QNAME (MSSG | FILE_NAME) [(MSG | FILE_NAME)...]'
def main(argv=None):
if argv is None:
argv = sys.argv
try:
(options,args)=parseOptions()
if len(args)<3:
raise MQException(1)
qmgrName=args[0]
qName=args[1]
message=args[2]
messages=args[2:]
#open queue in specified queue manager
qmgr = QueueManager(qmgrName)
putQ = Queue(qmgr, qName)
#loop through arguments and put messages
#to a queue
for message in messages:
#if -f options is specified, arguments are file names
if options.msgIsFile==True:
if os.path.exists(message)==False:
raise MQException(3)
#read file contents to a message-variable
f=open(message)
content=f.readlines()
f.close()
#variable 'content' is a list of lines in the specified file
#join lines in content-variable together as one string
message=''.join(content)
#single method call to put message to a queue
putQ.put(message)
if not options.quiet==True:
print 'Message sent.'
except MQException, err:
#if exception happens, print error message and exit
print '[ERROR]',err.errorCodes[err.msg]
print usage % (sys.argv[0],)
return err.code
except MQMIError,err:
print err
return -1
def parseOptions():
parser = OptionParser(usage=(usage % ('%prog',)))
parser.add_option("-f",
"--file",
action="store_true",
dest="msgIsFile",
help="Use file specified as third argument as message .", )
parser.add_option("-q",
"--quiet",
action="store_true",
dest="quiet",
help="Quiet mode.", )
(options, args) = parser.parse_args()
return (options, args)
#MQException class that holds application specific error codes
#and error messages
class MQException(Exception):
errorCodes={'1': 'QMGRNAME, QNAME or MESSAGE missing.',
'2': 'Too many arguments.',
'3': 'File does not exist.',
'4': 'QMGRNAME or QNAME.',
}
code=0
def __init__(self, code):
self.code=code
self.msg = str(code)
if __name__ == "__main__":
sys.exit(main())
上面清单5中的代码主要是应用程序逻辑,实际的PyMQI代码只有几行:获取队列管理器,获取队列,将消息放入队列以及错误处理。 这显示了PyMQI的强大功能:在Python程序中使用WebSphere MQ是微不足道的,Python的内置功能使开发工具非常容易。 例如,读取文件内容是四行代码,并且可能是您自己的工具箱中的函数。 Python OptionParser模块中有-h和-help选项,以打印命令行帮助。 例如, PyPut.py -h
可帮助PyPut:
Usage: PyPut.py [options] QMGRNAME QNAME (MSSG | FILE_NAME) [(MSG | FILE_NAME)...]
Options:
-h, --help show this help message and exit
-f, --file Use file specified as third argument as message .
-q, --quiet Quiet mode.
使用命令PyPut.py TEST_QM TESTQ message1 message2
。 此命令将两个消息放入队列管理器TEST_QM中名为TESTQ的队列。
PyPut.py也可以在脚本中使用。 例如: @for %i in ("*.txt") do call "PyPut.py" "-f" "TEST_QM" "TESTQ" "%i"
循环当前目录中的所有txt文件,并将每个目录的内容放入txt文件放入队列。
PyGet
PyGet.py与PyPut.py相似,除了消息被打印到系统输出或写入文件外。 清单6显示了PyGet.py的代码:
清单6. PyGet.py
from pymqi import *
import sys, os
from optparse import OptionParser
usage='Usage: %s [options] QMGRNAME QNAME'
def main(argv=None):
if argv is None:
argv = sys.argv
try:
(options,args)=parseOptions()
if len(args)>2:
raise MQException(2)
if len(args)<2:
raise MQException(4)
qmgrName=args[0]
qName=args[1]
#open queue manager and queue
qmgr = QueueManager(qmgrName)
Q = Queue(qmgr, qName)
if options.all==True:
moreMessages=True
while(moreMessages):
try:
#get single message from queue
message=Q.get()
printMessage(options,message)
except MQMIError,err:
if err.reason==2033:
moreMessages=False
if not options.quiet==True:
if not options.noDelim==True:
print '-'*70
print 'No messages.'
else:
raise
else:
message=Q.get()
printMessage(options,message)
except MQException, err:
print '[ERROR]',err.errorCodes[err.msg]
print usage % (sys.argv[0],)
return err.code
except MQMIError,err:
if err.reason==2033:
#no messages
if not options.quiet==True:
print 'No messages.'
else:
print err
return err.reason
def printMessage(options,message):
if options.saveFile==True:
seq=1
if not options.fileName==None:
fileName=options.fileName
else:
fileName='message'
fileName='%s%05d' %(fileName,seq)
while os.path.exists(fileName)==True:
fileName=fileName[:-5]
seq=seq+1
fileName='%s%05d' %(fileName,seq)
f=open(fileName,'w')
f.write(message)
f.close()
else:
if not options.quiet==True:
if not options.noDelim==True:
print '-'*70
print message
def parseOptions():
parser = OptionParser(usage=(usage % ('%prog',)))
parser.add_option("-f",
"--file",
action="store_true",
dest="saveFile",
help="Save message to a file with name 'message'.", )
parser.add_option("-n",
"--file-name",
dest="fileName",
help="File name for message. Use with -f option.", )
parser.add_option("-A",
"--all",
action="store_true",
dest="all",
help="Get all messages. If messages are saved to file,"+
" messages have sequence number in the file name.", )
parser.add_option("-q",
"--quiet",
action="store_true",
dest="quiet",
help="Quiet mode.", )
parser.add_option("",
"--no-delim",
action="store_true",
dest="noDelim",
help="Do not print message delimeter.", )
(options, args) = parser.parse_args()
return (options, args)
#MQException class that holds application specific error codes
#and error messages
class MQException(Exception):
errorCodes={'1': 'QMGRNAME, QNAME or MESSAGE missing.',
'2': 'Too many arguments.',
'3': 'File does not exist.',
'4': 'QMGRNAME or QNAME missing.',
}
code=0
def __init__(self, code):
self.code=code
self.msg = str(code)
if __name__ == "__main__":
sys.exit(main())
就像在PyPut.py中一样,实际的WebSphere MQ特定代码只有几行,而应用程序逻辑则使用了大多数源代码。 要获得有关PyGet的帮助,请键入PyPut.py -h
:
Usage: PyGet.py [options] QMGRNAME QNAME
Options:
-h, --help show this help message and exit
-f, --file Save message to a file with name 'message'.
-n FILENAME, --file-name=FILENAME
File name for message. Use with -f option.
-A, --all Get all messages. If messages are saved to file,
messages have sequence number in the file name.
-q, --quiet Quiet mode.
--no-delim Do not print message delimeter.
PyGet.py可以使用几个选项。 如果没有选项,它将从队列中检索一条消息并将其打印到系统中。 使用-A选项,将从队列中检索所有消息,这对于清除队列很有用,在开发过程中您可能需要经常这样做。 例如: PyGet.py -A -q TEST_QM TESTQ
清除TESTQ而不打印任何内容到系统中。 当脚本中包含此命令时,单个命令将清除队列。
Py浏览
PyBrowse.py具有与PyGet.py类似的功能,但是它浏览消息并且没有静默模式。 其他选项是--index, --lifo, --depth
。 index选项浏览指定索引中的消息-索引0是第一条消息,索引1是第二条消息,依此类推。 lifo选项在将消息打印到系统之前,先反转队列中的消息,并且可用于浏览放入队列中的最后一条消息。 depth选项使用inquery函数返回队列的当前深度。
PyBrowse的源代码:
清单7. PyBrowse.py
from pymqi import *
import sys, os
from optparse import OptionParser
usage='Usage: %s [options] QMGRNAME QNAME'
def main(argv=None):
if argv is None:
argv = sys.argv
try:
(options,args)=parseOptions()
if len(args)>2:
raise MQException(2)
if len(args)<2:
raise MQException(4)
qmgrName=args[0]
qName=args[1]
#open queue manager
qmgr = QueueManager(qmgrName)
gqdesc = od( ObjectName=qName)
Q= Queue( qmgr, gqdesc)
qDepth=Q.inquire(CMQC.MQIA_CURRENT_Q_DEPTH)
if options.depth==True:
#open queue for inquire
print 'Current depth: %d' % qDepth
return 0
if not options.index==None:
if int(options.index)>=qDepth:
raise MQException(5)
#open queue for browsing
Q= Queue( qmgr, gqdesc, CMQC.MQOO_BROWSE)
msgDesc = md()
getOpts = gmo(Options = CMQC.MQGMO_BROWSE_NEXT)
getOpts.WaitInterval = CMQC.MQWI_UNLIMITED
messages = []
try:
while 1:
msg = Q.get(None, msgDesc, getOpts)
messages.append(msg)
if not options.all==True and options.index==None and not options.lifo==True:
break
# null MsgId and CorrelId, or cursor won't move up
# the Q
msgDesc['MsgId'] = ''
msgDesc['CorrelId'] = ''
except MQMIError, me:
#assume that error is raised when there are
#no more messages in queue
pass
if options.lifo==True:
messages.reverse()
if not options.all==True and options.index==None:
messages=messages[0:1]
if not options.index==None:
printMessage(options,messages[int(options.index)])
else:
for message in messages:
printMessage(options,message)
except MQException, err:
print '[ERROR]',err.errorCodes[err.msg]
print usage % (sys.argv[0],)
return err.code
except MQMIError,err:
if err.reason==2033:
#no messages
print 'No messages.'
else:
print err
return err.reason
def printMessage(options,message):
if options.saveFile==True:
seq=1
if not options.fileName==None:
fileName=options.fileName
else:
fileName='message'
fileName='%s%05d' %(fileName,seq)
while os.path.exists(fileName)==True:
fileName=fileName[:-5]
seq=seq+1
fileName='%s%05d' %(fileName,seq)
f=open(fileName,'w')
f.write(message)
f.close()
else:
if not options.noDelim==True:
print '-'*70
print message
def parseOptions():
parser = OptionParser(usage=(usage % ('%prog',)))
parser.add_option("-f",
"--file",
action="store_true",
dest="saveFile",
help="Save message to a file with name 'message'.", )
parser.add_option("-n",
"--file-name",
dest="fileName",
help="File name for message. Use with -f option.", )
parser.add_option("-i",
"--index",
dest="index",
help="Browse message in the middle of queue.", )
parser.add_option("-A",
"--all",
action="store_true",
dest="all",
help="Browse all messages. If messages are saved to file,"+
" messages have sequence number in the file name.", )
parser.add_option("-d",
"--depth",
action="store_true",
dest="depth",
help="Print just the queue depth.", )
parser.add_option("-l",
"--lifo",
action="store_true",
dest="lifo",
help="Print last message first (Last-In-First-Out).", )
parser.add_option("",
"--no-delim",
action="store_true",
dest="noDelim",
help="Do not print message delimeter.", )
(options, args) = parser.parse_args()
return (options, args)
#MQException class that holds application specific error codes
#and error messages
class MQException(Exception):
errorCodes={'1': 'QMGRNAME, QNAME or MESSAGE missing.',
'2': 'Too many arguments.',
'3': 'File does not exist.',
'4': 'QMGRNAME or QNAME missing.',
'5': 'Index error. Not so many messages in queue.',
}
code=0
def __init__(self, code):
self.code=code
self.msg = str(code)
if __name__ == "__main__":
sys.exit(main())
PyBrowse的帮助:
Usage: PyBrowse.py [options] QMGRNAME QNAME
Options:
-h, --help show this help message and exit
-f, --file Save message to a file with name 'message'.
-n FILENAME, --file-name=FILENAME
File name for message. Use with -f option.
-i INDEX, --index=INDEX
Browse message in the middle of queue.
-A, --all Browse all messages. If messages are saved to file,
messages have sequence number in the file name.
-d, --depth Print just the queue depth.
-l, --lifo Print last message first (Last-In-First-Out).
--no-delim Do not print message delimeter.
构建可执行文件
在某些情况下,您的工具的用户将不会安装Python,因此拥有可执行文件进行分发非常有用。 幸运的是,使用Python和py2exe扩展名可以轻松地将Python脚本转换为Windows可执行文件,并且py2exe在单个目录中包含所有必需的Python文件,这些文件可以分发给用户。 要创建Python脚本的可执行文件,请先安装py2exe,然后创建安装脚本。 清单8具有用于Python MQ工具的最小安装脚本:
清单8. setup.py
from distutils.core import setup
import py2exe
setup(
console = ["PyPut.py"],
)
setup(
console = ["PyGet.py"],
)
setup(
console = ["PyBrowse.py"],
)
在Python MQ脚本所在的目录中执行setup.py。 使用命令python setup.py py2exe
并等待其完成。 现在,您有一个dist目录,其中包含Python MQ脚本作为可执行文件以及执行PyMQ工具所需的所有文件。 如果您在dist目录中查找,则会看到py2exe包含了所有必需的WebSphere MQ dll文件。 要将脚本分发给未安装WebSphere MQ的用户(例如,如果您的工具是远程管理工具),则可以将其保留在那里-否则,您应从dist目录中删除除python25.dll以外的所有dll文件。 脚本将从系统路径中找到MQ dll文件。
摘要
借助Python MQ接口,您可以使用Python语言为WebSphere MQ开发实用程序。 因为Python是用于快速开发的强大工具,所以PyMQI将快速开发扩展到WebSphere MQ程序。 在投入生产之前,可以使用Python快速测试和验证解决方案。 本文中描述的工具是示例,可以在开发使用WebSphere MQ的解决方案时在日常工作中使用。 由于使用了Python和PyMQI,示例代码会随着时间的推移而发展,并且这些示例可以成为开发人员或管理员工具箱中的资产。
翻译自: https://www.ibm.com/developerworks/websphere/library/techarticles/0708_salkosuo/0708_salkosuo.html