TUXEDO教程

第一章 开发BEA Tuxedo应用程序

§1.1 开发前的思考

在开发BEA Tuxedo应用程序之前,你需要先搞清楚一系列和设计开发相关的概念,如识别什么是客户机,有哪些方法可以从外界收集数据并提交服务器进行业务处理;识别什么是服务器,哪些程序包容了可以处理客户机输入的商业逻辑;识别什么是类型缓冲区,客户程序在向其这程序发送数据前如何分配内存区域;什么是BEA Tuxedo的消息范例等。最后你还要弄明白客户程序是通过调用ATMI库来访问BEA Tuxedo系统的。

§1.2 创建BEA Tuxedo的客户程序

创建BEA Tuxedo的客户程序与在C和C++编程语言中创建其它应用程序一样,BEA Tuxedo提供了一个其于C语言的编程接口,即应用程序事务监控接口ATMI,这套接口很容易使用,以便用于开发客户程序和服务程序。除了C语言接口外,BEA Tuxedo还提供了COBOL接口。

客户程序的任务

客户程序一般执行如下任务:

⑴.    调用tpchkauth()决定加入一个应用程序所需的安全级别。可能出现的响应包括:没有安全级别,应用程序口令,应用程序授权,访问控制列表,连接级加密,公钥加密,审计。这些可以根据你的需求进行选择;

⑵.    调用tpinit()来连接到一个BEA Tuxedo应用程序,所需的安全信息作为tpinit()的参数传给了应用程序;

⑶.    执行服务请求;

⑷.    调用tpterm()来断开和BEA Tuxedo应用程序的连接。

§1.3 创建的服务程序

尽管开发者使用ATMI编程接口来创建BEA Tuxedo客户程序和服务程序,但服务程序不全部由开发者来编写,开发者只需写一些称为服务的商业函数,然后和BEA Tuxedo的一些二进制程序联编成一个可执行的服务程序。BEA Tuxedo服务程序启动后,它总是保持运行状态,只到接收到一个shutdown消息为止。一个典型的BEA Tuxedo服务程序在shutdown或reboot之前都在执行着数千个服务。

服务程序的任务

⑴.    在BEA Tuxedo服务程序启动时,执行tpsvrinit()函数,可以在里面打开一些如数据库之类的资源供以后使用;

⑵.    在BEA Tuxedo服务程序关闭时,执行tpsvrdown()函数,可以在里面关闭tpsvrinit()中打开的资料;

⑶.    BEA Tuxedo服务程序以服务的形式来响应客户程序的请求,客户程序不是通过名字来调用服务程序的,而是调用服务,客户程序不知道处理它请求的服务程序的位置;

⑷.    服务程序调用tpreturn()函数来结束服务请求,并返回一个缓冲区,必要时,将它传给客户程序;

§1.4 在应用程序中使用类型缓冲区

在Bea Tuxedo系统中的所有通信过程都是通过类型缓冲区来完成的,Bea Tuxedo系统提供了大量的类型缓冲区来供开发者使用。所有类型缓冲区都必须通过Bea Tuxedo的tpalloc(), tprealloc(), tpfree()这些ATMI来分配回收,它们都有特定的头部。

 

统一定义的类型缓冲区可以使它们在跨越不同网络、不同协议、不同CPU构架以及不同操作系统之间得到统一的处理,这就使得开发者在分布式计算环境中有效地避开了异构网络和异构计算机系统带来的差异,把精力集中在商业逻辑的开发上。

§1.5 在BEA Tuxedo应用程序中使用消息范例

1.BEA Tuxedo系统提供多种通信模式

⑴.同步Request/Response模式;

⑵.异步Request/Response模式;

⑶.嵌套调用;

⑷.调用转发;

⑸.会话通信;

⑹.主动消息通告;

⑺.基于事件的通信;

⑻.基于队列的通信;

⑼.使用事务。

2.            同步的Request/Response模式

要进行同步调用,Bea Tuxedo客户程序使用ATMI函数tpcall()把一个请求送到服务程序,它不是通过名字来调用服务程序的,而是通过特定的服务来完成。客户程序要等到服务程序作出响应后才处理后面的工作,也就是说,它在收到服务程序的响应之前一直处于阻塞状态。

3.异步Request/Response模式

要进行异步调用,客户程序必须调用两个ATMI函数:tpacall(3c)函数,用于请求一个服务;tpgetrply(3c)函数,用于取得服务程序的响应。客户程序在请求和响应之间要完成特定任务时,可以采用这种模式。

4.使用嵌套调用

一个服务可以充当BEA Tuxedo客户程序,去调用其它BEA Tuxedo服务,换句话说,你请求的服务需要调用其它服务才能处理请求。BEA Tuxedo客户程序调用了服务X,等待它的响应,服务X调用服务Y后也处于等待状态,当服务X得到响应后,再给客户程序一个响应,这种机制的特点是效率高。

5.使用调用转发

在嵌套服务中,最里层嵌套服务可以直接给客户程序一个响应,没有必要按照调用栈逐级返回,这就使其它嵌套服务可以处理其它请求,当第一个服务是一个分发代理时,这种模式是非常有用的。在嵌套调用中,被客户调用的服务X使用tpforward(3c)函数把请求传给服务Y,服务X没有tpreturn(3c)函数。客户程序不用管请求是由谁来完成的,因此,转发调用对客户程序是透明的。

6.会话通信

会话通信适合于有多个缓冲区需要以有状态的方式在BEA Tuxedo客户程序和服务之间传递的场合。恰当地使用BEA Tuxedo的会话,因为参与会话的服务器在会话结束之前是不可用的。要完成会话通信,你的代码需要遵循如下步骤:

⑴.客户程序使用tpconnect()启动会话;

⑵.客户程序和服务使用tpsend()和tprecv()函数进行数据交换,一个特殊的标记指示着当前由哪一方来控制着会话;

⑶.当服务程序调用tpreturn()或tpdiscon()函数时,会话正常终止。

7.主动消息通告

要处理服务器的消息通知,客户程序必须使用tpsetunsol()函数来创建一个消息处理器,要发送主动消息,BEA Tuxedo客户程序或服务程序可以调用tpnotify()来把消息传递给单个客户程序,也可以通过tpbroadcast()函数来把消息同时广播给多个客户程序。当客户程序收到主动消息后,BEA Tuxedo系统调用客户程序的主动消息处理器来处理。

在一个基于信号系统中,客户程序没有必要处理所有的主动消息,然而,在一个非信号系统中,客户程序必须使用tpchkunsol()函数来检查主动消息。当客户程序调用一个服务请求时,tpchkunsol()被隐含地调用。在调用tpnotify()时,如果你设置了tpack标记位,你将会收到一个请求通知。

8.基于事件的通信

在基于事件的通信中,事件可以被发送到应用程序队列、LOG文件和系统命令。当BEA Tuxedo服务或客户程序调用tppost()函数时,任何一个BEA Tuxedo客户程序都可以使用tpsubscribe()函数订阅用户自定义事件;当BEA Tuxedo系统检测事件时,客户程序也可以订阅系统定义事件。当一个服务器死了,.SysServerDied事件就会被发布,它由BEA Tuxedo系统自动完成,不需要应用服务器干预。

9.基于队列的通信

为了实现了和/Q系统的接口,BEA Tuxedo客户程序使用两个ATMI函数,使用tpenqueue()把消息放入队列空间,使用tpdequeue()来把消息从队列空间中取走。

下面演示了点对点异步消息机制。一个客户程序使用tpenqueue()函数将消息传给服务,响应队列和失败队列的名字可以作为参数包含在tpenqueue()调用中,由于在队列中的数据是持续的,因此,所有和排队消息相关的响应消息和失败消息都可以从相应的响应队列和失败队列中取得。客户程序可以使用缺省的排队顺利,即按放放顺利排队,先进先出;也可以改变排队规则,如把一个消息放在队列开始,或放到另一个队列前面。Tpenqueue()调用把消息送到TMQUEUE服务器,并被放入固定存储体中进行排队,然后给客户程序发送一个通知消息。队列管理器给消息分配一个标识符,使用它可以随时将消息踢出队列,也可以用于tpenqueue()中,指示将新消息紧挨着标识符标识的消息。在消息出队时,要出队消息的事务必须成功地提交。客户程序使用tpdequeue()来使消息出队。

         下面演示了消息被转发到另一个服务器。客户程序发出一个消息,要调用服务器上的X服务,X服务接收消息后,处理消息中的指令,然后把响应放入队列空间,客户程序再从队列空间中取出。排队系统对于服务来说是透明的,也就是说,不论服务请求是从队列发出的,还是通过tp(a)call发出的,服务都能接受。

10.使用事务

要使用事务,应用程序开发者需要使用如下ATMI函数:

⑴.tpbegin(),用于开始一个事务;

⑵.tpcommit(),开始一个二阶段提交处理;

⑶.tpabort(),产即终止事务。

任何放在begin,commit/abord之外的代码不包含事务中。在下面的例子中,客户程序打开了一个事务,请求了两个服务,并且提交了事务。因为服务请求是在事务开始和提交之间完成的,所以两个服务的行为都被了事务记录。


第二章 一个简单的Tuxedo应用程序simpapp

本章介绍了BEA Tuxedo的一个简单例子,用C语言编写的simpapp,它包含了一个客户程序和一个服务器,服务器只执行一个服务:从客户程序接收小写字母,将其转换成大写后,返回给客户程序。在使用这个例子之前,需要在系统中安装C语言编译器。

准备simpapp的文件和资源

在准备simpapp例子之前,系统中必须安装了BEA Tuxedo软件,而且要设置$TUXDIR环境变量,NT平台下为%TUXDIR%,并把%TUXDIR%\bin加到PATH中,最后还要确保你的工作目录要有写权限。完成这些工作后,请按如下步骤来准备simpapp程序:

⑴.  复制simpapp所需要的所有文件,它们位于$TUXDIR/samples/atmi/simpapp目录下;

⑵.  检查并编译客户程序;

⑶.  检查并编译服务程序;

⑷.  编辑并加载配置文件;

⑸.  启动应用程序;

⑹.  执行运行时应用程序;

⑺.  监视运行时应用程序;

⑻.  关闭应用程序。

完成这个例子后,你应该理解客户程序和服务器所执行的任务,根据你的环境编写一个配置文件,通过tmadmin检查应用程序的活动。同时,你应该理解BEA Tuxedo应用程序的基本组成部分:客户程序、服务器程序、配置文件,通过BEA Tuxedo系统的哪些命令来管理你的应用程序。

1.复制simpapp例子的相关文件

⑴.创建目录:

mkdir simpdir

cd simpdir

⑵.设置并导出环境变量

TUXDIR=BEA Tuxedo系统的根目录,如UNIX系统下可以设置为:

TUXDIR="/usr/tuxedo",NT系统下可以设置为:

                            TUXDIR="G:\Program Files\BEA System\Tuxedo"

TUXCONFIG=当前工作目录加上/tuxconfig,如UNIX系统下可以设置为:

        TUXCONFIG="/usr/me/simpdir/tuxconfig",NT系统下可以设置为:

        TUXCONFIG="G:\simpdir\tuxconfig"

PATH=$PATH:$TUXDIR/bin

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TUXDIR/lib

export  TUXDIR  TUXCONFIG  PATH  LD_LIBRARY_PATH

TUXDIR和PATH用于访问BEA Tuxedo系统的文件和执行命令,在Sun Solaris系统中,必须把/usr/5bin放在PATH中的第一个,在RS6000中的AIX上,将LD_LIBRARY_PATH替换成LIBPATH,在HP9000中的HP-UX上,将LD_LIBRARY_PATH替换为SHLIB_PATH。

设置TUXCONFIG的目的是用于加载配置文件。

⑶.复制simpapp文件,

cp $TUXDIR/samples/atmi/simpapp/* .

⑷.查看文件

$ls

README env simpapp.nt ubbmp wsimpcl

README.as400 setenv.cmd simpcl.c ubbsimple

README.nt simpapp.mk simpserv.c ubbws

文件说明:

simpcl.c客户程序的源代码

simpserv.c服务程序的源代码

ubbsimple应用程序配置文件的纯文本形式

2.检查并编译客户程序

⑴.检查客户程序

$more simpcl.c

#include <stdio.h>

#include "atmi.h"          /*  TUXEDO的头文件 */

 

#if defined(__STDC__) || defined(__cplusplus)

main(int argc, char *argv[])

#else

main(argc, argv)

int argc;

char *argv[];

#endif

{

         char *sendbuf, *rcvbuf;

         long sendlen, rcvlen;

         int ret;

 

         if(argc != 2) {

                   (void) fprintf(stderr, "Usage: simpcl string\n");

                   exit(1);

         }

         /* 作为一个客户过程连接到System/T  */

         if (tpinit((TPINIT *) NULL) == -1) {

                   (void) fprintf(stderr, "Tpinit failed\n");

                   exit(1);

         }

        

         sendlen = strlen(argv[1]);

 

         /* 分配一个供请求响应使用的STRING 缓冲区 */

         if((sendbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {

                   (void) fprintf(stderr,"Error allocating send buffer\n");

                   tpterm();

                   exit(1);

         }

 

         if((rcvbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {

                   (void) fprintf(stderr,"Error allocating receive buffer\n");

                   tpfree(sendbuf);

                   tpterm();

                   exit(1);

         }

 

         (void) strcpy(sendbuf, argv[1]);

 

         /* Request the service TOUPPER, waiting for a reply */

         ret = tpcall("TOUPPER", (char *)sendbuf, 0,

(char **)&rcvbuf, &rcvlen, (long)0);

 

         if(ret == -1) {

                   (void) fprintf(stderr, "Can't send request to service TOUPPER\n");

                   (void) fprintf(stderr, "Tperrno = %d\n", tperrno);

                   tpfree(sendbuf);

                   tpfree(rcvbuf);

                   tpterm();

                   exit(1);

         }

 

         (void) fprintf(stdout, "Returned string is: %s\n", rcvbuf);

 

         /* Free Buffers & Detach from System/T */

         tpfree(sendbuf);

         tpfree(rcvbuf);

         tpterm();

         return(0);

}

说明:

语句

说明

atmi.h

调用ATMI函数必须的头文件

tpinit()

客户程序调用它来加入应用程序

tpalloc()

用于分配类型缓冲区的ATMI函数,STRING是五种BEA Tuxedo缓冲区数据类型之一,sendlen+1表示缓冲区类型,因为以空字符结尾,所以长度加1

tpcall()

把消息缓冲区送到TOUPPER服务,它提供了响应缓冲区的地址,它一直等待着返回消息

tpterm()

用于退出应用程序的ATMI函数,

tpfree()

释放分配的缓冲区,是和tpalloc()相对应的函数

⑵.编译客户程序

$buildclient -o simpcl -f simpcl.c

                   -o指明输出目标文件名,-f指出源文件名

3.检查并编译服务程序

⑴.检查服务程序

$more simpserv.c

#include <stdio.h>

#include <ctype.h>

#include <atmi.h>        /* TUXEDO Header File */

#include <userlog.h>  /* TUXEDO Header File */

 

/* 当服务器启动时,在处理请求之前,tpsvrinit被执行,这个不是必须的,对应的函数是shutdown*/

 

#if defined(__STDC__) || defined(__cplusplus)

tpsvrinit(int argc, char *argv[])

#else

tpsvrinit(argc, argv)

int argc;

char **argv;

#endif

{

         /* 当argc, argv没有被使用时,一些系统会发了警告 */

         argc = argc;

         argv = argv;

 

         /* userlog用于将TUXEDO消息写到日志文件中 */

         userlog("Welcome to the simple server");

         return(0);

}

 

/*  TOUPPER真正处理客户请求,它接收的参数是一个缓冲区指针 */

#ifdef __cplusplus

extern "C"

#endif

void

#if defined(__STDC__) || defined(__cplusplus)

TOUPPER(TPSVCINFO *rqst)

#else

TOUPPER(rqst)

TPSVCINFO *rqst;

#endif

{

         int i;

         for(i = 0; i < rqst->len-1; i++)

                   rqst->data[i] = toupper(rqst->data[i]);

         /* 返回转换后的类型缓冲区 */

         tpreturn(TPSUCCESS, 0, rqst->data, 0L, 0);

}

         说明:

语句

说明

whole file

整个服务程序不提供main函数,在build时,由BEA Tuxedo系统提供。

tpsvrinit()

在服务器初始化即处理请求之前被调用。若没有提供该函数,BEA Tuxedo系统会提供一个缺省的,它向USERLOG中写一条消息,说明服务器已经被启动。userlog(3c)是系统提供的一个写日志的方法。

TOUPPER()

simpserv提供的唯一一个服务,它接收一个TPSVCINFO结构,它包含了要被转换成大写的字符串。

for loop

BEA Tuxedo系统的循环,用于逐一转换。

tpreturn()

 

⑵.编译服务器

$buildserver –o simpserv –f simpserv.c –s TOUPPER

–s TOUPPER指明了在服务器启动时需要提供的服务

4.编辑并加配置文件

⑴.怎样编辑配置文件

#ident          "@(#) apps/simpapp/ubbsimple       $Revision: 1.1.10.1 $"

 

#Skeleton UBBCONFIG file for the TUXEDO Simple Application.

# 将<>里而的内容替换成实际值.

 

*RESOURCES

IPCKEY                <Replace with a valid IPC Key>

 

#Example:

#IPCKEY             123456

 

DOMAINID        simpapp

MASTER             simple

MAXACCESSERS     10

MAXSERVERS          5

MAXSERVICES         10

MODEL                         SHM

 

*MACHINES

DEFAULT:

              APPDIR="<Replace with the current directory pathname>"

              TUXCONFIG="<Replace with your TUXCONFIG Pathname>"

              TUXDIR="<Directory where TUXEDO is installed>"

#Example:

#           APPDIR="/home/me/simpapp"

#           TUXCONFIG="/home/me/simpapp/tuxconfig"

#           TUXDIR="/usr/tuxedo"

# 对于NT平台,可以替换成如下值

#           APPDIR="G:\JQEJB\simpapp"

#           TUXCONFIG="G:\JQEJB\simpapp\tuxconfig"

#           TUXDIR="G:\Program Files\BEA System\Tuxedo"

<Machine-name>     LMID=simple

 

#Example:

#JQ               LMID=simple

 

*GROUPS

GROUP1

     LMID=simple        GRPNO=1      OPENINFO=NONE

 

*SERVERS

DEFAULT:

              CLOPT="-A"

 

simpserv     SRVGRP=GROUP1 SRVID=1

 

*SERVICES

TOUPPER

⑵.加载配置文件

$ tmloadcf ubbsimple

Initialize TUXCONFIG file: /usr/me/simpdir/tuxconfig [y, q] ? y

$

5.启动应用程序

⑴.执行tmboot启动应用程序

$tmboot

Boot all admin and server processes? (y/n): y

Booting all admin and server processes in

/usr/me/simpdir/tuxconfig

Booting all admin processes ....

exec BBL -A:

process id=24223 ... Started.

Booting server processes ...

exec simpserv -A :

process id=24257 ... Started.

2 processes started.

BBL是应用程序中监视共享内存结构的管理进程,simpserv是连续运行的simpapp服务程序,它等待着处理请求。

6.如何执行运行时应用程序

$ simpcl “hello, world”

Returned string is: HELLO, WORLD

7.如何监视运行时应用程序

         作为管理者,你可以使用tmadmin命令解释器来检测一个应用程序,并作一些动态的改变,要运行该命令,你必须设置TUXCONFIG环境变量。tmadmin可以解释超过50个命令,要看完整的列表,请看tmadmin(1),这里我们使用了两个tadmin命令。

         ⑴.输入如一命令:

                   $tmadmin

                   显示:

tmadmin - Copyright (c) 1999 BEA Systems, Inc. All rights

reserved.

⑵.输入printserver(psr)命令,显示:

> psr

a.out Name  Queue Name  Grp Name  ID RqDone Load Done  Current Service

--------------  ---------------  -------------  -- --------- --------------  ------------------

BBL                 531993                simple       0      0            0                         ( IDLE )

simpserv     00001.00001 GROUP1            1        0            0                         ( IDLE )

⑶.输入printservice(psc)命令,显示:

Service Name Routine Name a.out Name Grp Name ID Machine # Done Status

------------ --- ------------------ ------------- ------------ --- ---------- --------- ---------

TOUPPER   TOUPPER     simpserv  GROUP1  1  simple    -    AVAIL

8.如何关闭应用程序

⑴.运行tmshutdown命令来关闭应用程序

$ tmshutdown

Shutdown all admin and server processes? (y/n): y

Shutting down all admin and server processes in

/usr/me/simpdir/tuxconfig

Shutting down server processes ...

Server Id = 1 Group Id = GROUP1 Machine = simple: shutdown

succeeded.

Shutting down admin processes ...

Server Id = 0 Group Id = simple Machine = simple: shutdown

succeeded.

2 processes stopped.

$

⑵.检查ULOG文件

$ cat ULOG*

$

113837.tuxmach!tmloadcf.10261: CMDTUX_CAT:879: A new file system

has been created. (size = 32 4096-byte blocks)

113842.tuxmach!tmloadcf.10261: CMDTUX_CAT:871: TUXCONFIG file

/usr/me/simpdir/tuxconfig has been created

113908.tuxmach!BBL.10768: LIBTUX_CAT:262: std main starting

113913.tuxmach!simpserv.10925: LIBTUX_CAT:262: std main starting

113913.tuxmach!simpserv.10925: Welcome to the simple server

114009.tuxmach!simpserv.10925: LIBTUX_CAT:522: Default

tpsvrdone() function used.

114012.tuxmach!BBL.10768: CMDTUX_CAT:26: Exiting system


第三章 一个完整的Tuxedo应用程序bankapp

bankapp是BEA Tuxedo系统提供一个简单的银行应用程序,它完成如下功能:打开和关闭账号,查询账号余额,存款和取款,账号之间转账。

§3.1 熟悉bankapp的文件

BEA Tuxedo系统提供了一个演示数据库,bankapp例子中有很多个地方使用了命令和SQL代码来访问它。bankapp由如下文件组成:

源文件

生成的文件

内容说明

ACCT.ec

ACCT.c, ACCT.o,

ACCT

包括两个服务:OPEN_ACCT和CLOSE_ACCT 用于打开和关闭账号

ACCTMGR.c

ACCTMGR

订阅事件和记录通告日志的服务器,包含: WATCHDOG 和 Q_OPENACCT_LOG 服务

AUDITC.c

AUDITC

包括一个会话服务器处理来自客户端auditcon的请求

BAL.ec

BAL.c, BAL.o,

BAL

包括一组服务:ABAL, TBAL, ABAL_BID, 和

TBAL_BID 允许audit客户获得银行或支行账号以及余额

BALC.ec

BALC.c, BALC.o,

BALC

包括两个服务:ABALC_BID和TBALC_BID。这些服务和TBAL_BID,ABAL_BID是一样的。

Bankmgr.c

bankmgr

订阅特定事件客客户程序

cracl.sh

-

用于创建访问控制列表ACL以演示ACL安全的shell脚本

crqueue.sh

-

notification.用于创建应用程序队列以供事件通告使用的shell脚本

Crusers.sh

-

创建用户和组以演示验证安全级别的shell脚本

event.flds

-

在事件特征中用到的字段表文件

FILES 

-

bankapp用到的所有文件列表

README

-

在除NT以外的所有平台上安装指南

README.nt

-

NT平台上的安装指南

README2

-

在bankapp中演示新特性的自述文件

README2.nt

-

在NT平台上演示新特性自述文件

RUNME.cmd

-

在NT平台上创建、配置、启动、关闭应用程序的交互式脚本

RUNME.sh

-

UNIX平台下的脚本文件,功能同上

showq.sh!

-

显示消息队列的状态和内容的shell脚本

TLR.ec

TLR.c, TLR.o, TLR

包含三个服务:WITHDRAWAL, DEPOSIT和INQUIRY

Usrevtf.sh

-

创建供TMUSREVT服务器使用的ENVFILE文件

XFER.c

XFER.o, XFER

包括TRANSFER服务

aud.v

aud.V, aud.h

一个在audit 客户和BAL服务器之间使用的FML view

Appinit.c

appinit.o

包含供所有服务器(除TLR以外)使用的用户自定义版的tpsvrinit()和tpsvrdown()

audit.c

audit.o, audit

通过ABAL, TBAL, ABAL_BID和TBAL_BID 服务获得银行及支行账号和余余额的客户程序

auditcon.c

auditcon

audit的交互式版本,使用ABAL, TBAL, ABALC_BID和TBALC_BID.服务

bankapp.mk

-

UNIX下应用程序Make文件

bankapp.nt

-

NT平台下应用程序的Make文件

bank.flds

bank.flds.h

由服务器使用,包含银行数据库和辅助FML字段文件

bank.h

-

bankapp应用程序的头文件

bankvar

-

包括bankapp使用的环境变量,其它环境变量在ENVFILE中定义,后者被前者调用

Crbank.sh

crbank

为bankapp在SHM模式下运行时创建数据的shell脚本

crbankdb.sh

crbankdb

为一个服务器组创建数据库的shell脚本

crtlog.sh

crtlog, TLOG

在master站和non-master站的UDL上创建UDL和TLOG的shell脚本

driver.sh

driver

通过FML缓冲区驱动应用程序的shell脚本

envfile.sh

envfile, ENVFILE

创建供tmloadcf使用的ENVFILE文件的shell脚本

gendata.c

gendata

生成10个支行,30个出纳员及200个账号的程序

Gentran.c

gentran

从DEPOSIT, WITHDRAWAL, TRANSFER和INQUIRY.生成事务请求的程序

populate.sh

populate

通过FML缓冲区向数据库中插入支行、出纳员、和账号信息的shell脚本

Ubbmp

TUXCONFIG

在MP-mode下使用的UBBCONFIG文件

ubbshm

TUXCONFIG

在SHM-mode下使用的UBBCONFIG文件

util.c

util.o

包含一组由服务使用的函数,如getstr1()等

bankclt.c

bankclt

bankapp的客户程序

§3.2 检查bankapp的客户程序

1.bankclt.c文件

         它是一个基于文本的客户,提供了:余额查询、取款、存款、转账、打开账号、关闭、号、退出程序等几大功能。除退出应用程序以外,每一个选项都调用了一个执行如下功能的例程:

⑴.通过get_account(), get_amount(), get_socsec(), get_phone(), get_val()函数从键盘获得用户输入。

⑵.将值存入一个全局的FML缓冲区(*fbfr),有些函数需要更多的字段,需要根据服务器所需的信息来确定。

⑶.通话通过do_tpcall()函数调用BEA Tuxedo系统服务,下面列出了一些函数和服务。

函数名

输入FML字段

输出 FML字段

服务名称

BALANCE()

ACCOUNT_ID

SBALANCE

INQUIRY

WITHDRAWAL()

ACCOUNT_ID SAMOUNT

SBALANCE

WITHDRAWAL

DEPOSIT()

ACCOUNT_ID SAMOUNT

SBALANCE

DEPOSIT

TRANSFER()

ACCOUNT_ID (0) ACCOUNT_ID (1) SAMOUNT

SBALANCE (0) SBALANCE (1)

TRANSFER

OPEN_ACCT()

LAST_NAME FIRST_NAME MID_INIT

SSN

ADDRESS

PHONE ACCT_TYPE BRANCH_ID SAMOUNT

ACCOUNT_ID SBALANCE

OPEN_ACCT

CLOSE_ACCT()

ACCOUNT_ID

SBALANCE

CLOSE_ACCT

⑷.调用成功完成后,每个函数可以从返回的FML缓冲区中取得需要的数据

do_tpcall()函数的代码如下:

static int do_tpcall(char *service){

long len;

char *server_status;

/* 开始一个全局事务 */

if (tpbegin(30, 0) == -1) {

(void)fprintf(stderr, "ERROR: tpbegin failed (%s)\n",tpstrerror(tperrno));

return(-1);

}

/* 使用用户数据请求服务 */

if (tpcall(service, (char *)fbfr, 0, (char **)&fbfr, &len,0) == -1) {

if(tperrno== TPESVCFAIL && fbfr != NULL &&

(server_status=Ffind(fbfr,STATLIN,0,0)) != 0) {

         (void)fprintf(stderr, "%s returns failure   (%s)\n", service,server_status);

}else {

         (void)fprintf(stderr,"ERROR: %s failed (%s)\n", service,

         tpstrerror(tperrno));

}

/* 终止事务*/

(void) tpabort(0);

return(-1);

}

/* 提交事务 */

if(tpcommit(0) < 0) {

(void)fprintf(stderr, "ERROR: tpcommit failed (%s)\n",tpstrerror(tperrno));

return(-1);

}

return(0);

}

2.bankapp中怎样使用ud(1)

bankapp使用到了Tuxedo系统的ud(1)程序,它允许数据从标准输入读取,并送到服务。populate和driver例程都用到了ud。

在populate中,一个叫gendata的程序把服务请求以及要输入数据库的客户帐号信息一起传给了ud。

在driver中也存在类似的数据流,但程序是gentran,它的作用是把事务传递给应用程序以模拟一个活动系统。

3.一个请求/响应客户:audio.c

audit中一个请求/响应客户程序,用于支行或全行范围内的余额查询,它用到ABAL、TBAL、ABAL_BID、TBAL_BID服务,你可以通过如下两种方法来激活它:

audit [-a|-t],-a打印全行所有账号总额,[-t]打印全行范围内所有出纳员的现金供应。

audit [-a|-t] branch_ID,打印某支行Branch_ID的上述信息。

audit源代码包括两个主要部分:main()和sum_bal()子程序。两部分都用到了ATMI函数,它用到了一个在aud.h头文件中定义的VIEW类型的缓冲区,如下它的伪码:

main(){

Parse command-line options with getopt();

Join application with tpinit();

Begin global transaction with tpbegin();

If (branch_ID specified) {

Allocate buffer for service requests with tpalloc();

Place branch_ID into the aud structure;

Do tpcall() to "ABAL_BID" or "TBAL_BID";

Print balance for branch_ID;

Free buffer with tpfree();

}else

call subroutine sum_bal();

Commit global transaction with tpcommit();

Leave application with tpterm();

}

sum_bal(){

Allocate buffer for service requests with tpalloc();

For (each of several representative branch_ID’s,one for each site)

Do tpacall() to "ABAL" or "TBAL";

For (each representative branch_ID) {

Do tpgetrply() wtith TPGETANY flag set

to retrieve replies;

Add balance to total;

Print total balance;

}

Free buffer with tpfree();

}

audit.c首先检查命令行参数,看是否指定的支行代号。若指定,则将它放入aud结构,并调用ABAL_BID或TBAL_BID服务来处理请求;否则就调用sum_bal()子过程来处理。它们的程序流程图如下:

4.一个会话客户:auditcon.c

auditcon是audit的会话版,它使用了ATMI与会话相关的函数,如使用tpconnect()建立服务与客户之间的连接,用tpsend()发送一条消息,用tprecv()接收消息。如下是它的伪码:

main(){

Join the application

Begin a transaction

Open a connection to conversational service AUDITC

Do until (user says to quit) {

Query user for input

Send service request

Receive response

Print response on user’s terminal

Prompt for further input

}

Commit transaction

Leave the application

}

5.一个监视事件的客户bankmgr.c

bankmgr是一个始终运行的应用程序,它订阅应用程序定义的事件,如一次存取超过10000美元的事件。

§3.3 检查bankapp的服务器和服务

服务器是一些可执行的进程,它们提供一个或多个服务。在Tuxedo系统中,服务器始终接受来自客户端的服务请求,并将它们分配给某些服务,让它们来处理请求。所有bankapp的服务都是用C语言写的,包含有嵌入式SQL语句的C程序扩展名不是C而是EC。TRANSFER由XFER服务器来提供,它是唯一一个不包含嵌入式SQL的服务。所有bankapp服务使用ATMI的函数来管理类型缓冲区、和其它服务进行同步或异不通信、定义全局事务、一般地访问资源服务器、把响应发送回客户端。

1.bankapp的请求/响应服务器

bankapp的5个服务器中,有4个用到了嵌入式SQL访问资源管理器,这些服务器的扩展名为EC。XFER是一个转账的服务器,本身不调用资源管理器,而调用了其它服务器中的WITHDRAWAL和DEPOSIT两个服务。5个服务器的描述如下:

服务器

提供的功能

BTADD.EC

允许任何一个站的支行和出纳员的记录添加到数据库中

ACCT.EC

提供一些账号相关的有代表性的服务,如OPEN_ACCT, CLOSE_ACCT

TLR.EC

为出纳员提供服务,如WITHDRAWAL, DEPOSIT, INQUIRY,每一个TLR进程标识着它本身是TELLER文件中的一个真实的出纳员

XFER.C

在账号之间进行转账业务

BAL.EC

计算所有支行或某个支行的余额

2.bankapp的会话服务器

AUDITC是一个会话服务器的例子,它提供了一个服务,名字也叫AUDITC。客户机auditcon建立一个与服务AUDITC的会话连接,然后发出请求。AUDITC分析请求,并调用适当的服务(ABAL,TBAL,ABAL_BID,TBAL_BID),当AUDITC从这些服务获得响应后,再将它们送回auditcon。会话服务器可以以客户机的身份请求其它服务,也可以连接到其它会话服务器。

3.bankapp的服务

bankapp提供了12个请求/响应服务。服务名和C语言函数名相同:

服务名

提供服务器

输入

执行功能

BR_ADD

BTADD

FML缓冲区

添加一个新支行记录

TLR_ADD

BTADD

FML缓冲区

添加一条新出纳员记录

OPEN_ACCT

ACCT

FML缓冲区

向ACCOUNT文件中插入一条记录并调用DEPOSIT存入开户金额;在支行代号BRANCH_ID的基础上选择一个ACCOUNT_ID

CLOSE_ACCT

ACCT

FML缓冲区

删除一个ACCOUNT记录;验证ACCOUNT_ID;

调用WITHDRAWAL取走所有余额

WITHDRAWAL

TLR

FML缓冲区

从一个指定的支行、出纳员、账号取款;

验证ACCOUNT_ID和SAMOUNT字段

DEPOSIT

TLR

FML缓冲区

向某个支行、出纳员、账号存款;

验证ACCOUNT_ID和SAMOUNT字段

INQUIRY

TLR

FML缓冲区

查询账号余额;验证ACCOUNT_ID

TRANSFER

XFER

FML缓冲区

执行一个tpcall()调用,先后请求WITHDRAWAL和DEPOSIT服务

ABAL

BAL

aud.v的VIEW缓冲区

计算某一个站点所有账号的余额

TBAL

BAL

aud.v的VIEW缓冲区

计算某个站点所有支行出纳员的余额

ABAL_BID

BAL

aud.v的VIEW缓冲区

计算BRANCH_ID的账号余额

TBAL_BID

BAL

aud.v的VIEW缓冲区

计算BRANCH_ID的出纳员余额

bankapp服务的算法

⑴.BR_ADD

void BR_ADD (TPSVCINFO *transb){

-set pointer to TPSVCINFO data buffer;

-get all values for service request from field buffer;

-insert record into BRANCH;

-tpreturn() with success;

}

⑵.TLR_ADD

void TLR_ADD (TPSVCINFO *transb){

-set pointer to TPSVCINFO data buffer;

-get all values for service request from fielded buffer;

-get TELLER_ID by reading branch’s LAST_ACCT;

-insert teller record;

-update BRANCH with new LAST_TELLER;

-tpreturn() with success;

}

⑶.OPEN_ACCT

void OPEN_ACCT(TPSVCINFO *transb){

-Extract all values for service request from fielded buffer using Fget() and Fvall();

-Check that initial deposit is positive amount and tpreturn() with failure if not;

-Check that branch ID is a legal value and tpreturn() with failure if it is not;

-Set transaction consistency level to read/write;

-Retrieve BRANCH record to choose new account based on branch’s LAST_ACCT

field;

-Insert new account record into ACCOUNT file;

-Update BRANCH record with new value for LAST_ACCT;

-Create deposit request buffer with tpalloc(); initialize it for FML withFinit();

-Fill deposit buffer with values for DEPOSIT service request;

-Increase priority of coming DEPOSIT request since call is from a service;

-Do tpcall() to DEPOSIT service to add amount of initial balance;

-Prepare return buffer with necessary information;

-Free deposit request buffer with tpfree();

tpreturn() with success;

}

⑷.CLOSE_ACCT

void CLOSE_ACCT(TPSVCINFO *transb){

-Extract account ID from fielded buffer using Fvall();

-Check that account ID is a legal value and tpreturn() with failure if it is not;

-Set transaction consistency level to read/write;

-Retrieve ACCOUNT record to determine amount of final withdrawal;

-Create withdrawal request buffer with tpalloc(); initialize it for FML with Finit();

-Fill withdrawal buffer with values for WITHDRAWAL service request;

-Increase priority of coming WITHDRAWAL request since call is from a service;

-Do tpcall() to WITHDRAWAL service to withdraw balance of account;

-Delete ACCOUNT record;

-Prepare return buffer with necessary information;

-Free withdrawal request buffer with tpfree();

tpreturn with success;

}

⑸.WITHDRAWAL

void WITHDRAWAL(TPSVCINFO *transb){

-Extract account id and amount from fielded buffer using Fvall() and Fget();

-Check that account id is a legal value and tpreturn() with failure if not;

-Check that withdraw amount (amt) is positive and tpreturn() with failure if not;

-Set transaction consistency level to read/write;

-Retrieve ACCOUNT record to get account balance;

-Check that amount of withdrawal does not exceed ACCOUNT balance;

-Retrieve TELLER record to get teller’s balance and branch id;

-Check that amount of withdrawal does not exceed TELLER balance;

-Retrieve BRANCH record to get branch balance;

-Check that amount of withdrawal does not exceed BRANCH balance;

-Subtract amt to obtain new account balance;

-Update ACCOUNT record with new account balance;

-Subtract amt to obtain new teller balance;

-Update TELLER record with new teller balance;

-Subtract amt to obtain new branch balance;

-Update BRANCH record with new branch balance;

-Insert new HISTORY record with transaction information;

-Prepare return buffer with necessary information;

tpreturn with success;

}

⑹.DEPOSIT

void DEPOSIT(TPSVCINFO *transb){

-Extract account id and amount from fielded buffer using Fvall() and Fget();

-Check that account ID is a legal value and tpreturn() with failure if not;

-Check that deposit amount (amt) is positive and tpreturn() with failure if not;

-Set transaction consistency level to read/write;

-Retrieve ACCOUNT record to get account balance;

-Retrieve TELLER record to get teller’s balance and branch ID;

-Retrieve BRANCH record to get branch balance;

-Add amt to obtain new account balance;

-Update ACCOUNT record with new account balance;

-Add amt to obtain new teller balance;

-Update TELLER record with new teller balance;

-Add amt to obtain new branch balance;

-Update BRANCH record with new branch balance;

-Insert new HISTORY record with transaction information;

-Prepare return buffer with necessary information;

tpreturn() with success;

}

⑺.INQUIRY

void INQUIRY(TPSVCINFO *transb){

-Extract account ID from fielded buffer using Fvall();

-Check that account ID is a legal value and tpreturn() with failure if not;

-Set transaction consistency level to read only;

-Retrieve ACCOUNT record to get account balance;

-Prepare return buffer with necessary information;

tpreturn() with success;

}

⑻.TRANSFER

void TRANSFER(TPSVCINFO *transb){

-Extract account ID’s and amount from fielded buffer using Fvall() and Fget();

-Check that both account IDs are legal values and tpreturn() with failure if not;

-Check that transfer amount is positive and tpreturn() with failure if it is not;

-Create withdrawal request buffer with tpalloc(); initialize it for FML with Finit();

-Fill withdrawal request buffer with values for WITHDRAWAL service request;

-Increase priority of coming WITHDRAWAL request since call is from a service;

-Do tpcall() to WITHDRAWAL service;

-Get information from returned request buffer;

-Reinitialize withdrawal request buffer for use as deposit request buffer with Finit();

-Fill deposit request buffer with values for DEPOSIT service request;

-Increase priority of coming DEPOSIT request;

-Do tpcall() to DEPOSIT service;

-Prepare return buffer with necessary information;

-Free withdrawal/deposit request buffer with tpfree();

tpreturn() with success;

}

⑼.ABAL

void ABAL(TPSVCINFO *transb){

-Set transaction consistency level to read only;

-Retrieve sum of all ACCOUNT file BALANCE values for the

database of this server group (A single ESQL

statement is sufficient);

-Place sum into return buffer data structure;

tpreturn( ) with success;

}

⑽.TBAL

void TBAL(TPSVCINFO *transb){

-Set transaction consistency level to read only;

-Retrieve sum of all TELLER file BALANCE values for the

database of this server group (A single ESQL statement is sufficient);

-Place sum into return buffer data structure;

tpreturn( ) with success;

}

⑾.ABAL_BID

void ABAL_BID(TPSVCINFO *transb){

-Set transaction consistency level to read only;

-Set branch_ID based on transb buffer;

-Retrieve sum of all ACCOUNT file BALANCE values for records

having BRANCH_ID = branch_ID (A single ESQL statement is sufficient);

-Place sum into return buffer data structure;

tpreturn( ) with success;

}

⑿.ABAL_BID

void TBAL_BID(TPSVCINFO *transb){

-Set transaction consistency level to read only;

-Set branch_ID based on transb buffer;

-Retrieve sum of all TELLER file BALANCE values for records

having BRANCH_ID = branch_ID (A single ESQL statement is sufficient);

-Place sum into return buffer data structure;

tpreturn( ) with success;

}

4.集成到服务器中的应用

bankapp中用到了两个C语言的源程:

appint.c:包含应用程序定义版的tpsvrinit()和tpsvrdown()过程,它们被包含到Tuxedo系统的main()中。缺省版的tpsvrinit()调用了两个函数:tpopen()和userlog(),tpopen()用于打开资源管理器,userlog()用于记录各类消息。帛省版的tpsvrdown()同样调用了两个函数:tpclose()和userlog(),分别用于关闭资源管理器和记录关闭过程中的各类事件。你可以修改这两个过程,以完成各类初始化或应用程序结束时的收尾工作。

util.c:包含了一个叫getstr()的过程,bankapp中用它来SQL的错误消息。

5.服务编码的可选方法

在bankapp中,一个服务器提供的所有服务的代码都集成到一个文件中,文件名和服务器名字相同,它们还不是真正的服务器,因为它们不包含main()方法,在buildserver时由系统提供一个。另一种组织Tuxedo系统应用程序的方法是把每个服务代码保存在一个单独的文件中。例如,对于TLR服务器,TLR.EC文件包含三个服务,请可以将它们分成三个文件:INQUIRY.EC、WITHDRAW.EC、DEPOSIT.EC。按如下步骤完成:

⑴.将每个EC文件编译成OBJ文件

⑵.运行buildserver,将它们放到-f开关后面:

buildserver   –r TUXEDO/SQL

                            -s DEOISUT –s WITHDRAW –s INQUIRY

                            -o TLR

                            -f DEPOSIT.C –f WITHDRAW.C –f INQUIRY.C

                            -f util.obj –f lm

这样一来,你就没有必要将所有的服务都写到一个源文件中了,从而增加了灵活性。

6.准备bankapp的文件和资源

⑴.设置环境变量

         将samples\atmi\bankapp\nt下的bankvar文件改名为bankvar.bat,复制到父目录,然后对其进行编辑:

@echo off

rem %Tuxedo%为Tuxedo安装目录,APPDIR是bankapp所在的目录

set APPDIR=%TUXDIR%\samples\atmi\bankapp

rem消息所在目录

set NLSPATH=%TUXDIR%\locale\C

rem逻辑块大小,数据库管理员必须设置

set BLKSIZE=512

rem 被缺省使用的数据库名字

set DBNAME=bankdb

rem 指示数据库为共享模式还是私有模式

set DBPRIVATE=no

rem 指示数据库使用的IPC值,必须与ubbconfig中的IPCKEY不同

set DIPCKEY=80953

rem 由tmloadcf使用的环境文件

set ENVFILE=%APPDIR%\ENVFILE

rem 由mc, viewc, tmloadcf使用的字段表文件

set FIELDTBLS=Usysflds,bankflds,creditflds

rem 查找字段表文件的目录

set FLDTBLDIR=%TUXDIR%\udataobj;%APPDIR%

rem 数据库使用的通用设备列表

set FSCONFIG=%APPDIR%\bankdl1

rem MENU中使用的网络地址

set NADDR=

rem 网络设备名

set NDEVICE=

rem MENU脚本中使用的网络监听器地址

set NLSADDR=

rem 事务日志设备,必须和ubbconfig中MACHINES节

rem LMID站点的TLOGDEVICE参数相同

set TLOGDEVICE=%APPDIR%\TLOG

rem 为/T提供全部信息的二进制配置文件

set TUXCONFIG=%APPDIR%\tuxconfig

rem 用户日志文件,必须和ubbconfig中的MACHINES节

rem LMID站点的ULOGPFX参数相同

set ULOGPFX=%APPDIR%\ULOG

rem 由RUNME.sh使用的系统名

set UNAME=

rem 由viewc, tmloadcf使用的view文件列表

set VIEWFILES=aud.vv

set VIEWFILES32=mib_views,tmib_views

rem 查找view文件的目录

set VIEWDIR=%TUXDIR%\udataobj;%APPDIR%

set VIEWDIR32=%TUXDIR%\udataobj;%APPDIR%

rem 指定Q设备

set QMCONFIG=%APPDIR%\qdevice

set PATH=%TUXDIR%\bin;%PATH%

rem 指出Visual C++安装的目录

set MSDEV=G:\Program Files\Microsoft Visual Studio\VC98

set PATH=%PATH%;%MSDEV%\bin

set INCLUDE=%INCLUDE%;%MSDEV%\include;%MSDEV%\mfc\include

set LIB=%LIB%;%MSDEV%\lib;%MSDEV%\mfc\lib

⑵.Build bankapp的应用程序

         bankapp的5个服务器:ACCT、BAL、BTADD、TLR、XFER。用一个命令就可以完成编译任务:

G:\Tuxedo\samples\atmi\bankapp\nmake bankapp.nt

若要手工完成编译,首先要将EC文件编译成C文件:

G:\Tuxedo\samples\atmi\bankapp\ESQLC ACCT.EC

生成FML缓冲区头文件:

G:\Tuxedo\samples\atmi\bankapp\mkfldhdr bankflds eventflds

生成目标文件:

G:\Tuxedo\samples\atmi\bankapp\CL /c ACCT.c appinit.c util.c

生成ACCT.exe文件:

buildserver -r TUXEDO/SQL -s OPEN_ACCT -s CLOSE_ACCT

-o ACCT.exe

-ACCT.obj -f appinit.obj -f util.obj

-r指示哪一个资源管理器的访问库将被编译到acct.exe文件中,本例为TUXEDO/SQL

⑶.编辑bankapp的make文件

在NT平台下,bankapp提供的make文件为bankapp.nt,使用前需要检查一下环境变量TUXDIR、APPDIR的设置。另外一个要注意的地方就是资源管理器参数RM,缺省使用TUXEDO/SQL,因为Tuxedo为bankapp提供数据库服务。如果使用了其它数据库产品,需要把RM参数设置成%TUXDIR%\udataobj\RM文件列表中的某一个值。

⑷.创建bankapp的数据库

bankapp使用了TUXEDO/SQL作为资源管理器,它是一个XA-compliant的资源管理器,XA是事务管理器和资源管理器之间的接口。在单处理机SHM模式和多处理机MP模式下创建数据库的方式是不同的,在SHM模式下,创建步骤如下:

设置环境变量:     G:\Tuxedo\samples\atmi\bankapp\bankvar

执行批处理文件:G:\Tuxedo\samples\atmi\bankapp\crbank

crbank.cmd调用crbankdb三次,每次调用前改变一些环境变量,执行完成后,同一台机器上有三个数据文件,这样,就可以在单机上模拟网络环境。在MP模式下创建数据库的步骤如下:

设置环境变量:G:\Tuxedo\samples\atmi\bankapp\bankvar

在一台机器上创建数据库:G:\Tuxedo\samples\atmi\bankapp\crbankdb

在其它机器上,修改bankvar.cmd文件中的数据库通用设备列表FSCONFIG,修改ubbmp配置文件中的相应部分,再进行创建操作。

⑸.准备一个XA-compliant资源管理器

若不使用TUXEDO/SQL作为资源管理器,而使用其它的XA-compliant资源管理器,需要作很多修改:修改bankvar.cmd、修改bankapp服务、修改bankapp.nt文件、修改crbank和crbankdb文件、修改配置文件。

修改bankvar.cmd文件。下面是TUXEDO/SQL资源管理器的配置,已经不能用了,你需要根据实际的数据库系统对这些值进行修改:

BLKSIZE=512

DBNAME=bankdb

DBPRIVATE=no

DIPCKEY=80953

FSCONFIG=${APPDIR}/bankdl1

修改bankapp的服务。bankapp中所有数据库访问都是通过ESQL来完成的,如果你的新资源管理器支持SQL,这就没什么问题。appinit.c中包含了打开和关闭数据库的tpopen()和tpclose()。

修改bankapp.nt。将RM参数修改为新的资源管理器,确保RM文件中有如下入口:

$TUXDIR/udataobj/RM

如果必要,改变SQL编译器和它的选项,源文件的扩展名不一定是EC,你需要指预编译的命令及参数,以ORACLE为例,使用PROC将PC文件预编译成C文件。

修改crbank和crbankdb。注意crbankdb创建的SQL语句在新资源管理器中是否能接受。修改配置文件。在GROUPS节中,为TMSNAME和OPENM指定一个适当的值参数值,这个值要让资源管理器能够识别。

⑹.如何将bankapp和Oralce8进行集成

Oracle8是XA兼容的资源管理器,要实现和bankapp的集成,按如下步骤进行:

①.编辑bankvar.cmd文件,修改如下环境变量的值:

ORACLE_HOME:Oracle8的安装目录

ORACLE_SID:Oracle的系统ID

BLK_SIZE:逻辑块的尺寸

DBNAME:缺省数据库

DBPRIVATE:指示数据库是以共享模式还是私有模式打开(yes/no)

FSCONFIG:数据库使用的通用设置列表

PATH=%PATH%;%ORACLE_HOME%\bin

INCLUDE=%ORACLE_HOME%\rdbms80\xa;

%ORACLE_HOME%\pro80\c\include

PLATFORM=inwnt40

LIB=%TUXDIR%\lib %ORACLE_HOME%\pro80\lib\msvc;

%ORACLE_HOME%\rdbms80\xa;

②.运行bankvar.cmd

③.编辑%TUXDIR%\udataobj\RM文件,追加如下行:

Oracle_XA;xaosw;%ORACLE_HOME%\pro80\lib\msvc\sqllib80.lib

%ORACLE_HOME%\RDBMS80\XA\xa80.lib

         如果Oracle服务器在网络的另一端,把那台机器映射到驱动器,如F;

         把如下行追加到%TUXDIR%\udataobj\RM文件中:

Oracle_XA;xaosw;f:\orant\pro80\lib\msvc\sqllib80.lib

f:\orant\RDBMS80\XA\xa80.lib

         删除RM文件中以前的Oracle_XA入口

④.为Oracle8创建事务管理服务器

cd %APPDIR%

buildtms -r Oracle_XA -o TMS_ORA

⑤.编辑nt\bankapp.mak文件

RM=Oracle_XA

ORACLE_LIB=$(ORACLE_HOME)\PRO80\LIB

RMNAME=Oracle_XA

SQLPUBLIC=$(ORACLE_HOME)\PRO80\C\INCLUDE

ORACLE_DIR=$(ORACLE_HOME)\bin

在.ec.c节中,编辑从EC到C的创建规则,不再使用ESQLC了,而使用PROC:

set TUXDIR=$(TUXDIR) & $(ORACLE_DIR)\proc80

mode=ansi release_cursor=yes

include=$(SQLPUBLIC) include=$(INCDIR)

$(SQL_PLATFORM_INC) -c iname=$*.ec

                   在.c.obj节中,编辑规则,作出下设置:

$(CC) -c $(CFLAGS) $(SQLPUBLIC) $(INCLUDE) $*.c

⑥.使用Oracle的SQL命令更新EC文件

⑦.将nt\bankapp.mak复制到%APPDIR%下,然后Make一下:

         copy nt\bankapp.mak %APPDIR%

         nmake –f bankapp.mak

⑧.编辑nt\ubbshm文件:

USER_ID=0

GROUP_ID=0

UNAME_SITE1=执行hostname返回值,用大写形式

TUXDIR=与bankvar.cmd中的相同

APPDIR=与bankvar.cmd中的相同

⑨.在配置文件的GROUPS节中,输入如下改变:

TMSNAME=TMS_ORA

BANKB1 GRPNO=1

OPENINFO="Oracle_XA:Oracle_XA+Acc=P/user1/PaSsWd1+SesTm=0+LogDir=."

[

Oracle_XA + required fields:

Acc=P/oracle_user_id/oracle_password

SesTm=Session_time_limit (maximum time a transaction can be inactive)

optional fields:

LogDir=logdir (where XA library trace file is located)

MaxCur=maximum_#_of_open cursors

SqlNet=connect_string (if Oracle exists over the network)

(eg. SqlNet=hqfin@NEWDB indicates the database with sid=NEWDB accessed at host hqfin by TCP/IP)

]

BANKB2 GRPNO=2

OPENINFO="Oracle_XA:Oracle_XA+Acc=P/user2/PaSsWd2+SesTm=0+LogDir=."

BANKB3 GRPNO=3

OPENINFO="Oracle_XA:Oracle_XA+Acc=P/user3/PaSsWd3+SesTm=0+LogDir=."

⑩.执行其它操作:

         创建二进制配置文件:tmloadcf –y nt/ubbshm

         在Master机上创建TLOG设备和设备列表:crtlog –m

启动数据库服务器,启动Tuxedo系统:tmboot –y,确保数据库中存在V%XATRANS%视图,如果不存在,以系统用户登录Oracle,然后执行%ORACLE_HOME%\RDBMS80\ADMIN\XAVIEW.SQL,授予使用XA库的Oracle用户Select权限。

在Oracle8中创建bankapp使用的数据库对象。Oracle8安装以后,会创建一个示例数据库,bankapp可以使用这个数据库。编辑crbank-ora8.sql文件,内容如下:

WHENEVER OSERROR EXIT ;

/* 获取system用户的口令 */

PROMPT

PROMPT

PROMPT -- Some of the operations require "system" user privileges

PROMPT -- Please specify the Oracle "system" user password

PROMPT

ACCEPT syspw CHAR PROMPT ’system passwd:’ HIDE ;

CONNECT system/&syspw ;

SHOW user ;

PROMPT

/* 在缺省数据库中为bankapp创建一个新的表空间 */

DROP TABLESPACE bank1

INCLUDING CONTENTS

CASCADE CONSTRAINTS;

PROMPT

PROMPT

PROMPT -- Will create a 3MB tablespace for bankapp ;

PROMPT -------- Please specify full pathname below for Datafile ;

PROMPT -------- Ex: %ORACLE_HOME%/dbs/bankapp.dbf

PROMPT

ACCEPT datafile CHAR PROMPT ’Datafile:’ ;

CREATE TABLESPACE bank1

DATAFILE ’&datafile’ SIZE 3M REUSE

DEFAULT STORAGE (INITIAL 10K NEXT 50K

MINEXTENTS 1 MAXEXTENTS 120

PCTINCREASE 5)

ONLINE;

/* 创建一个名叫user1的用户 */

DROP USER user1 CASCADE;

PROMPT Creating user "user1"

CREATE USER user1 IDENTIFIED by PaSsWd1

DEFAULT TABLESPACE bank1

QUOTA UNLIMITED ON bank1 ;

GRANT CREATE SESSION TO user1 ;

GRANT CREATE TABLE TO user1 ;

CONNECT user1/PaSsWd1 ;

SHOW user ;

PROMPT Creating database objects for user "user1" ;

PROMPT Creating table "branch" ;

CREATE TABLE branch (

branch_id NUMBER NOT NULL PRIMARY KEY,

balance NUMBER,

last_acct NUMBER,

last_teller NUMBER,

phoneCHAR(14),

address CHAR(60)

)

STORAGE (INITIAL 5K NEXT 2K

MINEXTENTS 1 MAXEXTENTS 5 PCTINCREASE 5) ;

PROMPT Creating table "account" ;

CREATE TABLE account (

account_id NUMBER NOT NULL PRIMARY KEY,

branch_id NUMBER NOT NULL,

ssn CHAR(12) NOT NULL,

balance NUMBER,

acct_type CHAR,

last_name CHAR(20),

first_name CHAR(20),

mid_init CHAR,

phoneCHAR(14),

address CHAR(60)

)

STORAGE (INITIAL 50K NEXT 25K

MINEXTENTS 1 MAXEXTENTS 50 PCTINCREASE 5) ;

PROMPT Creating table "teller" ;

CREATE TABLE teller (

teller_id NUMBER NOT NULL PRIMARY KEY,

branch_id NUMBER NOT NULL,

balance NUMBER,

last_name CHAR(20),

first_name CHAR(20),

mid_init CHAR

)

STORAGE (INITIAL 5K NEXT 2K

MINEXTENTS 1 MAXEXTENTS 5 PCTINCREASE 5) ;

PROMPT Creating table "history" ;

CREATE TABLE history (

account_id NUMBER NOT NULL,

teller_id NUMBER NOT NULL,

branch_id NUMBER NOT NULL,

amount NUMBER

)

STORAGE (INITIAL 400K NEXT 200K

MINEXTENTS 1 MAXEXTENTS 5 PCTINCREASE 5) ;

在SQL PLUS中执行上面这段SQL语句:

SQL*plus> start $APPDIR/ crbank-ora8.sql

填充数据库:

         nt\populate

         在Oracle数据库中生成事务

                   driver

         运行bankapp的客户程序:

                   run

         关闭Tuxedo应用程序:

                   tmshutdown -y

⑹.如何编辑配置文件

配置文件定义了应用程序如何运行。bankapp有两个配置文件:ubbshm和ubbmp。ubbshm定义了在单机环境下如何运行bankapp,ubbmp定义了在网络环境下如何运行bankapp。

①.打开并编辑ubbmp,将<…>替换成际值。对于ubbmp,NETWORK节必须替换

*RESOURCES

IPCKEY 80952

UID <user id from id(1)>

GID <group id from id(1)>

PERM 0660

MAXACCESSERS 40

MAXSERVERS 35

MAXSERVICES 75

MAXCONV 10

MAXGTT 20

MASTER SITE1,SITE2

SCANUNIT 10

SANITYSCAN 12

BBLQUERY 180

BLOCKTIME 30

DBBLWAIT 6

OPTIONS LAN,MIGRATE

MODEL MP

LDBAL Y

##SECURITY ACL

#

*MACHINES

<SITE1’s uname> LMID=SITE1

TUXDIR="<TUXDIR>"

APPDIR="<APPDIR>"

ENVFILE="<APPDIR>/ENVFILE"

TLOGDEVICE="<APPDIR>/TLOG"

TLOGNAME=TLOG

TUXCONFIG="<APPDIR>/tuxconfig"

TYPE="<machine type>"

ULOGPFX="<APPDIR>/ULOG"

<SITE2’s uname> LMID=SITE2

TUXDIR="<TUXDIR>"

APPDIR="<APPDIR>"

ENVFILE="<APPDIR>/ENVFILE"

TLOGDEVICE="<APPDIR>/TLOG"

TLOGNAME=TLOG

TUXCONFIG="<APPDIR>/tuxconfig"

TYPE="<machine type>"

ULOGPFX="<APPDIR>/ULOG"

#

*GROUPS

#

# Group for Authentication Servers

#

Group for Application Queue (/Q) Servers

#

##QGRP1 LMID=SITE1 GRP=102

## TMSNAME=TMS_QM TMSCOUNT=2

## OPENINFO=”TUXEDO/QM:<APPDIR>/qdevice:QSP_BANKAPP”

#

# Group for Event Broker Servers

#

##EVBGRP1 LMID=SITE1 GRPNO=104

DEFAULT: TMSNAME=TMS_SQL TMSCOUNT=2

BANKB1 LMID=SITE1 GRPNO=1

OPENINFO="TUXEDO/SQL:<APPDIR>/bankdl1:bankdb:readwrite"

BANKB2 LMID=SITE2 GRPNO=2

OPENINFO="TUXEDO/SQL:<APPDIR>/bankdl2:bankdb:readwrite"

*NETWORK

SITE1 NADDR="<network address of SITE1>"

NLSADDR="<network listener address of SITE1>"

SITE2 NADDR="<network address of SITE2>"

NLSADDR="<network listener address of SITE2>"

②.UID:公告栏中IPC结构所有者有效的用户ID,在ubbmp中,所有机器上的UID必须相同,为了避免引起混乱,输入Tuxedo系统的所有者ID。GID与UID类似。SITE1’s name:机器名,在UNIX下为uname –n的结果。machine type:一个字符串,在网络环境下,用于标识一类计算机,两台计算机通信时,Tuxedo系统检查它们的机器类型,如果不同,在它们之间传递的数据就需要进行编码和解码操作,以便两台机器都能够识别它们。SITE2 name:第二台机器的机器名。OPENINFO:一个只有Tuxedo资源管理器才能识别的格式化字符串,若使用其它的资源管理器如Oracle,必须对它进行修改,以满足要求。Network address of SITE1:SITE1上BRIDGE进程网络监听器完整地址, BRIDGE是一个维护着和其它参与计算的节点之间虚电路的系统进程,以便这些节点之间可以进行消息传递。Network listener address of SITE1:SITE1上tlisten进程监听器地址。Network address of SITE2和Network listener address of SITE2同上。

③.要使应用程序具有口令特征,在ubbshm或ubbmp中的RESOURCE节中加入:

SECURITY APP_PW

⑺.创建二进制配置文件和事务日志文件

         如果你在SHM模式下运行,你就没有必要在其它机器上创建tlisten进程和事务日志。

在%APPDIR%下运行bankar.cmd设置环境变量;

①.加载配置文件

tmloadcf –y ubbmp;TUXCONFIG只需要在Master机上安装,当用tmboot启动应用程序时,它就会自动地传给其它机器。如果指定了SECURITY,tmloadcf就会提示你输入应用程序的口令,可以长达30个字符。当客户进程试图加入应用程序时,就要求提供应用程序口令、用户名、用户口令。

②.创建事务日志文件TLOG

TLOG是Tuxedo系统管理全局事务使用的事务日志文件,在应用程序启动之前,在运行应用程序的每一台机器上必须创建一个TLOG入口,TLOG文件本身在Master机上创建。bankapp提供了一个叫crtlog的脚本,它创建了一个设备列表和一个TLOG文件,设备列表使用bankvar.cmd中的TLOGDEVICE变量来创建。要创建TLOG文件和设备列表,在Master机上运行:

crtlog –m

在生产环境中,设备列表名和数据库中用到的设备列表名必须相同。

在所有其它机器上,不要指定-m开关,当系统启动时,每一台非Master机上的BBL会创建日志。如果你使用了一个non-XA的资源管理器,就没有必要创建事务日志。

⑻.在每台机器上创建远程服务连接

         tlisten是一个监听进程,它为tmboot之类的进程提供了远程服务连接。它必须在网络中的每一台机器上安装,并与配置文件中NETWORK段的描述一致。推荐用如下命令启动另一个tlisten进程:

         tlisten –l nlsaddr

         nlsaddr值必须和配置文件中NLSADDR参数值一致,tlisten使用的logfile和Tuxedo系统其它log文件分开了。一个日志文件可以被多个tlisten进程使用,缺省文件名是:%TUXDIR%\udataobj\tlog。

7.运行bankapp

⑴.如何准备启动应用程序

启动bankapp之前,检查你的机器是否还有足够的IPC资源,方法是:

tmloadcf –c ubbshm

⑵.如何启动bankapp

bankvar

tmboot –y

你可以只boot配置文件中的一部分服务,如指定-A选项可以只启动管理进程。

⑶.如何填充数据库

使用populate脚本创建填充数据库,gendata创建了10个支行,30个出纳员,200个账号,pop.out保存了创建过程。

⑷.如何测试bankapp的服务

audit {-t|-a} [branch_id]

auditcon

使用driver程序(UNIX平台下使用,NT平台下使用gt.cmd),缺省情况下,它生成300个事务,你可以通过-n指定事务数:

driver –n1000

⑸.如何关闭bankapp

tmshutdown –y

 

buildtms [-v] -o name -r rmname

buildclient [-v][{-r rmname|-w}][-f firstfiles][-l lastfiles][-o name]

buildserver [-v][-r rmname][-f firstfiles][-l lastfiles][-o name][-s service]

-v: 显示编译过程

-r: 所需连接的资源管理器

-w: 生成WS程序

-f: 在连接TUXEDO内部库之前所需连接的文件

-l: 在连接TUXEDO内部库之后所需连接的文件

-o: 生成可执行程序

-s: 服务名与函数名映射

 

同一台主机上,Tuxedo提供了服务嵌套调用和递归调用的服务调用模式。

如果仅仅是服务A需要调用服务B,则可以直接在服务A中使用tpcall(B)。

在这种情况下,服务A模拟类似客户端,唯一的不同是这个时候不需要tpinit。

FML和FML32的区别,从字面间就可以看出,函数的功能是一样的,FML32支持的

数据长度为32位的

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值