[性能测试]:关于MQ协议脚本开发
消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过写和检索出入列队的针对应用程序的数据(消息)来通信,而无需专用连接来链接它们。
银行脚本使用MQ通信的较多,下面介绍一个MQ的脚本:
MQ的脚本分为SEND和RECIVE两部分
send部分:
import com.ibm.mq.*; import lrapi.lr; public class Actions { String PutQueueManagerName = "QMCPG1"; // 发送队列管理器 String PutQueueName = "HVPSBANK"; // 发送队列名,相当于前置机的接收队列 String QueueChannel = "xn_rcv"; // 通道名,要用服务器通道 int PutPort = 1428; // 发送端口号,相当于前置机的接收端口 int CCSID = 1381; // 客户端Unix用819,windows用1381 int OpenOptions = MQC.MQOO_INPUT_AS_Q_DEF|MQC.MQOO_OUTPUT|MQC.MQOO_INQUIRE; // 连接参数 int PutDepth = 0; // 发送队列深度 String SndTime = ""; // 当前发送时间 MQQueueManager PutQueueManager = null; // 创建发送队列管理器对象 MQQueue PutQueue = null; // 创建发送队列对象 MQMessage PutMessage = new MQMessage(); // 创建发送消息对象 MQPutMessageOptions PMO = new MQPutMessageOptions(); // 创建发送消息选项队列 public int init() throws Throwable { // 发送队列的参数********************************************** MQEnvironment.hostname = lr.eval_string("<HostIP>"); // 设置环境参数 MQEnvironment.port = PutPort; MQEnvironment.CCSID = CCSID; MQEnvironment.channel = QueueChannel; PutQueueManager = new MQQueueManager(PutQueueManagerName); // 连接发送队列管理器 PutQueue = PutQueueManager.accessQueue(PutQueueName, OpenOptions, null, null, null); // 建立访问发送队列 PutMessage.format = MQC.MQFMT_STRING; // 设置消息中应用数据的格式 PutMessage.characterSet = 1381; // 设置字符集 PutMessage.expiry = -1; // 设置消息为不过期 return 0; }//end of init public int action() throws Throwable { SndTime = String.valueOf(System.currentTimeMillis()); // 获取当前发送时间,13位 lr.start_transaction("02_CP2I111_大额来帐_发送"); PutQueueMessage("{H:" + "02" + "309391000011 " + "HVPS" + "306581000003 " + "HVPS" + "<Date>" + // 报文发起日期 "<Time>" + // 报文发起时间 "XML" + "hvps.111.001.01 " + SndTime + "<Num>" + // 通信级标识号,CNAPS2SIMU0000088212,20位,接收方根据OrigSender+OrigSendDate+MesgID唯一确定一个报文,该三项重复的报文作为通信级重复报文; SndTime + "<Num>" + // 通信级参考号,CNAPS2SIMU0000030415,20位,标识本报文的关联报文,由OrigSender设置,后续节点应保持该域不变,并在通信回应报文中带回该值,以便OrigSender匹配原报文; "3" + "D" + " " + "}\r\n" + "{S:" + // 数字签名域起始标识 "2016110700130322|2016-11-07T14:25:01|1|2016110700130322|A100|CNY10.05|NORM|309391000011|309391000011|306581000003|306588000016|321|123|309391000011|306588000016|xingneng|6214620421000208396|02102|" + // 数字签名内容 "}\r\n" + // 数字签名域结束标识 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<Document xmlns=\"urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02\">" + "<FIToFICstmrCdtTrf>" + "<GrpHdr>" + "<MsgId>" + "<Date>" + "<Time>" + "<MsgNum>" + "</MsgId>" + // 报文标识号,最大35位,最好是8位日期+8位流水,否则二代后台会处理异常,2016111015130018 "<CreDtTm>2016-11-07T14:25:01</CreDtTm>" + "<NbOfTxs>1</NbOfTxs>" + "<SttlmInf>" + "<SttlmMtd>CLRG</SttlmMtd>" + "</SttlmInf>" + "</GrpHdr>" + "<CdtTrfTxInf>" + "<PmtId>" + "<EndToEndId>1</EndToEndId>" + "<TxId>" + SndTime + "<Num>" + "</TxId>" + // 交易标识号,最大35位,2016110700130322 "</PmtId>" + "<PmtTpInf>" + "<CtgyPurp>" + "<Prtry>A100</Prtry>" + "</CtgyPurp>" + "</PmtTpInf>" + "<IntrBkSttlmAmt Ccy=\"CNY\">0.02</IntrBkSttlmAmt>" + // 金额 "<SttlmPrty>NORM</SttlmPrty>" + "<ChrgBr>DEBT</ChrgBr>" + "<InstgAgt>" + "<FinInstnId>" + "<ClrSysMmbId>" + "<MmbId>309391000011</MmbId>" + // 付款清算行行号 "</ClrSysMmbId>" + "</FinInstnId>" + "<BrnchId>" + "<Id>309391000011</Id>" + // 收款行行号 "</BrnchId>" + "</InstgAgt>" + "<InstdAgt>" + "<FinInstnId>" + "<ClrSysMmbId>" + "<MmbId>306581000003</MmbId>" + // 收款清算行行号 "</ClrSysMmbId>" + "</FinInstnId>" + "<BrnchId>" + "<Id>306588000016</Id>" + // 收款行行号 "</BrnchId>" + "</InstdAgt>" + "<Dbtr>" + "<Nm>沈监</Nm>" + // 付款人名称 "</Dbtr>" + "<DbtrAcct>" + "<Id>" + "<Othr>" + "<Id>6225684352000160189</Id>" + // 付款人账号 "</Othr>" + "</Id>" + "</DbtrAcct>" + "<DbtrAgt>" + "<FinInstnId>" + "<ClrSysMmbId>" + "<MmbId>309391000011</MmbId>" + // 付款人开户行行号 "</ClrSysMmbId>" + "</FinInstnId>" + "</DbtrAgt>" + "<CdtrAgt>" + "<FinInstnId>" + "<ClrSysMmbId>" + "<MmbId>306588000016</MmbId>" + // 收款人开户行行号 "</ClrSysMmbId>" + "</FinInstnId>" + "</CdtrAgt>" + "<Cdtr>" + "<Nm>燕净</Nm>" + // 收款人名称 "</Cdtr>" + "<CdtrAcct>" + "<Id>" + "<Othr>" + "<Id>6225684341000008415</Id>" + // 收款人账号 "</Othr>" + "</Id>" + "</CdtrAcct>" + "<Purp>" + "<Prtry>02102</Prtry>" + // 业务种类编码 "</Purp>" + "<RmtInf>" + "<Ustrd>/C00/2016-11-07</Ustrd>" + // 备注 "</RmtInf>" + "</CdtTrfTxInf>" + "</FIToFICstmrCdtTrf>" + "</Document>"); lr.end_transaction("02_CP2I111_大额来帐_发送",lr.PASS); return 0; }//end of action public int end() throws Throwable { try { PutQueue.close(); PutQueueManager.close(); PutQueueManager.disconnect(); } catch (MQException ex) { lr.error_message("02_CP2I111_大额来帐_发送退出关闭队列时出现错误,完成代码为:" + ex.completionCode + ",原因为:" + ex.reasonCode); ex.printStackTrace(); } catch(Exception e) { e.printStackTrace(); } return 0; }// end of end // 发送消息++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public void PutQueueMessage(String MyStr) { try { PutMessage = new MQMessage(); PutMessage.write(MyStr.getBytes("UTF-8")); // 呵呵 PutQueue.put(PutMessage, PMO);// 将消息放入队列 PutQueueManager.commit(); // 提交事务处理 //PutDepth = PutQueue.getCurrentDepth(); // 获取发送队列的深度 //System.out.println("++++++发送队列当前深度为:"+ PutDepth); //System.out.println("=======发送报文是:" + MyStr); PutMessage.clearMessage(); PutMessage = null; } catch (MQException ex) { lr.end_transaction("02_CP2I111_大额来帐_发送",lr.FAIL); lr.error_message("02_CP2I111_大额来帐_发送_发送消息时出错,完成代码为:" + ex.completionCode + ",原因为:" + ex.reasonCode + "流水号为:" + SndTime); lr.exit(lr.EXIT_ITERATION_AND_CONTINUE, lr.FAIL); //System.out.println("发送消息时出现错误,完成代码为:" + ex.completionCode + ",原因为:" + ex.reasonCode); //ex.printStackTrace(); } catch(Exception e) { e.printStackTrace(); } } }
RECIVE部分:
/* * LoadRunner Java script. (Build: _build_number_) * * Script Description: * */ import java.util.Date; import com.ibm.mq.*; import lrapi.lr; public class Actions { String GetQueueManagerName = "QMCPG1"; // 接收队列管理器 String GetQueueName = "306581000003.MBFEA.PBCTOBANK"; // 接收队列名,相当于前置机的发送队列 String QueueChannel = "xn_rsp"; // 通道名,要用服务器通道 //String HostName = lr.eval_string("<HostIP>"); // ip 地址 int GetPort = 1428; // 接收端口号,相当于前置机的发送端口 int CCSID = 1381; // 客户端Unix用819,windows用1381 int OpenOptions = MQC.MQOO_INPUT_AS_Q_DEF|MQC.MQOO_OUTPUT|MQC.MQOO_INQUIRE; // 连接参数 int GetDepth = 0; // 接收队列深度 MQQueueManager GetQueueManager = null; // 创建接收队列管理器对象 MQQueue GetQueue = null; // 创建接收队列对象 MQMessage GetMessage = new MQMessage(); // 创建接收消息对象 MQGetMessageOptions GMO = new MQGetMessageOptions(); // 创建接收消息选项对象 public int init() throws Throwable { // 接收队列的参数*********************************************** MQEnvironment.hostname = lr.eval_string("<HostIP>"); // 设置环境参数 MQEnvironment.port = GetPort; MQEnvironment.CCSID = CCSID; MQEnvironment.channel = QueueChannel; GetQueueManager = new MQQueueManager(GetQueueManagerName); // 连接接收队列管理器 GetQueue = GetQueueManager.accessQueue(GetQueueName, OpenOptions, null , null, null); // 建立访问接收队列 GetMessage.format = MQC.MQFMT_STRING; // 设置消息体参数 GetMessage.characterSet = 1381; GetMessage.expiry = -1; GMO.waitInterval = 20000; // 等待时间限制 GMO.options = MQC.MQGMO_NO_WAIT; // 如果队列没有消息则立即返回 return 0; }//end of init public int action() throws Throwable { String Msg = null; String NowTime = null; try { GetMessage = new MQMessage(); // 必须新建实例,否则无法多次迭代无法继续接收消息 GetDepth = GetQueue.getCurrentDepth(); // 获取接收队列的深度 if(GetDepth > 0) //接收队列深度不为0则打印消息 { GetQueue.get(GetMessage, GMO); GetQueueManager.commit(); //System.out.println("======接收队列当前深度为:"+ GetDepth); NowTime = String.valueOf(System.currentTimeMillis()); // 记录当前时间戳作为接收时间,13位 Msg = GetMessage.readString(GetMessage.getMessageLength()); CompResult(Msg,NowTime); // 记录接收时间、流水、交易码(所接收的交易返回信息不一定为当前程序发出的交易) //System.out.println("======接收消息的内容为:\n" + Msg); GetMessage.clearMessage(); GetMessage = null; } else { System.out.println("++++++接收队列无消息++++++"); } } catch(MQException ex) { if(ex.reasonCode == 2033) { // 2033是没有消息,不做处理 } else { lr.error_message("02_CP2I111_大额来帐_接收接收消息时出错,完成代码为:" + ex.completionCode + ",原因为:" + ex.reasonCode + ",流水号为:" + NowTime); ex.printStackTrace(); } } catch(Exception e) { e.printStackTrace(); } return 0; }//end of action public int end() throws Throwable { try { GetQueue.close(); // 关闭队列 GetQueueManager.close(); // 关闭队列管理器 GetQueueManager.disconnect(); // 断开连接 } catch (MQException ex) { lr.error_message("02_CP2I111_大额来帐_接收关闭队列时出现错误,完成代码为:" + ex.completionCode + ",原因为:" + ex.reasonCode); ex.printStackTrace(); } return 0; }// end of end // 统计交易结果 public void CompResult(String MSG, String RecTime) { boolean Result = true; // 交易是否成功 String StartTime = null; double DurTime = 0; // 交易处理时间 int FlowIndex = -1; // 位置 String FlowNo = null; int ErrIndex = -1; // 错误码位置 String ErrCode = null; FlowIndex = MSG.indexOf("<MsgId>"); // 流水号的位置 StartTime = MSG.substring(FlowIndex+7, FlowIndex+7+13); // 从流水号获取开始时间 DurTime = (Double.parseDouble(RecTime) - Double.parseDouble(StartTime))/1000; // 单位秒 //lr.error_message("======处理时间是:" + DurTime + "发送时间是:" + StartTime + "接收时间是:" + RecTime + "返回报文是:" + MSG); ErrIndex = MSG.indexOf("<MsgPrcCd>"); // 错误码的位置 ErrCode = MSG.substring(ErrIndex+10, ErrIndex+10+8); // 错误码 if(!ErrCode.equals("CU0I0000")) // 成功状态码是CU0I0000,交易失败则获取流水号 { Result = false; FlowNo = MSG.substring(FlowIndex+7, FlowIndex+7+13); // 流水号 lr.error_message("02_CP2I111_大额来帐_接收交易失败!出错流水号是:" + FlowNo + ",错误码是:" + ErrCode + ",完整出错信息是:" + MSG); } // 统计事务响应时间和成功率 if(Result) { lr.set_transaction("02_CP2I111_大额来帐_接收", DurTime, lr.PASS); //lr.error_message("======02_CP2I111_DELZ交易事务处理时间是:" + DurTime); } else { lr.set_transaction("02_CP2I111_大额来帐_接收", DurTime, lr.FAIL); } } } // 正确返回报文: //{H:02306581000003 HVPS309391000011 HVPS20161110164516XMLccms.990.001.02 20161110HVPS00062057012016111016501100013U } //<?xml version="1.0" encoding="UTF-8"?> //<Document xmlns="urn:cnaps:std:ccms:2010:tech:xsd:ccms.990.001.02"><ComConf><ConfInf><OrigSndr>309391000011</OrigSndr><OrigSndDt>20161110</OrigSndDt><MT>hvps.111.001.01</MT><MsgId>01201611101650110001</MsgId><MsgRefId>01201611101650110001</MsgRefId><MsgPrcCd>CU0I0000</MsgPrcCd></ConfInf></ComConf></Document>