§ TUXEDO是什么?
l 客户端/服务器模式的演化
l 基本的客户端/服务器模式
l 多层结构
l TUXEDO的客户端/服务器方法
l 一个完整的例子
l 应用配置文件:ubbconfig
l 运行应用的步骤
tuxedo是什么?
BEA TUXEDO是在企业、Internet 这样的分布式运算环境中开发和管理三层结构的客 户/服务器型关键任务应用系统的强有力工具。它具备分布式事务处理和应用通信功能,并提供完善的各种服务来建立、运行和管理关键任务应用系统。开发人员能够用它建立跨多个硬件平台、数据库和操作系统的可互操作的应用系统。BEA TUXEDO是企业、 Internet 分布式应用中的基础主干平台。它提供了一个开放的环境,支持各种各样的客户、数据库、网络、遗留系统和通讯方式。
特点:
² 大量在线用户
² 巨量数据
² 信息访问
² 小事务
² 复杂网络
C/S系统的层次结构
以下列出了分布式系统的主要层次:
² 用户界面:被分成表示管理和表示逻辑。代表有主机框架的3270仿真终端;UNIX系统的X终端等,最新的Web浏览器界面也是。
² 商业逻辑:包含应用逻辑和应用规则。
² 数据管理:分为数据访问逻辑(SQL)和数据库管理。
区分C/S结构的类型可以根据以下特性:
客户端和服务端程序间逻辑分布,如何实现层次功能;中间件产品及技术的使用。
C/S模式的演化
上图列举了不同种类的C/S模式。其中大型主机系统仍然统治着最大的OLTP应用;基于X终端和UNIX工作站的应用在80年代后期兴起;廉价的WINTEL机器支持的Windows GUI通常用于2层模式;数据库新技术和OSF带领了3层应用模式。
基本C/S模式
C/S系统是一种分布式系统,由其程序决定其特点:
² 客户端部分执行前端功能,如:提供用户界面,向后台发出用户请求的交易,将结果返回给用户。
² 服务提供一般后端功能,按交易组织,将结果返回前端。
² 交易是分散的,按需求的操作,可以被远程客户端访问的程序。
C/S模式可能会有如下优点:
² 减小客户端程序体积,提高反应速度
² 位置无关
² 模块化
² 扩展性好
可管理多层C/S模式
在可管理多层(Managed Multi-Tier –MMT)C/S模式中,提出了中间件管理。在本书范围内,此点由交易处理(TransactionProcessing –TP)管理完成,提供以下功能:
² 在客户端和服务端之间进行通讯和传输
² 提供良好的系统管理
² 提供交易、配置的分布式管理
它管理服务端从多个客户端收到的数据流,并不是在C/S间建立一对一的关系,而且客户端可以向多个服务发出请求。这种特点保证了TUXEDO可以提供强大的分布式交易处理框架。
由于不必进行通讯和交易管理,数据库引擎可以专注于其特长:管理数据!在这种情况下,数据库成了一个纯RM(Resource Manager)。
MMT C/S模式给OLTP应用增加了如下优点:
² 所有C/S模式的优点在MMT模式下都得到了增强。实际上,由于中间件的引入,处理能力得到改善。
² 由于中间件管理了数据流,带来了许多新功能,如:交易路由、服务分布、管道、数据依赖路由等成为可能。
² 统一的数据流控限制了最大交易数,总的数据库过程少了,服务器空闲时间也少了,这就增加了数据库和系统效率。
² 应用代码的设计可以不考虑物理地址和内部数据表示。
² 配置成了一件单纯的管理工作,进一步的,可以通过配置轻易的改变系统结构。服务可以动态的增加、删除和重启动。
TUXEDO的C/S方案
构成TUXEDO系统的各部分、工具和其特性组成的MMT C/S模式给应用带来的便利及TUXEDO的实现方法:
l 查找错误
tperrno,tperrordetail
tpstrerror(),tpstrerrordetail()
userlog()
l 使用ATMI
进程管理
缓冲管理
请求/响应通讯
l 建立并编译一个TUXEDO客户端应用
buildclient
客户端在C/S模式中的作用
为了更好的了解客户端的所有任务以编写客户端应用,有必要重新认识客户端在C/S模式中扮演的角色。
首先,客户端是用户界面。意思是当用户在系统上用程序进行一次操作的整个过程就是一个客户端过程。前端过程是对客户端的另一个描述。客户端的首要任务就是获得执行操作应该得到的数据。
一旦客户端得到了应有的信息,应该将数据按服务能够识别并适合传输的格式打包。
然后,向服务端发送请求并等待回应。
收到回应数据后,将其按一定格式返回给终端用户。
客户端开发过程
客户端程序的设计和实现可以被分成2部分考虑:
² 用户处理过程
² TUXEDO功能部分
下文的客户端程序只描述了TUXEDO功能部分。
利用TUXEDO的ATMI API调用可以做到:
——基本的TUXEDO调试技巧(tperrno,tpstrerror,userlog)
——TUXEDO进程管理(tpinit,tpterm)
——基本数据缓冲管理(tpalloc,tprealloc,tpfree)
——基本通讯(tpcall,tpacall,tpgetrply)
调试和错误处理
当调用ATMI出错时,返回值为-1,全程变量tperrno被设值,该变量提供系统定义的出错原因。函数tpstrerror()以此变量为参数,返回错误的字符说明信息。
完整的错误号和文本错误信息存在于文件$TUXDIR/include/atmi.h。
函数userlog()重定向输出文件为ULOG.mmddyy。使用方法同printf()。该函数每次输出都写硬盘,这样在系统失败时也能保留调试信息。
代码范例
main()
{
int ret;
ret = [a ATMI call]
if ( ret == -1 )
{
printf(“Errorin ATMI call\n”);
usrlog(“ATMIerror logged %d %s”,tperrno,tpstrerror(tperrno));
}else
printf(“ATMIcall OK\n”);
……
ret = tpterm();
if ( ret == -1 )
{
printf(“Errorin exiting application\n”);
usrlog(“ATMIerror logged %d %s”,tperrno,tpstrerror(tperrno));
}
}
tperrno – 全程变量
(char *)tpstrerror(int)
userlog(…) – 语法同printf()
ULOG.mmddyy – 日志文件
进程管理
为了使客户端能够访问TUXEDO交易,客户端程序必须连接TUXEDO应用并进行登记。这种管理性步骤在切断连接时也要类似执行一次。API如下:
inttpinit(TPINIT *tpinfo)
客户端通过调用tpinit()与应用连接,进行交互,有以下事件发生:
调用安全接口检查客户端是否需要认证
连接BB,使进一步的ATMI函数得到信息
使BBL了解BB中已经存在请求
建立客户端消息队列使服务可以发回返回信息,系统可以送出广播通知等
错误时返回-1,可能由以下原因引起:
² TPEINVAL 参数错误
² TPENOENT BB无空间
² TPEPERM 无连接权限
² TPEPROTO 协议错误 – 被服务调用
inttpterm()
l ATMI事务API
l 过程
l ubbconfig
创建格式化事务日志
用ATMI交易API写程序
分布式事务处理和XA接口
分布式事务处理(Distributed Transation Processing-DTP)有能力处理多数据库间、全局事务而不必考虑交易各方及其资源的位置。
服务使用嵌入式SQL接口去访问数据库。在一个“全局交易”中TM和RM使用XA接口保证执行所有的资源访问动作。
全局事务通常最初被ATMI调用,包含一个以上的组;由客户端和服务端启动、提交或撤消。TUXEDO通过全局事务标识符(Global TransactionIdentifier-GTRID)控制所有参与部分。
RM 资源管理者(Resource Manager),本例中是一个数据库。
XA 控制RM提交或回滚所有动作的协议。
TMS TUXEDO的事务管理服务(Transaction Management Server),能够按XA协议与RM联系。TMS负责协调系统范围内事务相关资源管理。应用程序员可以通过ATMI事务API与TMS联系。
GTRID 全局事务标识符(Global TransactionIdentifier)。
TLOG 事务日志,用于跟踪交易所有部分。
二段式提交(2 Phase Commit)
分布式事务处理的UBBCONFIG
分布式事务处理的UBBCONFIG范例
#A NULL TMS Example
*RESOURCES
MAXGTT 20
CMTRET COMPLETE
*MACHINES
lcspn1 LMID =SITE1
TUXDIR =”/usr/tuxedo”
APPDIR =”/usr/apps/atmapp”
TUXCONFIG=”/usr/apps/atmapp/atmapp.tux”
ENVFILE =”/usr/apps/atmapp/ENVFILE”
TLOGDEVICE =”/usr/apps/atmapp/logs/TLOG”
TLOGNAME =TLOG
TLOGSIZE =100
*GROUPS
DEFAULT:
TMSNAME =TMS
TMSCOUNT=2
OPENINFO=”“
CLOSEINFO=”“
BANKB1 LMID=SITE1 GRPNO=200
BANKB2 LMID=SITE2 GRPNO=220
*SERVICES
TRANSFER AUTOTRAN=Y TRANTIME=30
*RESOURCES节说明
MAXGTT限制了一台机器上同时可以提供的GTRID数。最大值是2048,最小是0,缺省100;
CMTRET设成LOGGED时表示tpcommit()在所有部分都成功预提交时返回;设成COMPLETE时表示tpcommit()在所有部分都成功提交才返回。
*MACHINES节说明
TLOGDEVICE指出了该机器包含事务日志(TLOG)的文件系统。
TLOGNAME指出了该机器的事务日志名字。
TLOGSIZE指出了该机器事务日志的大小,单位是物理页数。最大值是2048,最小是0,缺省100
*GROUPS节说明
TMSNAME是事务管理服务的可执行文件名
TMSCOUNT是TMS启动的数量(最小2,最大10,缺省3)
OPENINFO是一个用于打开RM的信息的字符串
CLOSEINFO是一个用于关闭RM的信息的字符串
AUTOTRAN设成N则该交易初始化成无事务方式,Y则反之。
TRANTIME事务创建的超时时间,单位为秒。
创建事务日志的脚本
tmadmin <<!
crdl –b 500 –z /usr/apps/atmapp/logs/TLOG–O 0
crlog –m STIE1
!
为支持分布式事务处理,必须创建一个格式化的设备记录事务信息。上文是用tmadmin命令的脚本生成此种设备的例子。
ATMI 事务API
事务API通过ATMI给应用提供了以下操作
² 通过tpbegin(),tpcommit(),tpabort()控制事务的开始和结束。
int tpbegin(int timeout, long flags)
int tpcommit(long flags)
int tpabort(long flags)
² 通过tpsuspend(),tpresume()管理多个并发的事务。
int tpsuspend(TPTRANID *tranid, longflags)
int tpresume(TPTRANID *tranid, longflags)
² 通过tpscmt()设定提交返回方式为”logged”或”complete”
int tpscmt(long flags)
TP_CMT_LOGGED-在第一段后返回
TP_CMT_COMPLETE-在第二段后返回
² 通过tpgetlev()决定当前事务模式
int tpgetlev(void)
² 通过tpopen(),tpclose()为服务组打开或关闭RM
int tpopen(void)
int tpclose(void)
使用ATMI事务API的代码范例
/* 确保交易TRANSFER没有设成AUTOTRAN */
#include <atmi.h>
FBFR *sendBuf=NULL;
FBFR *recvBuf=NULL;
Void TRANSFER(TPSVCINFO *transb)
{
sendBuf= (FBFR *)transb;
…
if(tpbegin(30,0) == -1)
{
userlog(“FAILEDTO BEGIN TRANSACTION:%s”,tpstrerror(tperrno));
tpreturn(TPFAIL,-1, (char *)recvBuf, 0, 0);
}
if( tpcall(“WITHDRAWAL”, (char *)sendBuf, 0, (char **)&recvBuf, &len,0)==-1)
{
userlog(“tpcall(WITHDRAWAL) fail:%s”, tpstrerror(tperrno));
tpreturn(TPFAIL,-1, (char *)recvBuf, 0, 0);
}
…
if ( tpcall(“DEPOSIT”, (char *)sendBuf,0, (char **)&recvBuf, &len, 0)==-1)
{
userlog(“tpcall(DEPOSIT) fail:%s”, tpstrerror(tperrno));
tpreturn(TPFAIL,-1, (char *)recvBuf, 0, 0);
}
if( tpcommit(0) == -1)
{
userlog(“tpcommit()fail:%s”, tpstrerror(tperrno));
tpreturn(TPFAIL,-1, (char *)recvBuf, 0 ,0);
}
userlog(“Transaction committedsuccessfully”);
tpreturn(TPSUCCESS, 0 , (char *)recvBuf,0 , 0);
}
本例中的TRANSFER交易使用了TUXEDO XA事务API;本例使用了TUXEDO的NULL TMS配置。当TRANSFER被调用,首先起一个事务,调用交易WITHDRAWAL,然后调用交易DEPOSIT。如果一切都运行成功,TRANSFER调用tpcommit()结束事务。任何错误都将导致RM回滚事务。
管理类API AdminAPI(MIB)
本节要点
l 定义
l 过程
l 代码例子
l 错误处理和管理类API域
在TUXEDO下管理应用有很多手段,如下:
² tmadmin
² tmadmin的脚本
² 调用ATMI
² X-Windows GUI
² JAVA applet Web GUI
² Admin API (MIB)
每一种方法都有其优点和适用场合。Admin API提供访问TUXEDO信息的控制方法和结构。这些信息被分类成组,称为管理信息库(Management Information Base—MIB)。通过Admin API可以访问MIB。使用AdminAPI有以下优势:
² 可访问的TUXEDO系统信息更多
² 管理应用有更高的灵活度
² 可以集成到外部系统工具中
AdminAPI(MIB)
TUXEDO系统组成的各个部分都有自己的MIB,每部分的MIB是一组相关的类,每个类代表一个MIB可管理的实体或项目,有其自身的属性、许可权限和语义。TUXEDO系统的MIB有5部分,如下:
² TM_MIB
² EVENT_MIB
² APPQ_MIB
² WS_MIB
² ACL_MIB
下边的例子是访问TM_MIB并显示了/T部分的管理信息库。
AdminAPI使用了一些预定义的FML32的域,这些数据组织存放在文件$TUXEDO/udataobj/tpadm中。环境变量必须设置如下:
FLDTBLDIR32=$TUXDIR/udataobj
FIELDTBLS32=Usysfl32,tpadm,evt_mib
ExportFLDTBLDIR32 FIELDTBLS32
使用AdminAPI的代码范例
#include <stdio.h>
#include <fml32.h>
#include <atmi.h>
#include <tpadm.h>
main(int argc, char **argv)
{
longblen;
FBFR32 *ibuf;
/*tpinit() 连接TUXEDO */
ibuf= (FBFR32 *)tpalloc(FMLTYPE32,NULL,0);
Fchg32(ibuf,TA_OPERATION,0,”GET”,0);
Fchg32(ibuf,TA_CLASS,0,”T_MACHINE”,0);
printf(“Queryth T_MACHINE class before:\n”);
Fprint32(ibuf);
printf(“\n”);
if(tpcall(“.TMIB”,(char *)ibuf,0,(char **)&ibuf,&blen,0)== -1){
printf(“tpcall(.TMIB)failed:%s\n”,tpstrerror(tperrno));
Fprint32(ibuf);
Return(-1);
}
printf(“Queryth T_MACHINE class after:\n”);
Fprint32(ibuf);
printf(“\n”);
tpfree((char*)ibuf);
tpterm();
return(0);
}
因为Admin API是基于FML32类型的数据,所以要包含TUXEDO系统头文件“fml32.h”。
因为Admin API要用一些预定义的域去访问MIB信息,如TA_OPERATION和TA_CLASS,所以要包含TUXEDO系统头文件“tpadm.h”。
用tpinit()连接TUXEDO系统。
分配一个FML32数据缓冲。
在本例中,我们通过“GET(ing)”得到“MACHINE”的信息。
用tpcall()调用.TMIB服务。
显示结果。
释放FML32缓冲。
切断连接。
本例的输出(域名和域值)
TA_ERROR 0
TA_MORE 0
TA_OCCURS 1
TA_PERM 438
TA_GID 302
TA_MAXACCESSERS 20
TA_MAXCONV 1
TA_MAXGTT 20
TA_MAXWSCLIENTS 0
TA_MINOR 6000
TA_RELEASE 60
TA_SPINCOUNT 0
TA_TLOGSIZE 100
TA_TMNETLOAD 0
TA_UID 261
TA_MAXCLCACHE 100
TA_CLASS T_MACHINE
TA_STATE ACTIVE
TA_APPDIR /usr/apps/atmapp
TA_CMPLIMIT MAXLONG,MAXLONG
TA_ENVFILE /usr/apps/atmapp/ENVFILE
TA_PMID lcspn1
TA_TLOGDEVICE /usr/apps/atmapp/logs/TLOG
TA_TLOGNAME TLOG
TA_TUXCONFIG /usr/apps/tuxconfig
TA_TUXDIR /usr/tuxedo
TA_TYPE RS6000
TA_ULOGPFX /usr/apps/atmapp/logs/ULOG
TA_LMID SITE1
其他Admin API域和错误处理
除基本的域外,其他一些Admin API域在管理MIB信息时也非常有用。如:
在一个大应用中,server节会包含很多条目,以下3个域在取得这些信息时很有用。
TA_OCCURS
在请求时,表示需要得到信息的行数。
在返回结果后,表示成功得到信息的行数。
TA_CURSOR
表示上一次GET操作停止的位置。配合TA_OPERATION的GETNEXT属性,可以顺序遍历MIB。
TA_FILTER
客户端程序可以通过该域得到一个特定域信息
使用AdminAPI发生错误时,在回应缓冲中会带回来自MIB的错误信息
/* 得到前3项 */
long n=3;
Fchg32(sendbuf,TA_OPERATION,0,”GET”,0);
Fchg32(sendbuf,TA_CLASS,0,”T_SERVER”,0);
Fchg32(sendbuf,TA_OCCURS,0,n,0);
Fchg32(sendbuf,TA_CURSOR,0,NULL,0);
/* 打印rpbuf中返回值*/
ret = tpcall(“.MIB”,(char*)sendbuf,0,(char **)&recvbuf,&len,0);
/* 如果出错打印TA_ERROR和TA_STATUS*/
if ( ret == -1 && tperrno ==TPESVCFAIL){
Fget32(recvbuf,TA_ERROR,0,(char*)&ta_error,NULL);
Ta_status=Ffind32(recvbuf,TA_STATUS,0,NULL);
Printf(“Failure:%ld,%s\n”,ta_error,ta_status);
}else
Fprint32(recvbuf);
/* 从recvbuf传递TA_CURSOR,得到下3项*/
Fget(recvbuf,TA_CURSOR,0,cursor,0);
Fchg32(sendbuf,TA_OPERATION,0,”GETNEXT”,0);
Fchg32(sendbuf,TA_CURSOR,0,cursor,0);
tpadmcall()
tpadmcall(FBFR32 *inbuf, FBFR32 **outbuf,long flags)
用法:
Unbooted App
Unconfigured App
用户是管理员,用于SET一个NEW T_RESOURCE类,然后定义一个初始配置给应用
Unbooted App
Configured App
在有权限的UID/GID情况下,GET并SET任何TM_MIB(5)中任何类的任何属性。
Booted App
Unattached Process
在有权限的UID/GID情况下或用户是管理员,当返回值不是ACTIVE时,可以GET任何TM_MIB(5)中有合适权限的任何类的任何属性。
Booted App
Attached Process
权限在tpinit()时由授权key决定,可以GET任何TM_MIB(5)中有合适权限的任何类的任何属性。
代码范例:
#include <stdio.h>
#include <fml32.h>
#include <atmi.h>
#include <tpadm.h>
main(int argc , char **argv)
{
FBFR32 *ibuf;
/*tpinit() 连接TUXEDO */
ibuf= (FBFR32 *)tpalloc(FMLTYPE32,NULL,0);
Fchg32(ibuf,TA_OPERATION,0,”GET”,0);
Fchg32(ibuf,TA_CLASS,0,”T_DOMAIN”,0);
printf(“Queryth T_DOMAIN class before:\n”);
Fprint32(ibuf);
printf(“\n”);
if(tpadmcall(ibuf,&ibuf,0)== -1){
printf(“tpadmcall()failed:%s\n”,tpstrerror(tperrno));
Fprint32(ibuf);
Return(-1);
}
printf(“Queryth T_MACHINE class after:\n”);
Fprint32(ibuf);
printf(“\n”);
tpfree((char*)ibuf);
tpterm();
return(0);
}
安全 Security
TUXEDO在其系统框架中集成了进程间通讯安全功能。在商业应用中可以由用户决定安全级别。
本节中,我们将讨论TUXEDO提供的不同的安全保障能力和应用实现的必要步骤。
本节要点
l 概念
l 管理文件和命令
l ubbconfig
l API使用说明
l 代码范例
TUXEDO系统在第一次ATMI调用时——tpinit()就进行安全工作。
安全级别信息先传入tpinit(),在公告牌上进行校验,然后用AUTHSVR进行二次检查。如果验证通过,tpinit()允许客户端连上TUXEDO系统。
TUXEDOAPI tpchkauth()用来决定应用的安全级别。下表是各安全级别认证需要的资源。
TPAPPAUTH
tpusr
tpgrp
tpacl
SECURITY USERAUTH
ACL
MANDATORY_ACL
AUTHSVC AUTHSVC
组命令
tpgrpadd –g GID groupname
tpgrpdel groupname
tpgrpmod –g GID –n new_groupnamegroupname
入口在$APPDIR/tpgrp
用户命令
tpusradd –u UID –g GID –c clntnameusrname
tpusrdel –c clntname
tpusrmod –u UID –g GID –c clntname –lnewlogin –n newclntname –p usrname
入口在$APPDIR/tpusr
ACL命令
tpacladd –g GID entity_name
tpacldel entity_name
tpaclmod –g GID entity_name
入口在$APPDIR/tpacl
简要说明
以上管理命令维护AUTHSVR的安全入口。只有安全级别要求到ACL(Access Control List)时,这些操作过程才是必须的。
AUTHSVR对每一个用户进行认证。当客户端进程调用tpinit()去连接应用时,发生以下过程:
AUTHSVR校验用户名,客户端名和密码
当成功,AUTHSVR提供一不可伪造的应用key
每次交易请求时,客户端都要提交此应用key
ubbconfig有关安全的部分
*RESOURCES
AUTHSVC “..AUTHSVC”
SECURITY “ACL”
*SERVERS
AUTHSVR SVRGRP=”AUTHGRP”SRVID=100
RESTART=YMAXGEN=2 GRACE=0
CLOPT=”-A”
AUTHSVR提供的交易名字叫“..AUTHSVC”
SECURITY设置了安全的级别
客户端代码范例
#include “atmi.h”
int ConnectToTuxedo()
{
FBFR *f;
TPINIT *tpinfo;
char *passwd2=”penquin”;
int do_auth = 0,no_auth = 0;
do_auth= tpchkauth();
switch(do_auth)
{
case -1:
printf(“tpchkauth()err:%s”,tpstrerrno(tperrno));
return(-1);
case TPNOAUTH:
no_auth= 1;
break;
case TPSYSAUTH:
tpinfo= (TPINIT *)tpalloc(“TPINIT”, NULL, 0);
if(tpinfo ==NULL)
{
printf(“tpchkauth()err:%s”,tpstrerrno(tperrno));
return(-1);
}
break;
case TPAPPAUTH:
tpinfo= (TPINIT *)tpalloc(“TPINIT”, NULL, TPINITNEED(15));
if(tpinfo ==NULL)
{
printf(“tpchkauth()err:%s”,tpstrerrno(tperrno));
return(-1);
}
tpinfo->datalen=strlen(passwd)+1;
memcpy((char*)&tpinfo->data, passwd2, tpinfo->datalen);
break;
default:
printf(“Invalidsecurity setting %d\n”,do_auth);
return(-1);
}
if(!no_auth)
{
strcpy(tpinfo->usrname,”tuxedo”);
strcpy(tpinfo->passwd,”hello”);
strcpy(tpinfo->grpname,”“);
}
if((tpinit(TPINIT *)tpinfo))==-1
{
printf(“Failedto join application\n”);
return(-1);
}
}
tpchkauth()返回TPNOAUTH,TPSYSAUTH,TPAPPAUTH或错误用以决定加密强度。
tpalloc()将分配一个TPINIT结构,存储与公告牌对比的密码。
Struct TPINIT {
char usrname[MAXTIDENT+2];
char cltname[MAXTIDENT+2];
char passwd[MAXTIDENT+2];
char grpname[MAXTIDENT+2];
long flags;
long datalen;
long data;
}
tpalloc()还将根据TPINITNEED()分配一段空间存储用户密码。
用tpinit()与TUXEDO连接。
事件代理 Event Broker
在事件代理出现前,所有的通讯由用户发起。通过事件代理,TUXEDO系统增加了另一种进程间通讯方式——通讯可以由事件发起。事件可以独立于客户端,促使其他活动发生。
事件代理搜寻并报告一些预定义的事件,如系统错误和用户定义错误。
在本节中,我们将研究事件监视模块,练习TUXEDO的’publish’和’subscribe’事件模块的程序设计。
本节要点
l ubbconfig范例
tpsubscribe和tpunsubscribe的代码范例
tppost的范例
事件代理提供了这样一种通讯方式:一些进程可以发布消息给订阅了这些消息的进程或客户端。例如:服务可以在价格发生变化时发布信息,所有连接系统的客户端都可以收到信息。
事件代理只能执行一些该事件预定动作,这些动作包括:
² 调用交易(tpacall)
² 将请求送入一个可靠队列(tpenqueue)
² 用户通知之类(tpnotify)
² 记录日志到ULOG.mmddyy
² 执行系统调用
主要有2类事件:
² 系统 TUXEDO系统内部活动引起,如网络故障等
² 用户定义 应用中与业务流程有关的
触发事件的ATMI API是tppost()。
订阅和取消订阅的ATMI API是tpsubscribe(),tpunsubscribe()。
Subscribing& Unsubscribing ATMI
longtpsubscribe(char *eventexpr, char *filter, TPEVCTL *ctl, long flags)
进行订阅。返回订阅句柄,-1失败
char *eventexpr 表示事件的字符串,可以含有通配符*
char *filter 一个布尔表达式,决定是否收到消息。
TPEVCTL ctl 一个描述事件代理将进行的动作
flags 可以是[TPNOTIME|TPSIGRSTRT|TPNOBLOCK]
inttpunsubscribe(long subscription, long flags)
取消订阅
long eventexpr tpsubscribe()返回的句柄
flags 可以是[TPNOTIME|TPSIGRSTRT|TPNOBLOCK]
struct TPEVCTL
{
longflags;
charname1[32];
charname2[32];
TPQCTLqctl;
}
调用另一个交易
ctl->flags=TPEVSERVICE;
strcpy(ctl->name1,”SERVICENAME”);
进入队列
ctl->flags=TPEVQUEUE;
strcpy(ctl->name1,”QSPACENAME”);
strcpy(ctl->name2,”QUEUENAME”);
ctl->qctl.flags=TPQREPLYQ;
strcpy(ctl->qctl.replyqueue,”RPLYQ”);
通知
ctl=(struct TPEVCTL *)NULL;
int tppost(char *eventname, char *data,long len, long flags)
tpsubscribe()和tpunsubscribe()的范例代码
#include <atmi.h>
static long sub_serv;
int tpsvrinit(int argc, char **argv)
{
TPEVCTLevctl;
/*连接TUXEDO系统——tpinit() */
evctl.flags=TPEVSERVICE;
strcpy(evctl.name1,”BANK_MANAGER”);
sub_serv=tpsubscribe(“BANK_TLR_WITHDRAWAL”,
”AMOUNT>300.00”,&evctl,TPSIGRSTRT);
if(sub_serv == -1)
return(-1);
}
int tpsvrdone()
{
if(tpunsubscribe(sub_serv,TPSIGRSTRT)== -1)
{
printf(“Errorunsubscribing to service event\n”);
}
}
建立一个服务调用订阅事件,被调用服务是BANK_MANAGER,当交易BANK_TLR_WITHDRAWAL的AMOUNT域的值大于300.00触发。
用tpunsubscribe()取消订阅。
tppost()的范例代码
void WITHDRAWAL(TPSVCINFO *transb)
{
……
if(amt > 300.00)
{
if( (Fchg(transf,EVENT_NAME,0,”BANK_TLR_WITHDRAWAL”,0)<0) ||
(Fchg(transf,EVENT_NAME,0,gettime(),0)<0)||
(Fchg(transf,EVENT_NAME,0,(char*)&amt,0)<0) ))
{
sprintf(emsg,”Fchg(eventflds) failed :%s”,Fstrerror(Ferror));
}elseif( tppost(“BANK_TLR_WITHDRAWAL”,(char *)transf,0L,
TPNOTRAN|TPSIGRSTRT)<0)
{
if(tperrno!=TPENOENT)
{
sprintf(emsg,”tppost()failed :%s”,tpstrerror(tperrno));
}
}
if( strcmp(emsg,””)!=0)
{
userlog(“WARN:EventBANK_TLR_WITHDRAWAL not posted:%s”
,emsg);
strcpy(emsg,””);
}
}
}
从传入FML中分离交易金额;增加交易过滤规则:金额>300.00,给FML域赋值;调用tppost()。
Ubbconfig相应改变
*SERVERS
TMSYSEVT SRVGRP=EVTGRP1 SRVID=100
RESTART=YMAXGEN=5 GRACE=3600
CLOPT=”-A -- -f tmsysevt.dat”
TMUSREVT SRVGRP=EVTGRP1 SRVID=150
RESTART=YMAXGEN=5 GRACE=3600
CLOPT=”-A -- -f tmusrevt.dat”
TMUSREVT SRVGRP=EVTGRP1 SRVID=200
RESTART=YMAXGEN=5 GRACE=3600
CLOPT=”-A -- -S –p 120”
TMSYSEVT 系统事件代理服务进程
TMUSREVT 用户事件代理服务进程
-f 指定了包含订阅信息的数据文件
-S 表示有第二事件代理,-p决定其轮循时间(单位:秒)
消息队列 Queued Message
本节要点
l 定义
l 基本队列
l 队列设定—qmadmin
l 高级队列
l 交易和管道
l ubbconfig
l 代码范例
可靠队列
当进程通过消息方式进行通讯时,消息在被取用前存储的地方称为消息队列。这些队列是一些存储空间,或者是内存(IPC消息队列),或在硬盘上。内存中的队列在写硬盘前可以清除;这样,在主机故障时,就有丢失信息的风险。基于硬盘的队列可以在主机或网络瘫痪时可靠地保存信息,代价是读写硬盘的开销。
商业上用队列方式使任务可以同步完成。一般地,商业系统需要保证系统总是稳定可靠,良好地完成任务。传统上是使用昂贵的容错系统达到此目标,花费主要是在冗于硬件上,使用队列,往往只要复制部分系统就能达到此效果。
作为请求/应答通讯方式的一种替代,可靠队列允许商业应用通过同步或时序方式使用可靠存储队列进行通讯。BEA TUXEDO /Q提供了这种机制。
其特性提供优点如下:
² 可靠传递
² 同步的、自由处理
² 审计、恢复
/Q ATMI通过按照2段式XA事务协议操作,保证可靠的传输,并且有内建的错误处理能力处理意外情况。
基本队列
/Q提供的API简单而功能强大,有以下两个函数:
² tpenqueue() – 将消息置入队列
² tpdequeue() – 从队列中得到消息
队列由BEATUXEDO管理员创建,定义队列并指定大小。队列全部位于队列空间,队列空间的名字是函数参数之一。每个队列都有一个名字,函数通过名字调用队列。
tpenqueue()参数如下:
² 队列空间名
² 队列名
² 包含置入队列信息的结构
² 置入队列的数据缓冲
² 长度
² 控制标志
tpenqueue(qspace,qname,control_info,buffer,len,flags)
tpdequeue()参数如下:
² 队列空间名
² 队列名
² 包含取队列信息的结构
² 取队列的数据缓冲
² 长度
² 控制标志
tpdequeue(qspace,qname,control_info,buffer,len,flags)
qmadmin范例
qmadmin是一个命令行工具,TUXEDO /Q的一个部分,使管理员可以建立基于硬盘的的队列;qmadmin用于在设备上建立、初始化、列出和删除队列和队列空间。
$qmadmin
QMCONFIG=/usr/apps/atmapp/QUE
>crdl /usr/apps/atmapp/QUE
Starting Offset :0
Size in disk pages:400
Created decice/usr/apps/atmapp/QUE,offset 0,size 400
>qspacecreate
Queue space name:QSPACE
IPC Key for queue space:62639
Size of queue space in disk space:100
Number of queues in queue space:6
Number of concurrent transaction in queuespace:4
Number of concurrent processes in queuespace:9
Number of messages in queue space:3
Error queue name:errque
Initialize exter\nts(y,n[default=n]):y
Blocking factor[default=16]:16
>qopen QSPACE
>qcreate
Queue name:DEPOSIT
Queue order(priority,time,fifo,lifo):fifo
Out-of-ordering enqueuing(top,msgid):none
Retries[default=0]:2
Retry dela in seconds[default=0]:30
High limit for queue capacity warning:80%
Reset(low)limit for queue capacitywarning:0%
Queue capacity command:
No default queue capacity command
Queue ‘DEPOSIT’ created
>qcreate
Queue name:REPLYQ
Queue order(priority,time,fifo,lifo):fifo
Out-of-ordering enqueuing(top,msgid):none
Retries[default=0]:2
Retry dela in seconds[default=0]:30
High limit for queue capacity warning:80%
Reset(low)limit for queue capacitywarning:0%
Queue capacity command:
No default queue capacity command
Queue ‘REPLYQ’ created
说明:
用crdl命令在/usr/apps/atmapp/QUE上建立一个400页的设备
用qspacecreate命令在设备上建立一个100页的队列空间QSPACE,有6个队列。
用qopen命令打开队列空间QSPACE。
用qcreate命令在队列空间QSPACE上建立队列DEPOSIT,FIFO方式,消息可以取出2次。同样建立队列REPLYQ。
高级队列
每个队列都有与之相关的一些控制信息;其中绝大多数内容由应用设定,但是有些由BEA TUXEDO队列软件直接设定。
队列次序
缺省的,消息进出队列的次序由管理员确定,一般是先入先出(FIFO-first in first out);但有时消息不需要立即处理,这样就需要其他的队列次序。BEA TUXEDO提供了几种方案解决之,有:
² 按优先级
² 按时序
² 先进先出
² 后进先出
管理员甚至可以合并使用上述几种方式决定队列次序。
按时释放
当一个消息进队列时,程序员可以决定其在某时间前不可出队列。这个时间可以是一个定值(如:1月7号下午2点)或相对于入队列的时间。当程序试图出队列时,那些‘还没到时间’的消息是不可见的。例:
control_info->deq_time=3600;/* 3600秒后才可以出队列*/
control_info->flags=TPQTIME_REL;/* 表示相对时间值被设定*/
TPQCTL结构
TPQCTL结构用来控制一个消息如何进/出队列
struct tpqctl{
long flags;
long deq_time;
long priority;
long diagnostic;
char msgid[TMMSGIDLEN];
char corrid[TMCORRIDLEN];
char replyqueue[TMQNAMELEN+1];
char failurequeue[TMQNAMELEN+1];
CLENTID cltid;
long urcode;
long appkey;
};
tpenqueue的flags有如下可能:
TPNOFLAGS,TPQPRIORITY,TPQCORRID,[TPQTOP|TPQBEFOREMSGID],[TPQTIME_ABS|TPQTIME_REL], TPQREPLYQ,TPQFAILUREQ
tpdequeue的flags有如下可能:
TPNOFLAGS,TPQWAIT,[TPQGETBYMSGID|TPQGETBYCORID]
本节中有定义:
typedef struct tpqctl TPQCTL;
优先级
一条消息可以被设置一个优先级;优先级决定消息相对于队列中其他消息的位置。高优先级的消息较靠近队列头,可以较早出队列。例:
control_info->priority=100; /*设入队列优先级为最高级*/
control_info->flags=TPQPRIORITY; /* 表示优先级的值已经设定*/
返回和错误队列
在将消息入队列前,程序可以定义两个队列:返回队列和错误队列。当消息出队列时,这些队列中存有原消息的处理结果:返回或错误消息。
相关标识
应用可以在消息上加一个‘标记’,当消息被从一个队列移动到另一个队列并被应用的不同部分处理时可以识别它。这些标记被称为‘相关标识’。
超次序
虽然队列被定义了一个固定的出/入次序,但有时应用需要超越这个次序。BEA TUXEDO的队列工具允许管理员配置程序入队列时可以超越次序的队列。
² 可以将一条消息置于队列头
² 可以将一条消息置于特定消息前
错误诊断
如果tperrno被设成TPEDIAGNOSTIC,则TPQCTL结构中的诊断域将被设成一个错误状态,有以下:
² QMEINVAL 调用时使用了非法标志值
² QMEDADMSGID 非法错误消息ID
² QMENOMSG 队列没有可以取出的消息
² QMEINUSE 队列中有消息,但现在不可用
事务和管道
事务
事务是一种保证一系列操作全部成功或全部失败的机制;通常用来保证对数据库的多次操作全部完成。
BEATUXEDO可以协调本队列修改、其他队列修改和数据库系统操作。当程序调用tpdequeue()将一条消息出队列时,事实上消息仅在程序事务确认时才从队列中除去。如果事务回滚或超时,消息仍在队列中;可以再次操作。系统从而有效地保障该消息仅被处理一次。
TMQUEUE是一个BEATUXEDO系统提供的当程序调用tpenqueue()和tpenqueue()时将消息入、出队列的服务。tpenqueue()和tpenqueue()的第一个参数是队列空间名;该名字必须由TMQUEUE的一个交易发布过。
管道
TMQFORWARD是BEATUXEDO提供的将消息通过调用tpenqueue()将消息前转的服务。
消息将被发送到一个有与读出队列名匹配的交易的服务。消息将在一个事务中出队列并送给服务。如果交易失败,事务回滚、消息将被送回队列,可以重试的次数决定于队列配置;如果达到了限制次数,消息将送入队列空间的错误队列。
ubbconfig的相应改变
*GROUPS
QUE1 LMID=SITE1 GRPNO=2
TMSNAME=TMS_QM TMSCOUNT=2
OPENINFO=”TUXEDO/QM:/apps/atmapp/QUE:QSPACE”
*SERVERS
TMQUEUE SRVGRP=QUE1 SRVID=1
CLOPT=”-sQSPACE:TMQUEUE –“
TMQFORWARD SRVGRP=QUE1 SRVID=5
CLOPT=”---I 2 –q DEPOSIT”
说明:
每个队列空间需要单独创建一个组,本例中为QUE1。TMSNAME是事务管理服务的名字。TMCOUNT决定最少启动几个TMS_QM服务。
TMQUEUE是处理tpenqueue()将请求置入队列的/Q服务。TMQFORWARD是将请求出队列并通过tpcall()将请求送相应的交易。-i决定再次读队列前应该延迟的秒数。-q决定前转请求的来源队列。
客户端代码范例
#include <stdio.h>
#include <atmi.h>
main()
{
char *reqstr;
long len;
TPQCTL qctl;
/* 用tpinit()连接TUXEDO*/
qctl.flags = TPQREPLYQ;
strcpy(qctl.rplyqueue,”RPLYQ”);
if (tpenqueue(“QSPACE”,”TOUPPER”,&qctl,reqstr,0,0)== -1)
{
printf(“tpenqueue(TOUPPER):%s\n”,tpstrerror(tperrno));
if(tperror ==TPEDIAGNOSTIC)
{
printf(“Queuemanager diagnostic %ld\n”,qctl.diagnostic);
}
tpfree(reqstr);
tpterm();
exit (-1);
}
sleep(10);
qctl.flags = TPQWAIT;
if(tpdequeue(“QSACE”, “REPLYQ”,&qctl,&reqstr,&len,TPNOTIME) == -1)
{
printf(“tpdequeue(REPLYQ):%s\n”, tpstrerror(tperrno));
if (tperrno ==TPEDIAGNOSTIC)
{
printf(“Queuemanager diagnotic %ld\n”, qctl.diagnostic);
}
tpfree(reqstr);
tpterm();
exit(-1);
}
printf(“after:%s\n”,reqstr);
tpfree(reqstr);
tpterm();
return (0);
}
会话 Conversations
本节要点
l 简介
l 定义
l ATMI
l UBBconfig
作为对呼叫/应答方式的补充,TUXEDO提供了一种称为会话的通讯方式。该方式用于客户端和服务端需要进行大量、多次数据传输并保持连接时。在一个会话过程中双方会有多次发送和接收。例如,一对客户端/服务端之间传诵一个大的数据库查询结果游标时,需要进行几次传输。
在呼叫/应答方式中,所有的数据必须在一次通讯中传递,不保留任何中间状态信息。在会话模式中,通讯双方使用了一种“半双工”协议。一个进程只能处于发送数据或接收数据状态之一。该通讯协议中,状态信息与数据一同传送。
会话被用来传送大量数据,如:
² 报表
² 数据/图形文件传输
² 大型数据库查询
此模式必须进行另外的ATMI编程才能实现。以下函数协助实现此种连接:
² tpconnect() 建立连接
² tpsend() 发送信息
² tprecv() 接收信息
² discon() 撤消连接(出错时)
在会话持续期间,客户端被绑定在服务上。不利之处是服务在会话期间不能响应其他请求。
ATMI
int tpconnect (char *svc, char *data,long len, long flag)
int tpsend( int cd, char *data, long len,long flag, long *revent)
int tprecev(int cd, char *data, long len,long flag, long *revent)
int tpdiscon(int cd )
ubbconfig应作的改动
*RESOURCES MAXCONV 域内缺省最大会话数
MACHINES MAXCONV 本机器上最大会话数,可以超越*RESOURCES节定义的域内缺省最大会话数
*SERVERS CONV=Y 定义该服务是一个会话方式的服务。
ubbconfig的例子
*RESOURCES
MAXCONV 20
*MACHINES
lcspn1 TUXDIR=”/usr/tuxedo”
MAXCONV=25
*SERVERS
audit SRVGRP=BANKB1 SRVID=1
CONV=Y
CLOPT=”-A”
会话方式的客户端源程序
main(int argc, char *argv[])
{
int ret,cd; /* 循环计数器 */
char *buf; /* 数据指针 */
long len; /*长度 */
long revent; /* tpsend 失败的事件方式 */
/* 连接TUXEDO – tpinit() */
if ( buf = (char*)tpalloc(“STRING”,NULL,1024)==NULL)
{
printf(“tpaclloc():%s\n”,tpstrerror(tperrno));
tpterm();
exit(-1);
}
if ( cd =tpconnect(“AUDIT”,NULL,0,TPSENDONLY)==-1)
{
printf(“tpconnect():%s”,tpstrerror(tperrno));
tpfree(buf);
tpterm();
exit(-1);
}
strcpy(buf, “humpty dumpty”);
if (tpsend(cd , buf ,(long)strlen(buf), 0, &revent) == -1)
{
printf(“tpconnect():%s”,tpstrerror(tperrno));
}
strcpy(buf,“mickey mouse”);
if(tpsend(cd , buf ,(long)strlen(buf), 0 , &revent) == -1)
…
if(tpsend(cd , NULL , 0, TPRECVONLY , &revent) == -1)
…
if( tprecv(cd, &buf , &len, 0, &revent) == -1 )
…
tpfree(buf);
tpterm();
}
连接TUXEDO域;
分配一个1K的ATMI缓冲;
使用tpconnect()连接名为’AUDIT’的一个会话交易;
客户端通过TPSENDONLY将通讯控制权交给服务端。此时无数据传送。返回的通讯描述符存储于cd,用来跟踪绑定在会话上的唯一服务过程;
数据首先被复制到ATMI缓冲中;
数据被发送到会话服务上;
第二部分数据被复制到ATMI缓冲中;
用tpsend()发送到会话服务上;
客户端用TPRECVONLY标志放弃控制权。此处调用tpsend()没有发送数据,客户端准备接收数据;
客户端用tprecv()接收数据。
会话方式的服务端源程序
voidCONV(TPSVCINFO *rqst)
{
static state= SRECV;
long len,revent;
for ( ; ;)
{
switch(state)
{
case SRECV:
if ( tprecv(rqst->cd,&buf, &len, 0, &revent ) == -1)
{
if ( tperrno == TPEEVENT&& revent == TPEV_SENDONLY)
{
userlog(“statechange from receive to send”);
state =SSEND;
}else
{
tpreturn(TPFAIL,0, rqst->data, 0, 0 );
}
}
break;
case SSEND:
strcpy(buf, “all done &protocol complete”);
if ( tpsend(rqst->cd,buf, 0, 0, &revent)==-1)
{
userlog(“tpsend(%d):%s”,revent,tpstrerror(tperrno));
}else
{
userlog(“SENDMESSAGE”);
}
state = SDONE;
break;
case SDONE:
tpfree(buf);
tpreturn(TPSUCCESS, 0,rqst->data, 0, 0);
break;
}
}
}
#define SRECV 1
#define SSEND 2
#define SDONE 3
以上宏定义在程序中用到;
当客户端刚连接交易时,状态被设为RECEIVE;
此部分代码是会话交易在RECEIVE状态中;
tprecv()用来接收客户端数据;
协议在以下情况把状态由RECEIVE转成SEND:
tprecv()返回-1
tperrno被设成TPEEVNT
revent被设成TPEV_SENDONLY
在状态变成SEND后,服务可以调用tpsend();
如果协议有“部分”失败,服务切断客户端连接去处理错误;
代码将会话交易状态转成SEND;
使用tpsend()发送数据;
在一次数据传送后,服务状态被设成DONE;
注意tpreturn用来结束一个成功的会话;tpdiscon()用于出错时结束会话。
广播通知Unsolicited Notification
本节要点
l 定义
l ATMI
一般情况下,客户端发起并控制通讯。TUXEDO额外提供了一种允许客户端接收消息的通讯方式。该通讯方式的发起方可以是其他客户端或服务。我们称之为广播通知。
有两种方式的广播通知:目标是一个客户端(通知);目标是多个客户端(广播)。
为接收此种非主动请求信息,客户端必须指定处理此种信息的回应函数。客户端通常使用信号传递处理信息。而不使用此种方式的客户端可以通过tpchkunsol(),或DIPIN方法处理此种信息。当任何TUXEDO ATMIAPI 被调用时,DIPIN被定义成此类信息的检查标志。
管理员使在系统出错时用此类信息通知客户端。此外,该类信息还有其他许多用途。
ATMI
int tpbroadcast(char *lmid, char*usrname, char *cltname, char *data, long length, long flags)
int tpnotify( CLTID *clentid, char *data,long length, long flags)
int tpchkunsol()
void *tpsetunsol( void (* disp) (char*data, long len, long flags)))()
ubbconfig中的相应信息
*RESOURCES NOTIFY DIPIN
TUXEDO 将用DIPIN方法与客户端进行广播通知方式的通讯。
客户端使用广播通知方式通讯的源代码
#include <atmi.h>
void main()
{
/*作为一个柜员客户端连接TUXEDO——tpinit()*/
if ( tpsetunsol(unsolfunc)==TPUNSOLERR)
{
printf(“tpsetunsol():%s\n”,tpstrerror(tperrno));
}
…
tpchkunsol();/*在一个轮循中*/
…
tpterm();
}
void unsolfunc(char *data,long len,longflag)
{
printf(“Unsolicitedmessage is %s”,data);
return;
}
客户端连接TUXEDO域;
客户端登记回应函数,unsolfunc,当收到广播通知的信息时触发;
客户用tpchkunsol()端轮循处理信息;
接下来是回应函数的定义;
在本例中,广播通知的信息是一个字符串,客户端将其打印出来。
服务端广播通知消息的源代码
void UNSOL(TPSVCINFO *incoming)
{
char*data;
if(data = (char *)tpalloc(“STRING”,NULL,1024)==NULL)
{
userlog(“Errorallocating buffer”);
}
strcpy(data,”Thisdata will be sent to clents”);
if(tpnotify(&incoming->cltid,data,0,0) == -1)
{
userlog(“tpnotify():%s”,tpstrerror(tperrno));
}
if(tpbroadcast(“SITE1”,NULL,”TELLER”,0,0)==-1)
{
userlog(“tpbroadcast():%s”,tpstrerror(tperrno));
}
tpreturn(TPSUCCESS,0,incoming->data,0, 0);
}
广播通知信息必须使用ATMI缓冲,所以,先分配一个ATMI缓冲。
用tpnotify()发送消息给请求了UNSOL交易的客户端。
服务使用tpbroadcast()将同一消息发送到SITE1上所有以TELLER登录的用户。
工作站的客户端workstation Client
BEA TUXEDO 的/WS部分实际上是工作站扩展件。此前,所有的客户端平台都是运行着TUXEDO系统的UNIX,这就限制了TUXEDO的客户端只能运行于UNIX平台。在今天是不可思议的。
/WS通过以下几点突破了以上限制:
² 允许远端不需公告牌即可运行
² 不需要TUXEDO系统域资源
² 不限制客户端的平台
² 服务器上无进程对客户端的一对一的限制
突破这些限制后,服务器不再考虑客户端的表示,不必管理大量的客户端进程而专注于TUXEDO和应用服务,大大扩展了系统的可伸缩性。
本节中,我们开始研究/WS应用。
本节要点
l 定义
l 过程
l 改变ubbconfig
l 网络阻塞
l buildclient
远程/WS客户端(WSC)可以是UNIX或WINDOWS客户端。所有的客户端与TUXEDO通过工作站监听进程(WSL-Workstation Listener)和工作站处理进程(WSH-WorkstationHandler)进行通讯。
当客户端进行tpinit()或tpchkauth()调用时,进程读取本地环境变量WSNADDR。该变量应该与监听连接请求的WSL进程的地址相符。地址值设定在WSL可执行服务的CLOPT的参数中。
WSL进程处理请求,将WSC的网络地址通知WSH进程。WSH进程处理WSC与TUXEDO系统的进一步通讯。
WSH将请求发给合适的服务并将结果返回WSC。如果交易在远程机器上,WSH将请求发给BRIDGE,由它将请求前转到合适的节点。
ubbconfig的相应变化
*RESOURCES
NOTIFY DIPIN
*MACHINES
SITE1
…
MAXWSCLIENTS=150
…
SITE2
…
MAXWSCLIENTS=0
*SERVERS
WSL SRVGRP=”BANKB1” SRVID=500 RESTART=Y
CLOPT=”-A–
-n//lcspn1:3060
-d/dev/xti/tcp
-m2 –M 7 –x 5 –I 5 –T 60”
通知客户端的方式设为“DIPIN”,使用Windows的消息仿UNIX信号,若消息为WM_TIMER则对应tpchkunsol()。
MAXWSCLIENTS表示该机最多允许连接的工作站数目。
工作站监听进程启动参数如下:
-n 指定交易请求连接TUXEDO应用环境的监听进程的主机名和端口号。格式如下:
//lcspn1 主机名
: 间隔符
3060 端口号
-d WSL和WSH用于传递ATMI数据的的设备
-m tmboot最少启动的WSH进程数
-M tmboot最多启动的WSH进程数
-x 每个WSH支持的工作站数
-I 工作站连接应用许可的最大耗时
-T 无响应连接许可时间
PC上的环境变量设置
set TUXDIR=C:\TUXEDO
set WSNADDR=//lcspn1:3060
set WSDEVICE=/dev/xti/tcp
set WSENVFILE= C:\ENV4WS
set WSTYPE=DIFF
set TMPDIR= C:\tmp
set WSRPLYMAX=64K
set APP_PW=HOMERUN
注意:WSNADDR可以是一些由逗号隔开的使用相同端口的地址,或由竖线隔开自由选择端口。例:
WSNADDR=//lcspn1:3050,//lcspn2:3050
WSNADDR=(//lcspn1:3050|//lcspn2:3050)
TUXDIR TUXEDO系统软件位置
WSNADDR WSL网络地址
WSDEVICE 网络设备
WSENVFILE 环境变量文件
WSTYPE 机器类型,控制编、解码
TMPDIR 存储返回的目录
WSRPLYMAX 应用返回缓冲内存大小
APP_PW 应用密码
编译:
buildclient –w –v –o atmclt –f atmclt.c
-w 表示是WS客户端,Windows将通过一个DLL去访问ATMI。
/Domain作为TUXEDO的一组件,使独立的TUXEDO应用可以进行通讯和共享资源。每个应用环境视作一个’domain’。这种结构有以下优点:
l 仍然可以访问远程其他域的数据
l 应用管理工作可以分散进行
l 资源可以根据计算的需要合适地分配
一个域可以跨越多台(个)机器或处理器。所有的客户端通过BB(Bulletin Board)了解所有的机器上提供的交易。BB间的一致性通过DBBL(DistinguishedBulletin Board Liaison)来保证。
通过/Domain,可以维护独立于主域的BB,可以设定那些交易可以响应其他机器。当一个远程域提出一个合法的交易请求时,/Domain将请求发送到被请求域并把返回送到请求进程。
以下介绍进行域间通讯时需修改的配置。
本节要点
l 概念解释
l 配置过程
——环境变量
——ubbconfig
——dmconfig
——dmloadcf
使用TUXEDO组件/DOMAINS时,需要对管理配置作一些改变。在以下例子中,会创建一个独立的测试应用环境(DOMAINID是TEST),它可以读取/请求另一个应用的交易(ProdCust)的数据。
服务GWTDOMAIN(GWT)负责响应域间通讯。GWADM和DMADM是处理管理交易和域服务的管理服务。这些服务必须配置在UBBCONFIG文件中。配置信息必须在远程和本地应用环境中定义。
服务GWTDOMAIN通过TCP/IP协议与其他域进行通讯。物理上远程的域的应用位置是透明的。
服务GWTDOMAIN是双向的:可以处理远程域发来的请求也可以向远程域发出请求。
除UBBCONFIG外,配置/DOMAINS还需要一些信息。这些信息在DMCONFIG文件中。DMCONFIG的文本文件通过BDMCONFIG编译成二进制文件。
过程
第一步:UBBCONFIG应作相应改动
为/DOMAIN建立的新组应该和其他应用组隔离开。其一用于管理,其他是网关服务。
UBBCONFIG
*RESOURCES
IPCKEY 49152
MAXACCESSERS 2
MAXSERVERS 25
MASTER SITE1
MODEL SHM
*MACHINES
class2 LMID=SITE1
TUXDIR=”/usr/tuxedo”
APPDIR=”/usr/apps/atmapp”
TUXCONFIG=”/usr/apps/atmapp/atmapp.tux”
*GROUPS
LDMGRP LMID=SITE1 GRPNO=20
LGWGRP LMID=SITE1 GRPNO=30
#下一行用于‘prod’域
APP1 LMID=SITE1 GRPNO=10
*SERVERS
DMADM SRVGRP=LDMGRP SRVID=200
GWADM SRVGRP=LGWGRP SRVID=310
GWTDOMAIN SRVGRP=LGWGRP SRVID=320
#下一行用于‘prod’域
CUSTOMER CLOPT=”-A” SRVGRP=APP1 SRVID=100
*SERVICES
#下一行用于‘prod’域
ProdCust
第二步:为域间请求创建DMCONFIG
下文的ASCII数据存在的文件一般称为DMCONFIG,由此生成的二进制格式文件称为BDMCONFIG。以下的DMCONFIG存在于“TEST“域,用来请求远程的”prod“域的”ProdCust“交易。
DMCONFIG on TEST DOMAIN
*DM_LOCAL_DOMAINS
test GWGRP=LGWGRP
TYPE=TDOMAIN
DOMAINID=”TEST”
DMTLOGDEV=”/usr/apps/atmapp/logs/DLOG”
*DM_REMOTE_DOMAINS
production TYPE=TDOMAIN
DOMAINID=”prod”
*DM_TDOMAIN
prod NWADDR=”//lcspn1:3070”
NWDEVICE=”/dev/xti/tcp”
TEST NWADDR=”//lcspn2:3070”
NWDEVICE=”/dev/xti/tcp”
*DM_REMOTE_SERVICES
ProdCust
*DM_LOCAL_SERVICES
第三步:创建DMCONFIG指定对域外提供的交易
下文的DMCONFIG位于域’prod’,该域将向其他域提供可调用交易:ProdCust。
域‘prod’上的DMCONFIG
#本地域信息
*DM_LOCAL_DOMAINS
#LMID
production GWGRP=LGWGRP
#域描述:TDOMAIN即TUXEDODOMAINS
TYPE=TDOMAIN
#域的唯一标识符
DOMAINID=”prod”
#交易的日志
DMTLOGDEV=”/usr/apps/atmapp/logs/DLOG”
#远程域信息
*DM_REMOTE_DOMAINS
test TYPE=TDOMAIN
DOMAINID=”TEST”
*DM_TDOMAIN
#地址和设备名
prod NWADDR=”//lcspn1:3070”
NWDEVICE=”/dev/xti/tcp”
TEST NWADDR=”//lcspn2:3070”
NWDEVICE=”/dev/xti/tcp”
*DM_REMOTE_SERVICES
*DM_LOCAL_SERVICES
#远程域可以使用的交易
ProdCust
第四步:设定环境变量
/DOMAIN进程需要额外的环境变量去访问/DOMAINS配置信息
exportBDMCONFIG=/usr/apps/atmapp/atmapp.bdm
第五步:编译ubbconfig
本过程是从两个域中相同的UBBCONFIG生成二进制文件TUXCONFIG。在本例中,UBBCONFIG的信息位于’ubbconfig’。
tmloadcf –y ubbconfig
第六步:编译dmconfig
本过程是创建二进制DOMAINS配置文件,BDMCONFIG,在两个域中相同;而两者都有的文件‘dmconfig’内容是不同的。
dmloadcf –y dmconfig
--转自必应