System/Q部件是Tuxedo系统的一个重要组成部分,它提供了一种队列机制,允许消息按某种排队规则存储到持续介质(如磁盘)或非持续介质(如内存)中,然后再转发给其它处理进程。这种存储转发机制可以保证在两个通信实体之间传递的消息不丢失、不重传,从而保证交易的完整性。
System/Q的队列通信
System /Q用到了Tuxedo系统提供的两个服务器:消息队列服务器TMQEUE和消息转发服务器TMQFORWARD。TMQEUE用于对消息进行出队入队管理,TMQFORWARD用于将消息从队列中取出,转发给服务器进行处理,然后将处理结果放回响应队列。
图1
System/Q的队列通信可以分为两类:客户机对客户机和客户机对服务器,差别在于前者消息不需要转发,而后者需要将消息转发到服务器请求服务处理。因此,对于前者,配置文件中就不用提供转发服务器TMQFORWARD。
客户机对客户机的通信
这种端对端的通信模式是队列系统的简单应用,图1是端对端异步通信模式的展示。左侧客户机通过tpenqueue()函数往队列里写了一条消息,然后接着做下面的工作;右侧客户机通过tpdequeue()函数接收消息,并进行处理,之后再往队列中写消息;左侧客户机从队列中取出消息;至此,一个通信周期完成。
若使用同步通信,左侧客户往队列中写入消息后,就处于阻塞状态,只有等到取得右侧客户机的响应消息后,流程才继续往下执行。
客户机对服务器的通信
这种通信模式是System/Q的常规应用,下面是客户机和服务器的通信流程:
图2
图2中左侧为客户机,右侧为服务器,中间为消息队列系统。右侧服务器提供了两个服务:SERVICE1和SERVICE2。在消息队列系统中,TMS_QM是System/Q的事务管理服务器,它定义了一个队列服务器组,组中定义了一个队列空间,队列空间中定义了有四个消息队列,SERVICE1和SERVICE2分别是对应于同名的两个服务的队列(这是一种习惯的命名规则,客户机若请求服务器中的SERVICE1服务,就把请求消息放入SERVICE1队列中)。CLIENT_RPLY1是SERVICE1服务对请求的响应队列,FAILUREQ是服务器操作失败的响应队列。图中流程说明:①客户机提出对SERVICE1的请求;②TMQUEUE将请求消息入队;③TMQUEUE向客户机汇报入队是否成功;④TMQFORWARD取出请求消息;⑤将请求消息传给SERVICE1;⑥SERVICE1对请求作出响应;⑦TMQFORWARD将响应消息入队;⑧客户机要求取回响应消息;⑨TMQUEUE取出响应消息;⑩TMQUEUE取消息是否成功。
队列管理
在使用System/Q部件之前,需要先创建队列空间和队列。Tuxedo对队列的操作和管理基本上是通过qmadmin来完成的,在NT下,qmadmin是一个DOS应用程序,运行前,先要设置环境变量QMCONFIG,如:
set QMCONFIG=C:\qsample\QUE
qmadmin通过这个变量决定在C:\qsample目录下创建队列设备QUE。运行qmadmin,出现一个操作环境,按照如下命令依次创建队列设备、队列空间和消息队列:
> crdl c:\qsample\QUE 0 400
… …
> qspacecreate -n 100B
Queue space name: QSPACE
IPC Key for queue space: 62839
Size of queue space in disk pages: 100
Number of queues in queue space: 6
…
> qopen QSPACE
> qcreate
Queue name: STRING
Queue order (priority, time, expiration, fifo, lifo): fifo
crdl命令创建了一个队列设备,名为QUE,大小为400个磁盘块;接着用qspacecreate命令创建了一个队列空间,名为QSPACE,大小为100个磁盘块;最后用qcreate命令在QSPACE中创建了一个名为STRING的队列,它使用了先进先出(fifo)的排队规则。为了完成本文中介绍的例子,还必须创建另外两个队列:RPLYQ和ERRQUE。
System/Q的应用实例
qsample是Tuxedo用于演示System/Q的例子,客户机将一个包含字符串的消息放入STRING队列中,TMQFORWARD将该消息转发到STRING服务,要求它将消息体内的字符串转换成大写。处理完毕后,TMQFORWARD把响应消息放入响应队列RPLYQ,客户机再从RPLYQ中取出响应消息,进行打印输出。
qsample的服务程序
服务程序server.c的内容如下,其中第2行定义了一个名为 STRING的服务,第9行完成字母的大写转换,第11行通过tpreturn函数将转换结果传回给TMQFORWARD服务器,并表明转换成功。
1. #include "atmi.h"
2. STRING(msg)
3. TPSVCINFO msg;
4. {
5. char str;
6. int i;
7. str = (char )msg->data;
8. for (i = 0; i < msg->len; i++) {
9. str[i] = toupper(str[i]);
10. }
11. tpreturn(TPSUCCESS, 0, msg->data, 0L, 0);
设置环境变量
除了设置QMCONFIG外,还需要根据实际情况设置:TUXDIR(Tuxedo的安装目录)、APPDIR和TUXCONFIG环境变量。
创建消息队列
qsample用到了一个队列空间QSPACE和三个队列STRING、RPLYQ与errque。在NT平台下创建它们的最好办法是使用nmake命令,即“c:\qsample\nmake/f qsapme.nt QUE”,当然也可以手工创建。
创建事务日志
TMS_QM在队列事务管理时,需要用到日志设备,创建办法也是用nmake命令:
c:\qsample\nmake/f qsapme.nt TLOG
它执行了qsample.nt中预定义的一组Tuxedo命令。
qsample的客户程序
客户程序client.c的流程是:加入Tuxedo系统→消息入队→消息出队→退出系统。simpapp直接通过tpcall()函数调用TOUPPER服务,而qsample则将消息放入队列STRING,由TMQFORWARD服务器通过tpcall()调用STRING服务。下面是部分源代码,其中略去了错误捕捉处理的部分:
#include "Uunix.h"
#include "atmi.h"
main(){
char reqstr;
/ 要发送的字符串 /
long len;
/ 返回的字符串长 /
TPQCTL qctl;
/ System/Q的控制结构 /
tpinit(NULL);
/ 加入Tuxedo系统 /
reqstr = tpalloc("STRING",NULL,100));
/ System/Q的控制结构 /
(void) strcpy(reqstr,"this is a q example");
/ 输入要转换的字符串 /
(void) printf("before: %s\n", reqstr);
qctl.flags = TPQREPLYQ; / 说明要指定响应队列 /
(void) strcpy(qctl.replyqueue, "RPLYQ"); / 指定响应队列名称为RPLYQ /
/ 使用消息进入队列空间QSPACE的STRING队列,reqstr为消息体 /
tpenqueue("QSPACE", "STRING", (TPQCTL )&&qctl,(char )reqstr,0, 0);
qctl.flags = TPQWAIT;
/ 设置等待响应标记 /
tpdequeue("QSPACE", "RPLYQ", (TPQCTL )&&qctl, (char )&&reqstr,&&len, TPNOTIME);
(void) printf("after: %s\n",reqstr);
tpfree(reqstr);
/ 释放内存并退出 /
(void) tpterm();
/ 退出Tuxedo系统 /
}
修改配置文件
配置文件ubb.sample定义了三个服务器:server、TMQUEUE、TMQFORWARD和两个组:GROUP1和QUE1。SERVER提供STRING服务,TMQUEUE和TMQFORWARD属于QUE1组。QUE1组中的OPENINFO参数定义了队列资源管理器TUXEDO/QM、队列设备和队列空间。最后一行CLOPT参数中定义了将消息转发给STRING服务。
GROUPS
GROUP1
LMID = SITE1 GRPNO = 1
TMSNAME=TMS TMSCOUNT=2
QUE1
LMID = SITE1 GRPNO = 2
TMSNAME = TMS_QM TMSCOUNT = 2
OPENINFO = "TUXEDO/QM:c:\qsample\QUE;QSPACE"
SERVERS
DEFAULT: CLOPT="-A"
server SRVGRP=GROUP1 SRVID=1
TMQUEUE
SRVGRP = QUE1 SRVID = 1
GRACE = 0 RESTART = Y CONV = N MAXGEN=10
CLOPT = "-s QSPACE:TMQUEUE -- "
TMQFORWARD
SRVGRP=QUE1 SRVID= 5 GRACE=0 RESTART=Y CONV=N MAXGEN=10
编译和运行
确保make文件qsample.nt中include和lib变量已经包含了Tuxedo系统的头文件和库文件,然后使用如下命令进行编译:
c:\qsample\nmake/f qsample.nt all
成功后,用tmloadcf命令加载配置文件,用tmboot命令启动应用程序,最后,运行客户程序client.exe,就可以看到STRING服务的处理结果。