| 由于Tuxedo的ATMI开发基本上是在C语言来进行开发的,本文根据《Using the Visual C++ IDE To Develop BEA Tuxedo ATMI Applications》一文对MS VC 6.0编译器进行了修改,然后在此基础上开发了server和client程序,所有程序都是C++语言,也利用了Win32 SDK的一些API,实现了一个简单的同步通讯例子,使用了自定义缓冲FML,虽然Tuxedo支持在VC开发工具,但是目前类似的例子很少见到,而VC开发工具目前已有很多开发者使用,本文希望能更多的人尝试不同的开发工具使Tuxedo的开发者有更多的选择,同时大家更加理解Tuxedo的通信机制。
目 录
1.工作环境:...
2. FML的开发...
3. MS VC编译器的配置...
4.环境变量和UBB的配置...
5.Server端的开发...
6. Client端的开发...
7 总结...
作者资料:...
1.工作环境:
Windows2000 server
Tuxedo 8.1
机器一:CPU P4 1.4MHz 内存:512M
机器二:CPU P4 1.4GHz 内存:512M
2. FMLx的开发
由于本例程是要进行文件传输,因此文件内容我们采用CARRAY类型,下面是我们采用Tuxedo的工具tuxdev.exe来完成,参见图1。
图 1
然后在Build菜单中选择Create,则在该目录下生成一个头文件,其实是对每一个名称产生一个FLDID32,该ID代表该FML缓冲中的数据成员ID,以后调用很多FML 函数使都会使用。
下面是生成的头文件ftp.h
#define name ((FLDID32) 201326593) // number: 1 type: carray
#define size ((FLDID32) 33554434) // number: 2 type: long
3. MS VC编译器的配置
参照Bea网站中的《Using the Visual C++ IDE To Develop BEA Tuxedo ATMI Applications》一文对你的VC编译器进行配置,就会发现在你的Tools菜单中多了一个工具即BuildTuxedo,打开就会弹出一个对话框,参见图2。对此对话框进行配置你的server和client,将会自动形成一些文件的代码,这些将是我们工作的开始。
图 2
如果你选择开发服务器,你还要选择Service Tab进行配置,这个详细情况请参见《Using the Visual C++ IDE To Develop BEA Tuxedo ATMI Applications》。
本例程的server端Service的配置是:函数名称未MYFTP,Service名称也是MYFTP,请参见图3。
图 3
4.环境变量和UBB的配置
由于要建立远程文件传输,因此需要在环境变量中添加WSNADDR和FLDTBLDIR32和FIELDTBLS32的配置,详细请参见Bea电子文档区UBBCONFIG(5)一文。
下面是我的环境变量的配置:
set TUXDIR=c:\BEA\Tuxedo8.1 //根据实际情况
set APPDIR=D:\mywork\server //根据实际情况
set PATH=%TUXDIR%\bin;%APPDIR%;%PATH%
set TUXCONFIG=%APPDIR%\tuxconfig //根据实际情况
set WSNADDR=//192.168.0.109:8000 //根据实际情况
set FLDTBLDIR32=%APPDIR% //根据实际情况
set FIELDTBLS32=%APPDIR%\ftp.fml //根据实际情况
VCVARS32.BAT
下面是我的UBB配置
# (c) 2003 BEA Systems, Inc. All Rights Reserved.
#ident "@(#) samples/atmi/simpapp/ubbsimple Revision: 1.5 "
#Skeleton UBBCONFIG file for the TUXEDO Simple Application.
#Replace the <bracketed> items with the appropriate values.
*RESOURCES
IPCKEY 100001 #<Replace with a valid IPC Key> #这个地方改过
DOMAINID ftpapp #根据实际情况
MASTER simpftp #根据实际情况
MAXACCESSERS 100
MAXSERVERS 5
MAXSERVICES 10
MODEL SHM
LDBAL N
*MACHINES
DEFAULT:
APPDIR="D:\mywork\server" #根据实际情况
TUXCONFIG="D:\mywork\server\tuxconfig" #根据实际情况
TUXDIR="C:\bea\tuxedo8.1" #根据实际情况
GDYANGGCH LMID=simpftp #根据实际情况,前面的<machine name>替代成我的机器名LZ
MAXWSCLIENTS=10
*GROUPS
GROUP1
LMID=simpftp GRPNO=1 OPENINFO=NONE #根据实际情况
*SERVERS
DEFAULT:
CLOPT="-A"
WSL SRVGRP=GROUP1 SRVID=22 #根据实际情况
CLOPT="-A -- -n //GDYANGGCH:8000 -m2 -M6 -x10"
FtpApp SRVGRP=GROUP1 SRVID=1 #根据实际情况
*SERVICES
MYFTP #服务名和上面创建的Service名称一样
5.Server端的开发
由上述BuildTuxedo工具生成的文件中,必然有一个头文件和CPP文件(本文采用C++语言),因此将其添加到工程中,然后将“FML32.h”和刚才生成的FML头文件添加到你的主要CPP文件中(完成服务函数的文件中),下面是我的头文件清单:
#include "stdafx.h" //VC工程形成
#include <stdio.h>
#include <ctype.h>
#include <tmenv.h> //BuildTuxedo工具形成
#include <xa.h> //BuildTuxedo工具形成
#include <atmi.h> //BuildTuxedo工具形成
#include <fstream.h>
#include "fml32.h" 要使用FML32必须包含
#include “ftp.h” 用mkfldhdr32.exe形成的
剩下的任务就是编写你的Service相关连的函数,本例程是MYFTP函数,下面是我的MYFTP函数的代码部分,以C++的ofstream将Tuxedo传来的缓冲转变文件。
void MYFTP _((TPSVCINFO *rqst))
{
TM32U len;
int ret;
char* sbuf, *sResult;
FBFR32 *iFML;
//获得数据的指针
iFML = (FBFR32 *)rqst->data;
//开buffer用于存放文件
if((sbuf = (char *) tpalloc("CARRAY", NULL, 10*1024)) == NULL) {
printf("Error in FML allocation!","Error");
tpterm();
return ;
}
sResult=(char*)tpalloc("STRING",NULL,1024);
//从FML中读出文件的数据到buffer
ret = Fget32(iFML,size,0,(char *)&len,0); //掌握FML的函数是使用FML缓冲变量的关键,其中size来自于ftp.h头文件
ret = Fget32(iFML, name, 0, sbuf, &len); //name来自ftp.h头文件
if(ret ==-1)
sprintf(sResult,"error in geting transfer data, the error code is %d",ret);
else
sprintf(sResult,"succeed in ftp!");
ofstream sFile("test.bak");
sFile.write(sbuf,len);
sFile.flush();
sFile.close();
tpreturn(TPSUCCESS, 0, sResult, 0L, 0);
}
编译成功后,出现一个server同级目录,调用tmloadcf对UBB配置成功后,启动服务,应该有三个服务,参见图4。
图 4
6. Client端的开发
client端的开发是一个WIN32的应用程序,通过输入文件上传的路径,读取文件,然后利用FML缓冲上传到Server端。
这里需要主要的是Tpinit前需要将一些环境变量,下面是我的初始化函数:
static bool _init()
{
strcpy(TempBuf, "WSNADDR=//192.168.0.109:8000"); //这里的ip和port根据实际情况指定.
tuxputenv(TempBuf);
memset(TempBuf,0,255);
strcpy(TempBuf,"FLDTBLDIR32=D:\mywork\client");
tuxputenv(TempBuf);
memset(TempBuf,0,255);
strcpy(TempBuf,"FIELDTBLS32=D:\mywork\client\ftp.fml");
tuxputenv(TempBuf);
if (tpinit((TPINIT *) NULL) == -1) {
return false;
}
return true;
}
下面就是进行文件的读取(略去)和缓冲的转换,缓冲的转换是影响是否成功的重要部分,需要仔细读取FML函数的说明,参见http://e-docs.bea.com/tuxedo/tux80/atmi/rf3fml.htm。
这里主要用到了其中的一个函数fchg32(),详见下文。
int ftpDo(HWND hDlg,char *sFile)
{
//开辟文件的内存空间 和 SendBuf
char *rcvbuf,* pBuf;;
FBFR32 *sndbuf;
int ret=0;
long rlen;
FLDLEN32 ldlen;
//调用tpalloc()为指针分配大小,如果要调用fchg32必须使用该函数进行空间大小的分配,代替malloc()函数。这部分略去
…
//进行初始化
if(!_init())
{
MessageBox(hDlg,"Error in initilization!","Error",0);
return 0;
}
MessageBox(hDlg,"Ok in initilization!","Ok",0);
//读取数据文件到pBuf指定的内存,fsize为文件长度
ifstream in(sFile);
in.seekg(0,ios::seek_dir::end);
streampos pos = in.tellg();
sprintf(pBuf,"The file size is %d",pos);
if(pos)
MessageBox(hDlg,pBuf,"Notify",0);
in.seekg(0,ios::seek_dir::beg);
if (pos<(1024*1024)) {
in.read(pBuf,pos);
}
//将文件数据放入FML SendBuf
ldlen = (TM32U)pos;
ret = Fchg32(sndbuf,size,0,(char *)&ldlen,0); //使用Fchg32函数将FML缓冲填充,size是在ftp.h头文件中定义的FML变量的FLDID32
ret = Fchg32(sndbuf, name,0, pBuf,ldlen); // name是在ftp.h头文件中定义的FML变量的FLDID32
if (ret == -1) {
goto finished;
}
//call service
ret = tpcall("MYFTP", (char *)sndbuf, 0L, (char **)&rcvbuf, &rlen, 0L);
if (ret == -1) {
goto finished;
}
MessageBox(hDlg,"ok in transfer file!","Ok",0);
in.close();
tpfree((char *)sndbuf);
tpfree((char *)rcvbuf);
tpterm();
return 1;
finished:
in.close();
tpfree((char *)sndbuf);
tpfree((char *)rcvbuf);
tpterm();
return 0;
}
运行后,由于是一个DEMO,目前功能较为简单,需要手工输入文件路径,当然程序会判断文件是否存在,参见图5。
图 5
当你输入文件路径,点击SUBMIT,将随后进行初始化,判断文件存在等工作,如果全部成功,将出现提示框显示文件传输成功。
7 总结
本文有两个方面的突破:一方面是将VC和Tuxedo相结合,为开发者提供了一个更多的选择,并且利用VC来开发服务,大大加快了开发的速度,将服务的开发从传统的Unix转到Windows平台上,等大部分代码调试完成后,完全也可以再转到Unix平台上,这一工作应该比较容易,当然UNIX有很多不同于Windows的东西,但是在服务的开发方面我们尽量使用标准的C++,应该问题不大。
另一方面是突出了如何开发你的FML,定义自己的缓冲变量,并如何利用FML函数将这些缓冲利用起来,完成服务的调用,为开发者进行FML开发提供了一个清晰的思路。
当然由于作者初步接触Tuxedo,对Tuxedo理解得不够深刻,文章中的一些观点可能是错误的或者不够妥当,希望大家多多指正,更希望我们在Tuxedo的开发方面有更多的尝试,这样才有更多的收获。
|