当前位置: 首页 > 工具软件 > WebSphere MQ > 使用案例 >

在WebSphere MQ应用程序中使用Python

潘兴朝
2023-12-01

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之前,编译需要其他步骤:

  1. 为Windows®C编译器安装MinGW32(极简GNU)。
  2. 修改WebSphere MQ C头文件。
  3. 编译PyMQI。
  4. 安装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

 类似资料: