FML(FML32)缓冲区
FML(FML32)缓冲区类似于一个表,它一般用在用在与数据库有关的操作中,如把查询结果通过FML(FML32)缓冲区发送到客户端,它有自己的一套函数对其进行操作。FML(FML32)在发送时,只发送真正用到的数据,这一点与其他的类型的缓冲区不一样。如分配的缓冲区大小为1M,但真正用到的空间只有1K,那么在发送时只发送这1K数据,如果时其他类型的缓冲区时也是发送1M的数据。它的使用方式和VIEW差不多,说明如下:(最大为4G)
1. 定义FML(FML32)的描述文件,如定义名为demo.fml的描述文件如下,假设该文件在D:\DEMO目录下。
*base 1000
# name number type flags comments
EMPNO 1 long - -
ENAME 2 string - -
PHOTO 3 carray - “store the photo data”
SAL 4 double - -
定义一个FML(FML32)文件类似于定义一张表,各个字段的含义如下:
type: 该字段的类型, 可以为short, char, long, float, double,STRING ,CARRAY.
注意: STRING,CARRAY要用小写。
name: 该字段的名字
number: 该字段的ID号,在一个FML(FML32)的定义文件中要唯一,
0-100, 6000-7000归TUXEDO系统内部用,
FML的范围是101–8191,
FML32的范围是101 -33,554,431。
Flag: 设置该字段的一些标志
comments: 对该字段的注释
*base: 字段的ID号的起始值,真正的值*base加上number的值
$: 注释,并且出现在生成的*.h文件中
#: 注释,不出现在生成的*.h文件中
“-”:表示该属性采用默认值.
2. 用mkfldhdr或mkfldhdr32进行编译,生成对应的*.h文件,如于上面的定义相对应的
*.h文件用mkfldhdr32 demo.fml32命令编译,生成demo.fml32的内容如下:
/* fname fldid */
/* ----- ----- */
#define EMPNO ((FLDID32)33555433) /* number: 1001 type: long */
#define ENAME ((FLDID32)167773162) /* number: 1002 type: string */
#define PHOTO ((FLDID32)201327595) /* number: 1003 type: carray */
#define SAL ((FLDID32)134218732) /* number: 1004 type: double */
3. 定义环境变量FIELDTBLS (FIELDTBLS32), FLDTBLDIR (FLDTBLDIR32)
4. FLDTBLDIR (FLDTBLDIR32): FML(FML32)的定义文件所在的路径
FIELDTBLS (FIELDTBLS32): FML(FML32)的定义文件名,如果有多个用,隔开
如对上面的demo.fml32文件为:
SET FLDTBLDIR32=D:\DEMO
SET FIELDTBLS32= demo.fml32
5. 在使用到该FML(FML32)的程序中用#include包含生成的*.h文件.并要包含fml.h
fml32.h文件。
6.在程序中通过FML(FML32) 函数对FML(FML32)缓冲区进行操作
FML与FML32的区别:
FML与FML32相类似,区别在于:
1. FML32中使用32位的数表示字段的ID和该字段的长度,FML32中使用16位的数表示字段的ID和该字段的长度,所以FML32能表示更大的缓冲区。
2. 对FML32的操作函数都以32结尾。 环境变量也以32结尾。
常用的FML(FML32)操作函数:
FML(FML32)采用自己单独的一套函数对FML(FML32)缓冲区进行操作。FML32的操作函数
与FM的操作函数一样,只是以32结尾,所以下面只说明常用的FML函数
FBFR* Falloc (FLDOCC F, FLDLEN V)
描述: 分配一块FML缓冲区
参数:
FLDOCC: 该FML缓冲区的字段个数,
FLDLEN: 该FML缓冲区的长度
返回值:成功返回一个指向该FML缓冲区首地址的指针,失败返回NULL,错误号保存在全局
变量Ferror中
注意: 该FML缓冲区不能用于TPCALL(),TPACALL(),TPRETURN()等中,在这些函数中用到
的FML缓冲区只能用TPALLOC()分配。
int Finit(FBFR *fbfr, FLDLEN buflen)
描述: 初始化该FML缓冲区
参数:
fbfr: 一个指向该FML缓冲区首地址的指针
buflen: 该FML缓冲区的长度
返回值:失败为-1, 错误号保存在全局变量Ferror中
int Fadd(FBFR *fbfr, FLDID fieldid, char *value, FLDLEN len)
描述: 往FML缓冲区fbfr中ID为fieldid的字段增加一个值value
参数:
fbfr: 指向该FML缓冲区首地址的指针
fieldid: 要增加的字段的ID
value: 要增加的值,如果时其他类型的要转化为char *
len: 该字段的长度,如果不时CARRARY类型的,可设为0
返回值: 失败为-1, 错误号保存在全局变量Ferror中
int Fchg(FBFR *fbfr, FLDID fieldid,int occ, char *value, FLDLEN len)
描述: 改变fbfr中ID为fieldid字段的值。
参数:
fbfr: 指向该FML缓冲区首地址的指针
fieldid: 要增加的字段的ID
value: 该字段的新值,如果时其他类型的要转化为char *
len: 该字段的长度,如果不时CARRARY类型的,可设为0
返回值:失败为-1,错误号保存在全局变量Ferror中
int Fget(FBFR *fbfr, FLDID fieldid,int occ, char *value, FLDLEN *maxlen)
描述: 从fbfr缓冲区中取ID为fieldid字段的值到value中。
参数:
fbfr: 指向该FML缓冲区首地址的指针
fieldid: 字段的ID
value: 取出的值保存到该指针指向的地址中
maxlen: 可以COPY到缓冲区value中的字符串的长度,返回值为真正COPY到该缓冲区的字
符串的长度
返回值:失败为-1, 错误号保存在全局变量Ferror中
Fprint(FBFR *fbfr)
描述: 按格式打印fbfr缓冲区的内容。一般用于程序调试中。
参数:
fbfr: 指向该FML缓冲区首地址的指针
返回值:失败为-1, 错误号保存在全局变量Ferror中
Ferror:
和C语言中的errno类似,当调用FML(FML32)函数出错时,把错误号保存在全局变量Ferror中。
char * Fstrerror(int err)
描述:返回错误号为err的错误描述
参数:err: Ferror的值
返回值:成功返回错误描述,失败返回NULL
XML缓冲区
从TUXEDO7.1开始,TUXEDO支持XML缓冲区,并可根据XML中某个ELEMENT(元素)的值,ELEMENT的类型,或ATTRIBUTE(属性)的值实现数据依赖路由。同CARRAY一样,在对XML缓冲区进行操作时要指定缓冲区的长度。
在TUXDO7.1中内置了XML PARSER,它主要完成以下工作:
1. 自动检测XML缓冲区所采用的字符集。
2. 如果XML缓冲区所采用的字符集不是ASCII或 EBCDIC字符集,把ELEMENT,ATTRIBUTE的名字转换为ASCII或 EBCDIC。
3. 检查缓冲区中ELEMENT的内容,ATTRIBUTE的值。
4. 数据类型转换,在数据依赖路由中,如果是采用XML类型,要指定所采用的路由字段的数据类型,XML只支持字符型的数据,如果路由字段是数字型的,将自动进行类型转换。
例子:
用户的定单保存成XML文件形式,定单的格式都一样,但预定不同的产品要进行不同的处理,或要保存到不同的数据库中,如定单号为1-9999的是购买衬衫的,要保存到数据库1中,定单号为10000-19999是购买鞋的,要保存到数据库2中,其它的定单保存到数据库3中。
可采用数据依赖路由来实现这样的功能,
客户端程序读取这些XML文件,并调用服务ORDER处理这些定单,TUXEDO服务器根据收到的XML缓冲区中的定单号ORDERNO的值,把请求路由到不同的GROUP进行处理。定单号为1-9999路由到GROUP1(对应数据库1),定单号为10000-19999路由到GROUP2(对应数据库12),其他的定单则路由到GROUP3(对应数据库3)。
定单的XML文件格式如下:
<?xml version="1.0" encoding="UTF-8"?>
<ORDER>
<HEADER DATE="03/16/2000" ORDERNO="12345"/>
<COMPANY>ACME</COMPANY>
<ITEM BRAND="CALVIN KLEIN" SIZE="16,32" COLOR="WHITE" QUANTITY="15">SHIRTS</ITEM>
</ORDER>
配置文件的内容
*RESOURCES
IPCKEY 61234
MASTER simple
MAXACCESSERS 100
MAXSERVERS 50
MAXSERVICES 100
MODEL SHM
*MACHINES
MYSERVER LMID=simple
TUXCONFIG="D:\tuxdemo\xml\tuxconfig"
TUXDIR="d:\bea\tuxedo7.1"
APPDIR="d:\tuxdemo\xml"
*GROUPS
GROUP1 LMID=simple GRPNO=1
TMSNAME="TMS_ORA8i" TMSCOUNT=2
OPENINFO="Oracle_XA:Oracle_XA+Acc=P/scott/tiger+SesTm=600+MaxCur=5+LogDir=."
GROUP2 LMID=simple GRPNO=2
TMSNAME="TMS_INFORMIX" TMSCOUNT=2
OPENINFO="INFORMIX:mydb2"
GROUP3 LMID=simple GRPNO=3
TMSNAME="TMS_INFORMIX" TMSCOUNT=2
OPENINFO="INFORMIX:mydb3"
*SERVERS
DEFAULT:
CLOPT="-A"
shirtorder SRVGRP=GROUP1 SRVID=9
shoeorder SRVGRP=GROUP2 SRVID=10
otherorder SRVGRP=GROUP3 SRVID=11
*SERVICES
ORDERSVC LOAD=50 PRIO=50 ROUTING=ORDERNO
*ROUTING
ORDERNO FIELD="ORDER/HEADER/@ORDERNO"
BUFTYPE="XML"
RANGES="1-9999:GROUP1,
10000-19999:GROUP2,
*:GROUP3"
客户端程序orderclt.c的内容:
#include <stdio.h>
#include "atmi.h" /* TUXEDO Header File */
#define MAXXMLDOCSIZE 4096 /* Max XML doc size */
main(int argc, char *argv[])
{
char *sendbuf, *rcvbuf;
long sendlen, rcvlen;
int ret;
FILE *xml_fd;
char xml_file[256];
char *xml_buffer;
int nsize;
if(argc != 2)
{
printf("Usage: %s <XML-doc-file>\n", argv[0]);
exit(1);
}
/* Read the XML document in first */
strcpy(xml_file, argv[1]);
if ((xml_fd = fopen(xml_file, "r")) == NULL)
{
printf("fopen(%s) fail\n", xml_file);
exit(1);
}
if ((xml_buffer = (char *)malloc(sizeof(char) * MAXXMLDOCSIZE)) == NULL)
{
printf("malloc failed for XML doc\n");
exit(1);
}
if ((nsize = fread(xml_buffer, sizeof(char), MAXXMLDOCSIZE, xml_fd)) < 0)
{
printf("fread(%s) fail\n",xml_file);
exit(1);
}
/* Attach to System/T as a Client Process */
if (tpinit((TPINIT *)NULL) == -1)
{
printf("tpinit() fail: %s\n", tpstrerror(tperrno));
exit(1);
}
/* Allocate XML buffers for the request and the reply */
sendlen = strlen(xml_buffer);
if((sendbuf = (char *) tpalloc("XML", NULL, sendlen+1)) == NULL)
{
printf("tpalloc(sendbuf) fail:%s\n",tpstrerror(tperrno));
tpterm();
exit(1);
}
if((rcvbuf = (char *) tpalloc("XML", NULL, sendlen+1)) == NULL)
{
printf("tpalloc(sendbuf) fail:%s\n",tpstrerror(tperrno));
tpfree(sendbuf);
tpterm();
exit(1);
}
(void)strcpy(sendbuf, xml_buffer);
/* Request the service ORDERSVC, waiting for a reply */
ret = tpcall("ORDER", (char *)sendbuf, sendlen, (char **)&rcvbuf, &rcvlen, 0);
if(ret == -1)
{
printf("tpcall(ORDERSVC) fail:%s",tpstrerror(tperrno));
tpfree(sendbuf);
tpfree(rcvbuf);
tpterm();
exit(1);
}
printf("Returned string is: %s\n", rcvbuf);
/* Free Buffers & Detach from System/T */
tpfree(sendbuf);
tpfree(rcvbuf);
tpterm();
}
服务端程序order.c
#include <stdio.h>
#include <atmi.h> /* TUXEDO Header File */
#include <userlog.h> /* TUXEDO Header File */
ORDER(TPSVCINFO *rqst)
{
userlog("ORDER xml data: %s", rqst->data);
/*把定单保存到数据库中,程序省略*/
。。。。。。。。。
tpreturn(TPSUCCESS, 123, rqst->data, rqst->len, 0);
}
把order.c编译为shirtorder和shoeorder两个SERVER
buildserver -o shirtorder -f order.c -s ORDER
buildserver -o shoeorder -f order.c -s ORDER
运���程序:
orderclt test.xml
如果test.xml中ORDERNO的值为1-9999路由到GROUP1,为10000-19999路由到GROUP2,其他的定单则路由到GROUP3。