tuxedo入门教程
1. 2012-04-06 初稿
2. 2014-02-19 修复文中的一些小错误 感谢周泳
===============
先介绍下目录结构
bin etc include lib log src
bin 目录用来存放服务命令和客户端命令
etc 用来存放ubb配置文件
include 用来存放头文件
lib 用来存放库文件
log 日志目录
src 源文件
src下有四个目录
client public realize service
client 用来存放客户端命令
public 用来存在公共函数
realize 用来存放实现和数据库通信的某种函数
service 用来存放服务程序
文件组成:
ls -R
.:
bin etc include lib log src
./bin:
client service
./etc:
tuxconfig ubb.txt
./include:
public.h
./lib:
libpublic.a librealize.a
./log:
./src:
client public realize service
./src/client:
client client.c makefile
./src/public:
makefile public.c
./src/realize:
makefile realize.pc
./src/service:
makefile service service.pc
本文假定已经安装oracle和TUXEDO。
先看client.c程序
================
#include <stdio.h>
#include "atmi.h" /*包含TUXEDO系统的头文件"atmi.h", 以便引用TUXEDO的函数和变量定义。*/
#define ALLOClEN 80 /*定义输入和返回的长度*/
int main(int argvc, char** agr)
{
char *inbuf=NULL;
char *outbuf=NULL;
long len=0;
long outlen=0;
/*客户端调用tpinit()连接应用*/
if (tpinit((TPINIT * )NULL) == -1)
{
exit(1);
}
/*用tpalloc()分配一个STRING类型数据缓冲*/
if (NULL==(inbuf=tpalloc("STRING", NULL, ALLOClEN)))
{
tpterm();
exit(2);
}
/*用tpalloc()分配一个STRING类型数据缓冲*/
if (NULL==(outbuf=tpalloc("STRING", NULL, ALLOClEN)))
{
tpterm();
exit(-1);
}
/*将"hello world"拷贝进缓冲*/
strcpy(inbuf, "ht");
printf("\t请求报文====>[%s]\n",inbuf);
/*先连上数据库,这里inbuf,outbuf,outlen没有什么作用*/
if ( tpcall("sv_connect", inbuf, 0, &outbuf, &outlen, 0)== -1)
{
fprintf(stderr, "sv_connect fail.\n");
tpfree(inbuf);
tpfree(outbuf);
tpterm();
exit(-1);
}
/*用tpcall()包含数据缓冲,向交易"TOUPPER"发一个同步请求*/
if ( tpcall("sv_update", inbuf, 0, &outbuf, &outlen, 0)== -1)
{
fprintf(stderr, "service requst fail.\n");
tpfree(inbuf);
tpfree(outbuf);
tpterm();
exit(-1);
}
/*打印出改变的数据缓冲*/
printf("\n");
printf("\t返回报文<======[%s]\n", outbuf);
tpfree(inbuf);
tpfree(outbuf);
/*调用tpterm()切断与应用的连接*/
tpterm();
exit(0);
}
这个函数用以下命令编译:
buildclient -f client.c -o client -v
编译后把生成的client, 移到bin目录下。
在这里建一个makefile, 内容如下:
all:
buildclient -f client.c -o client -v
@cp client ../../bin
注意,buildclient前面不是空格,是一个tab. @表示执行命令时不显示拷贝的过程。
在写服务程序之前,先写一个日志程序,这样可以打印日志。
public.h
=========
#ifndef __PUBLIC_H__
#define __PUBLIC_H__
#include "ctype.h"
#include <stdio.h>
#include <stdlib.h>
#include <sqlca.h>
#include <oraca.h>
#include <sqlcpr.h>
#include <assert.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <sys/timeb.h>
char *GetTimeChar();
int WriteLog(int LogLevel,char * format,...);
#endif /* __PUBLIC.H__*/
public.c
=========
#include "public.h"
int GLogLevel=0; /*记日志的级别. 记日志的级别有:0,1,2。 0级别最高*/
char GLogFile[100]= "../log/serv%s.log";
char *GetTimeChar()
{
int year = 0;
static char tt[20] = "";
struct tm t;
time_t now;
time(&now);
t = *localtime(&now);
year=t.tm_year;
if (year<50)
year+=2000;
else
year+=1900;
sprintf(tt,"%04d-%02d-%02d %02d:%02d:%02d",year,t.tm_mon+1,t.tm_mday,t.tm_hour,t.tm_min,t.tm_sec);
return tt;
}
/***************************************************************************
函数名称:WriteLog
函数功能:写日志文件
输入参数:filename:文件名;format:参数
输出参数:无
返 回 值:0:正确;其他:失败
***************************************************************************/
int WriteLog(int LogLevel,char * format,...)
{
FILE * fp;
va_list args;
char *ttime = NULL;
char ddate[9]="";
char LogPath[50]="";
ttime=GetTimeChar();
strncpy(ddate,ttime,4);
strncat(ddate,(ttime+5),2);
strncat(ddate,(ttime+8),2);
sprintf(LogPath,GLogFile,ddate);
if (LogLevel<=GLogLevel)
{
if((fp=fopen(LogPath,"a+"))==NULL)
{
perror("Create or Open LogFile Error! GLogFile\n");
return -1;
}
fprintf(fp,"[%s]",GetTimeChar());
va_start(args,format);
vfprintf(fp,format,args);
va_end(args);
va_start(args,format);
vprintf(format,args);
va_end(args);
fclose(fp);
}
return 0;
}
makefile文件:
=============
all:
gcc -c public.c -I$(TUXDIR)/include -I../../include -I$(ORACLE_HOME)/precomp/public
ar -r libpublic.a *.o
@mv libpublic.a ../../lib
@rm *.o
这里把公用函数生成一个静态库,以后服务程序可以直接用。
service.pc这个文件中存放服务调用,由这里入口。
============================================
#include "public.h"
#include "atmi.h"
#define BUF_SIZE 100
/************************************************
函数名称:sv_connect
函数功能:连接数据库
输入参数:
TPSVCINFO *rqst;不用
输出参数:TPSVCINFO *rqst;不用
返 回 值:无
************************************************/
void sv_connect(TPSVCINFO *rqst)
{
EXEC SQL BEGIN DECLARE SECTION;
char username[100]="hstest";
char password[100]="hstest";
char server[100]="ora10g";
EXEC SQL END DECLARE SECTION;
char *sBuf = NULL;
sBuf = tpalloc("STRING",NULL,BUF_SIZE);
if(sBuf == NULL) {
WriteLog(0,"分配内存错误!");
return ;
}
/* 连接到数据库 */
EXEC SQL CONNECT :username IDENTIFIED BY :password USING :server;
if (sqlca.sqlcode < 0)
{
WriteLog(0,"connect oracle error:%.*s",sqlca.sqlerrm.sqlerrml,sqlca.sqlerrm.sqlerrmc);
sprintf(sBuf,"7002;数据库连接失败:%.*s",sqlca.sqlerrm.sqlerrml,sqlca.sqlerrm.sqlerrmc);
}
else
strcpy(sBuf,"0");
oraca.oradbgf = 1; /* enable debug operations */
oraca.oracchf = 1; /* gather cursor cache statistics */
oraca.orastxtf = 3; /* always save the SQL statement */
tpreturn(TPSUCCESS, 0, sBuf, 0L, 0);
}
/*******************************************
函数名称:sv_update
函数功能: 测试
输入参数:
TPSVCINFO *rqst;
rqst->data格式:NAME
输出参数:TPSVCINFO *rqst;
成功:0;OK
失败:1;错误原因
返 回 值:无
*******************************************/
void sv_update(TPSVCINFO *rqst)
{
char *sBuf = NULL;
sBuf = tpalloc("STRING",NULL,BUF_SIZE);
if(sBuf == NULL) {
WriteLog(0,"分配内存错误!");
return ;
}
WriteLog(0,"预处理开始\n");
if(TOUPPER(rqst->data) != 0){
sprintf(sBuf,"1;%s","ERROR!");
}
else
strcpy(sBuf,"0;OK!");
WriteLog(0,"预处理完成\n");
tpreturn(TPSUCCESS, 0, sBuf, 0L, 0);
}
makefile
========
all:
proc PARSE=NONE include=-I/home/oracle/product/10.2.0/precomp/public include=-I/home/oracle/product/10.2.0/rdbms/public sqlcheck=full USerid=hstest/hstest iname=service.pc
gcc -c service.c -I./ -I/home/oracle/product/10.2.0/precomp/public -I/home/oracle/product/10.2.0/plsql/public -I/home/oracle/product/10.2.0//rdbms/demo -I/home/tuxedo/bea/tuxedo8.1/include -I../../include
buildserver -v -o service -f "service.o " -s sv_connect -s sv_update -f "-L/home/oracle/product/10.2.0/lib -lclntsh -lc -lm " -f "-L../../lib -lpublic -lrealize"
cp service ../../bin
@rm *.lis *.c *.o
realize.pc
==========
#include "atmi.h"
#include "public.h"
/*包含TUXEDO系统头文件"atmi.h"*/
/*从客户端收到的数据放在TPSVCINFO结构中,是唯一的入参*/
int TOUPPER (const char *inbuf)
{
EXEC SQL WHENEVER SQLERROR goto sqlerr;
EXEC SQL UPDATE plsqltest SET salary=256 WHERE name=:inbuf;
EXEC SQL COMMIT WORK;
WriteLog(0,"update successfully.");
return 0;
sqlerr:
WriteLog(0, "%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
return -1;
}
makefile
========
all:
proc include=/home/oracle/product/10.2.0/precomp/public include=/home/oracle/product/10.2.0/rdbms/public include=../../include include=/home/tuxedo/bea
/tuxedo8.1/include ORACA=YES LINES=YES MODE=ORACLE DBMS=V7 SQLCHECK=SEMANTICS UNSAFE_NULL=YES USerid=hstest/hstest iname=realize.pc
gcc -c realize.c -I./ -I/home/oracle/product/10.2.0/precomp/public -I/home/oracle/product/10.2.0/plsql/public -I/home/oracle/product/10.2.0/rdbms/demo -I/home/tuxedo/bea/tuxedo8.1/include -I../../include
ar -r librealize.a *.o
@mv librealize.a ../../lib
@rm *.o *.c *.lis
ubb.txt
========
*RESOURCES
IPCKEY 55000
MASTER SITE1
MODEL SHM
*MACHINES
"vmlinux" LMID=SITE1 --->"vmlunx"机器名
TUXDIR="/home/tuxedo/bea/tuxedo8.1" -->根据实际情况
APPDIR="/home/hsta/tux_test/tst_02/bin" -->根据实际情况
TUXCONFIG="/home/hsta/tux_test/tst_02/etc/tuxconfig" -->根据实际情况
ULOGPFX="/home/hsta/tux_test/tst_02/log/ULOG" -->根据实际情况
*GROUPS
GROUP1 LMID=SITE1 GRPNO=1
*SERVERS
service SRVGRP=GROUP1 SRVID=1
*SERVICES
sv_connect
sv_update
.bash_profile
==============
PATH=$PATH:$HOME/bin
export PATH
unset USERNAME
export TUXDIR=/home/tuxedo/bea/tuxedo8.1 -->根据实际情况
export ORACLE_BASE=/home/oracle -->根据实际情况
export ORACLE_HOME=$ORACLE_BASE/product/10.2.0 -->根据实际情况
export ORACLE_SID=ora10g -->根据实际情况
export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib/:/usr/local/lib:$TUXDIR/lib:$TUXDIR/lib
export TUXCONFIG=$HOME/tux_test/tst_02/etc/tuxconfig -->根据实际情况, 和ubb.txt中保持一致
export PATH=$PATH:$ORACLE_HOME/bin:$TUXDIR/bin:.
export LANG=C
要把client,public,realize,service目录下进行make编译
用tmloadcf -y ubb.txt编译生成tuxconfig
tmboot -y 启动程序 这里可以看到启动的进程。
键入tmadmin, 然后输入psc 可看到启动的服务。 按Q键退出。
tmshutdown -y关闭进程
数据库表结构
=============
create table PLSQLTEST
(
salary NUMBER,
NAME VARCHAR2(10)
);
insert into plsqltest (salary, NAME)
values (1000, 'xym');
insert into plsqltest (salary, NAME)
values (2000, 'ht');
commit;