大家好,我是Michael Guo,或者虫哥,这是我的笔名:邮箱:gwlii@163.com[/email],下面我讲述一下怎么去封装一个通用的 tuxedo客户端 转载本篇文章,请注明作者:Michael
Guo,并且标明:本文章来自于www.tuxdev.cn 我们知道tuxedo有4种类型的缓冲区,下面我将演示如何封装这4种类型的缓冲区
并封装好了之后,发送给tuxedo,然后获得返回数据,并进行解析,输出 整个过程,完整的封装了tuxedo。并且封装成为一个通用的tuxedo客户端。
一:,我们来分析一下输入的配置文件格式如下:
servicename@wsnaddr@typebuffer[/email]@数据成员名称:inout@数据成员类型@数据成员名称:inout@类型..(目前支持int,double,float,char,long)
对于fml类型的缓冲区需要提供FLDTBLDIR32=路径和FIELDTBLS32=值, 例如:
string类型:[url=]SWAP@//192.168.9.33:21550@string@send:in:char[1024]@recv:out:char[10[/url] 24]表示SWAP服务在那个主机上,服务端接收缓冲区类型为STRING,入参数据成员名称:send,ch
ar[1024]长度,出参数据成员的名称:recv,char[1034]
view32类型:INSERTVIEW@//192.168.9.33:21552@view32@rid:inout:int@rname:inout:lon [email=g@rsal:inout:char[8]g@rsal:inout:char[8[/email]]
表示INSERTVIEW这个服务在主机上,服务端接收VIEW32缓冲区,入参的数据成员名称分别是 :rid,rname,rsal 数据成员的类型分别是:int类型,long,和char类型,也就是struct有3个成员
fml32类型:[url=]INSERTFML@//192.168.9.33:21552@fml32:FLDTBLDIR32=/home/guowl/fml:FIELDTBLS32=regions@id:inout:long@name:inout:char[8]@sal:inout:char[8[/url]]
表示INSERTFML这个服务在主机上,服务端接收FML32缓冲区,域表头文件的目录在/home/guowl/fml,域表头文件名称regions 数据成员名称分别是:id,name,sal,类型分别是:long,char[8],char[8] 然后将这个服务定义文件,读入到一个char
*的指针里面,
char * GetServiceDef()//获取服务配置文件
{
char sTmp[255]="";
static char sBuffer[8192]="";
strcpy(sTmp,"/home/guowl/service.def");//服务配置文件的路径 FILE *fp;
fp=fopen(sTmp,"r");
if(fp==NULL) {
printf(" cannot open 配置文件 file%s\n",tmp);
return -1;
}
memset( sBuffer,0,sizeof(sBuffer));//读取到sBuffer
fread(sBuffer,255,100,fp); return sBuffer;//返回sBuffer;
}
二.我们来介绍一下对外的统一接口函数:
//4个入参,服务名,请求的入参数据,状态,和data,这个data指针是/home/guowl/servi ce.def里面的内容//g_OutputData,g_InputData,g_sname,tuxlog均为全局的char一维数组
char * InterFace( char *ServiceName, char *InputData,int *ServiceStatus, char *data )
{
memset(g_OutputData,0,BUFFLEN*sizeof(char));//全局一维数据初始化 memset(g_InputData,0,BUFFLEN*sizeof(char));
//由于入参是指针,极其容易发生变化,所以先把请求的入参数据和请求的服务名称复制到
g_InputData和g_sname
memcpy(g_InputData,InputData,strlen(InputData)); g_InputData[strlen(g_InputData)]=0;
memset(g_sname,0,sizeof(g_sname));//先初始化,再复制,因为是全局变量
memcpy(g_sname,ServiceName,strlen(ServiceName));
sname[strlen(sname)]=0;
memset(tuxlog,0,sizeof(tuxlog));//日志数组的初始化,tuxlog表示日志的一维数组
if(strlen(g_InputData)==0) {//判断请求的入参数据是否为空
*ServiceStatus=-3;
return (char*)NULL;
} //gx是一个全局的对象,他是TuxPost类型的一个对象,后面会介绍每个类的声明以及类的? 饔?
/* gtux.m,m是TuxPost类里面的string对象,用来存储日志信息,Buffer是TuxPost类里面? 墓潭?
长度的一纬char数组。。用来存储每一次请求,tuxedo的返回结果,这两个都需要初始化 */
gtux.m.clear();
memset(gtux.Buffer,0,sizeof(gtux.Buffer));
//*ServiceStatus= 1;//表示请求状态,默认为-1,表示失败
//g_out1也是全局的二维char数组,用来分割使用,配合splitStr函数使用。
//splitStr函数返回指针data里面,使用"\n"为分隔符,能把data分割 每一份,从前往后,可以用g_out1[1],g_out1[2]....
//下面讲公用函数的时候,会介绍的
memset(g_out1,0,sizeof(g_out1));
intiNum=splitStr(data,"\n",g_out1);
//Stype是TuxPost类型里面表示类型,也就是缓冲区类型,STRING/VIEW32/FML32,注意全 部都是大写,他也需要初始化
memset(gtux.Stype,0,sizeof(gtux.Stype));
//RedoSvc是TuxPost类型里面的一个成员函数,会查询本次请求以前有没有请求过同样的 服务
//如果请求过,则会优化一些细节,减少系统的消耗,也就是一个容器而已
gtux.RedoSvc(g_sname);
string RedoServiceName;
string Redoinput;
RedoServiceName.assign(sname); //获取redo servicename..。
Redoinput.assign(g_InputData);
//获取本次请求的redo 请求入参
if(Redoflag!=1) {//Redoflag也是全局变量,=1表示以前请求过,!=1表示以前没请求过
for(int i=0;i<iNum;++i) {
if(strcmp(g_out1[i],"")!=0) {
memset(sout,0,sizeof(sout));
memcpy(sout,g_out1[i],sizeof(g_out1[i]));
sout[strlen(g_out1[i])]=0;
//上面的for循环是针对配置文件service.def的每一行数据,也就是g_out[i],判断是否 为空。。
if(gtux.VeiwInit(sout,g_sname)==0) {
break;
//针对每一行的数据做一些初始化和成员的识别,包括gtux.Stype和gtux.wsnaddr等等
}
}
}
}
if(strcmp(gtux.Stype,"")==0) {//判断是否识别到了本次请求的缓冲区的类型信息 *ServiceStatus=-2;
memcpy(tuxlog,gtux.m.c_str(),gtux.m.size());
//如果没有识别到。。。那么输出日志 的错误信息,并且返回
return (char*)NULL;
}
if(strncmp(gtux.Stype,"FML",3)==0) {//如果是FML类型,
if(gtux.FmlDest()==-1) { //分配接收缓冲区,发送缓冲区以及初始化连接tuxedo等等。
*ServiceStatus=gtux.m_status;
memcpy(tuxlog,gtux.m.c_str(),gtux.m.size());//如果上述操作失败了,返回日志错误 信息
return NULL;
}
if(gtux.CallAnaly(g_InputData,sname)==-1) {//分析本次的请求入参数据,根据入参数据,进行缓冲区的数据填充也就是缓冲?鳩ML成员的数据填充
*ServiceStatus=gtux.m_status;
memcpy(tuxlog,gtux.m.c_str(),gtux.m.size());//填充失败..
return NULL;
}
if(gtux.FInvoke(sname)==-1) {//呼叫TUXEDO的服务..。
*ServiceStatus=gtux.m_status;
memcpy(tuxlog,gtux.m.c_str(),gtux.m.size());
return NULL;//失败了。。
}
gtux.DelMem();//做一些清理工作。。。
}
if(strncmp(gtux.Stype,"VIEW",4)==0) {//VIEW32缓冲区
if(gtux.ViewDest()==-1) {//分配VIEW32缓冲区,初始化连接tuxedo等等
*ServiceStatus=gtux.m_status; memcpy(tuxlog,gtux.m.c_str(),gtux.m.size()); return NULL;
}
if(gtux.CallAnaly(g_InputData,sname)==-1) {//分析本次请求的入参数据,之后进行发送缓冲区数据的填充
*ServiceStatus=gtux.m_status; memcpy(tuxlog,gtux.m.c_str(),gtux.m.size()); return NULL;
}
if(gtux.VInvoke(sname)==-1) {//呼叫view32的tuxedo服务
*ServiceStatus=gtux.m_status;
memcpy(tuxlog,gtux.m.c_str(),gtux.m.size()); return NULL;
}
gtux.DelMem();//做清理工作
}
if(strncmp(gtux.Stype,"STRING",6)==0 ) {//STRING缓冲区的处理方式.
if(gtux.StringDest()==-1) {
*ServiceStatus=gtux.m_status; memcpy(tuxlog,gtux.m.c_str(),gtux.m.size()); return NULL;
}
if(gtux.CallAnaly(g_InputData,sname)==-1) {
*ServiceStatus=gtux.m_status; memcpy(tuxlog,gtux.m.c_str(),gtux.m.size());
return NULL;
}
if(gtux.SInvoke(sname)==-1) {
*ServiceStatus=gtux.m_status; memcpy(tuxlog,gtux.m.c_str(),gtux.m.size());
return NULL;
}
gtux.DelMem();
}
//上面每种缓冲区的处理流程完成了之后,就开始把gtux.Buffer里面的数据,返回? 鋈?,环游中间产生的日志信息等等.
if(strcmp(gtux.Buffer,"")!=0) {
memset(g_OutputData,0,BUFFLEN*sizeof(char));
memcpy(g_OutputData,gtux.Buffer,strlen(gtux.Buffer));
}
memcpy(tuxlog,gtux.m.c_str(),gtux.m.size());
*ServiceStatus=gtux.m_status; return g_OutputData;
}
三.介绍公用的成员函数,以及涉及到的类和函数的声明:
#define IN 0 //入参标志
#define OUT 1 //出参标志
#define INOUT 2 //即是出参,又是入参标志
#define BUFFLEN 20480
extern char g_out1[255][255];
extern char g_out2[255][255];
extern char g_FLDTBLDIR32[255];
extern char g_FIELDTBLS32[255];
extern char g_WSNADDR[255];
extern char sname[255];
extern char sout[255];
extern char g_OutputData[BUFFLEN];
extern char g_InputData[BUFFLEN];
extern int Redoflag;
extern TPINIT* tpinitbuf; 上面都是全局变量的声明.
class TuxPost
{
private:
char m_CurWSNADDR[64];
bool m_bInConnection; //是否正处在连接之中
char FIELDTBLS32[255];//类里面的FML域表头文件目录
char FLDTBLDIR32[255];
char *v_RecBuff; //view32接收缓冲区
char * v_SendBuff; //view32发送缓冲区
char * f_RecBuff; //fml32接收缓冲区\
char * f_SendBuff;//fml32发送缓冲区
char * s_RecBuff;//string接收缓冲区
char * s_SendBuff; //string发送缓冲区 Veiw gview;//辅助类对象。。。
public:
char Buffer[BUFFLEN];//统一的,用于接收tuxedo返回的处理结果
char Stype[255];//缓冲区类型
bool TuxInit();
bool TuxTerm();
int StringSrc();//分配发送缓冲区
int StringDest(); //分配接收缓冲区函数
int VeiwInit(char*a,char
*sname);//初始化service.def里面的内容,查找到和本次请求入参一样的tuxedo服务记录?⑶易龀稍钡某跏蓟?
int SetVeiwBuffer();//填充VIEW32发送缓冲区
int CallAnaly(char *p,char *sname);//分析本次请求的入参数据,以方便每个缓冲区的填充
int ViewDest();
int ViewSrc();
int BufferViewSend();//填充VIEW32的发送缓冲区
int BufferFmlSend(char *data,char *value,const char *p);//填充fml缓冲区,来源数据是
view gv
int SetSendFml(char *data,char *value,int iNum);
int BufferStringSend();//填充STRING发送缓冲区
int BufferStringRec();
int BufferFmlRec();
int FmlDest();
int FmlSrc();
void DelMem();//清理现场的函
int VInvoke(char *sname);//view32的tpcall版本
int BufferViewRec();
//处理VINVOKE后,组织数据返回结果
int OutViewBuffer();//处理返回结果
int FInvoke(char *sname); //FML版本的tpcall
int SInvoke(char *sname);
//STRING版本的tpcall
int SetServType();
//设置本次请求的缓冲区类型
int Param(const char*); //判断是入参,出参的函数
map<string,Trie> themap; //这个MAP用于保留每次请求后的结果。。以方便下次请求的成员设置
int RedoCallAnaly(string,string);//分析本次请求是否已经请求过
int makeTrie(); //产生一个Trie的对象,用于存储themap
int RedoSvc(string s); //判断是否请求过
string RedoStr;
map<string,VeiwType>RedotheView; //如果请求过,这个容器是自动保存业务成员信息的容器
int CheckFmlTables();//加入了检查FML请求成员的合法性.