第八章TUXEDO的通讯方式.docx
《第八章TUXEDO的通讯方式.docx》由会员分享,可在线阅读,更多相关《第八章TUXEDO的通讯方式.docx(54页珍藏版)》请在冰豆网上搜索。
第八章TUXEDO的通讯方式
第八章:
TUXEDO的通讯方式
TUXEDO中的客户端与服务端之间可以采用的通讯方式有:
1.同步调用方式
2.异步调用方式
3.管道方式
4.会话方式
5.消息方式
6.事件发布订阅方式
7./Q方式
注意:
1.服务端的SERVICE之间,可以采用管道方式,客户端与服务端之间不能采用。
2.客户端与服务端之间可以采用消息方式,服务端的SERVICE之间不能采用消息方式。
3.其他通讯方式在服务端的SERVICE之间,及客户端与服务端之间都可以采用。
管道方式(tpforward())在服务端编程中有说明,/Q方式在第十章中在介绍,对这两种方式在本章种不做介绍.
8.1同步调用方式
如下图所示:
在同步请求/回答方式中,客户端使用tpcall()给本地或远程的服务器(由TUXEDO系统根据公告板信息确定)发送服务请求,此时客户将传送请求服务的名字、用于请求服务的输入参数和输出参数,tpcall()发出后,客户的数据被传送至服务器,得到相应的服务处理。
在此方式下,服务器处理请求时,客户端将等待,不继续运行,直到服务器返回相应结果。
调用过程如图:
例子:
客户端通过对一个文件分块,每调用一次TPCALL()发送一块数据,把一个文件从客户端传送到服务端。
客户端与服务端采用FML32缓冲区进行通信。
在异步调用方式和会话方式中也用到该例子。
可以做一个比较。
在该例子中我们把块的大小定义为
1024字节。
采用FML32缓冲区。
FML32定义文件Myfml.h的内容:
*base100
#namenumbertypeflagscomments
FNAME1string--
BNUM3long
BID4long--
FDATA5carray--
BSIZE6long--
服务端程序Call.c的内容:
#include
#include
#include
#include
#include"fml32.h"
#include"myfml.h"
CALL(TPSVCINFO*rqst)
{
FILE*fp;
longi=0;
FBFR32*rcvbuf;
charfname[100]="";
FLDLEN32len=0;
longbid=0;
longbsize=1024;/*传送的块大小为1024字节*/
char*fdata;
rcvbuf=(FBFR32*)rqst->data;
len=sizeof(bid);
if(Fget32(rcvbuf,BID,0,(char*)&bid,&len)==-1)
{
userlog("Fget32(BID)failure:
%s",(char*)Fstrerror32(Ferror32));
tpreturn(TPFAIL,0,0,0,0);
}
len=sizeof(fname);
if(Fget32(rcvbuf,FNAME,0,fname,&len)==-1)
{
userlog("Fget32(FNAME)failure:
%s",(char*)Fstrerror32(Ferror32));
tpreturn(TPFAIL,0,0,0,0);
}
strcat(fname,".s");
if((fp=fopen(fname,"rb"))==NULL)
{
fp=fopen(fname,"wb");
}
elseif(bid==0)
{
fclose(fp);
fp=fopen(fname,"wb");
}
else
{
fclose(fp);
fp=fopen(fname,"r+b");
}
if(fp==NULL)
{
userlog("fopen()%sfailure\n",fname);
tpreturn(TPFAIL,0,0,0,0);
}
fdata=(char*)malloc(bsize+1);
if(fdata==NULL)
{
userlog("malloc(fdata)failure");
tpreturn(TPFAIL,0,0,0,0);
}
len=bsize;
if(Fget32(rcvbuf,FDATA,0,fdata,(FLDLEN32*)&len)==-1)
{
userlog("Fget32(FDATA)failure:
%s",(char*)Fstrerror32(Ferror32));
tpreturn(TPFAIL,0,0,0,0);
}
i=bid*bsize;
if(fseek(fp,i,0)!
=0)
{
userlog("fseek()failure\n");
tpreturn(TPFAIL,0,0,0,0);
}
i=fwrite(fdata,1,len,fp);
if(i!
=len)
{
userlog("fwrite()fail\n");
tpreturn(TPFAIL,0,0,0,0);
}
fclose(fp);
tpreturn(TPSUCCESS,0,NULL,0L,0);
}
客户端程序callcli.c的内容:
#include
#include
#include"atmi.h"
#include"fml32.h"
#include"myfml.h"
FBFR32*sendbuf=NULL;
char*filebuf;
FILE*fp;
log(constchar*fmt,...)
{
va_listap;
va_start(ap,fmt);
vfprintf(stdout,fmt,ap);
fflush(stdout);
va_end(ap);
fclose(fp);
tpfree((char*)sendbuf);
free(filebuf);
tpterm();
exit
(1);
}
main(intargc,char*argv[])
{
longrcvlen=0;
longfilelen=0;
longi=0;
intret=0;
longreallen=0;
longbnum=0;
longbsize=1024;/*传送的块大小为1024字节*/
FLDLEN32len=0;
if(argc!
=2)
{
(void)fprintf(stderr,"Usage:
%sfilename\n",argv[0]);
exit
(1);
}
fp=fopen(argv[1],"rb");
if(fp==NULL)
{
printf("openfile:
%sfailure\n",argv[1]);
exit
(1);
}
if(fseek(fp,0,SEEK_END)!
=0)
{
perror("fseek()failure:
");
exit
(1);
}
filelen=ftell(fp);
if(filelen==-1)
{
perror("ftell()failure:
");
exit
(1);
}
rewind(fp);
if((sendbuf=(FBFR32*)tpalloc("FML32",NULL,bsize+1024))==(FBFR32*)NULL)
{
printf("Errorallocatingsendbuffer\n");
exit
(1);
}
len=Fsizeof32(sendbuf);
if(Finit32(sendbuf,(FLDLEN32)len)==-1)
{
printf("finit32()failure\n");
exit
(1);
}
if(tpinit(NULL)==-1)
{
printf("tpinit()failure");
exit
(1);
}
filebuf=(char*)malloc(bsize);
if(filebuf==NULL)
{
printf("malloc(filebuf)failure");
exit
(1);
}
bnum=(filelen-1)/bsize+1;
if(Fchg32(sendbuf,FNAME,0,argv[1],(FLDLEN32)len)<0)
{
log("Fchg32(FNAME)failure\n",Fstrerror32(Ferror32));
}
printf("filelen=%ld,blocknum=%ld\n",filelen,bnum);
for(i=0;i{
if(fseek(fp,i*bsize,0)!
=0)
{
log("fseekfailure\n");
}
reallen=fread(filebuf,1,bsize,fp);
if(reallen!
=bsize&&feof(fp)==0)
{
log("fread()failure\n");
}
if(Fchg32(sendbuf,BID,0,(char*)&i,0)<0)
{
log("Fchg32(BID)failure:
%s\n",Fstrerror32(Ferror32));
}
printf("bid=%ld\n",i);
if(Fchg32(sendbuf,FDATA,0,filebuf,(FLDLEN32)reallen)<0)
{
log("Fchg32(FDATA)failure:
%s\n",Fstrerror32(Ferror32));
}
ret=tpcall("CALL",(char*)sendbuf,0,(char**)&sendbuf,&rcvlen,(long)0);
if(ret==-1)
{
log("tpcall()failure:
tperrno=%ld,errstr=%s\n",tperrno,tpstrerror(tperrno));
}
}
log("finished\n");
}
8.2异步调用方式
如图所示:
在异步请求/回答方式中,客户端使用tpacall()给本地或远程的服务器(由TUXEDO系统根据公告板信息确定)发送服务请求,与同步方式不同的是:
在此方式下,服务器处理请求时,客户端继续运行。
当客户端想得到请求的处理结果时,用tpgetrply()将结果取回。
调用过程如图:
例子:
该例子实现与同步调用方式一样的功能.但在该例子中采用异步通讯方式.
服务端的程序与同步调用方式中的一样,客户端的程序Acallcli.c的内容如下:
注意:
每调用TPACALL()50次之后,就要调用tpgetrply()把服务端返回的结果取出,
否则,返回缓冲区会满,会出如下错误:
atpcall()failure:
tperrno=5,errstr=TPELIMIT-asystemlimithasbeenreached
Acallcli.c的内容:
#include
#include
#include"atmi.h"
#include"fml32.h"
#include"myfml.h"
FBFR32*sendbuf=NULL;
char*filebuf;
FILE*fp;
log(constchar*fmt,...)
{
va_listap;
va_start(ap,fmt);
vfprintf(stdout,fmt,ap);
fflush(stdout);
va_end(ap);
fclose(fp);
tpfree((char*)sendbuf);
free(filebuf);
tpterm();
exit
(1);
}
main(intargc,char*argv[])
{
longrcvlen=0;
longfilelen=0;
longi=0;
intret=0;
longreallen=0;
longbnum=0;
longbsize=1024;/*传送的块大小为1024字节*/
FLDLEN32len=0;
longj=0;
intcd[50];
if(argc!
=2)
{
(void)fprintf(stderr,"Usage:
%sfilename\n",argv[0]);
exit
(1);
}
fp=fopen(argv[1],"rb");
if(fp==NULL)
{
printf("openfile:
%sfailure\n",argv[1]);
exit
(1);
}
if(fseek(fp,0,SEEK_END)!
=0)
{
perror("fseek()failure:
");
exit
(1);
}
filelen=ftell(fp);
rewind(fp);
if((sendbuf=(FBFR32*)tpalloc("FML32",NULL,bsize+1024))==(FBFR32*)NULL)
{
printf("Errorallocatingsendbuffer\n");
exit
(1);
}
len=Fsizeof32(sendbuf);
if(Finit32(sendbuf,(FLDLEN32)len)==-1)
{
printf("finit32()failure\n");
exit
(1);
}
if(tpinit(NULL)==-1)
{
printf("tpinit()failure");
exit
(1);
}
filebuf=(char*)malloc(bsize);
if(filebuf==NULL)
{
printf("malloc(filebuf)failure");
exit
(1);
}
bnum=(filelen-1)/bsize+1;
if(Fchg32(sendbuf,FNAME,0,argv[1],(FLDLEN32)len)<0)
{
log("Fchg32(FNAME)failure\n",Fstrerror32(Ferror32));
}
printf("filelen=%ld,blocknum=%ld\n",filelen,bnum);
j=0;
for(i=0;i{
if(fseek(fp,i*bsize,0)!
=0)
{
log("fseekfailure\n");
}
reallen=fread(filebuf,1,bsize,fp);
if(reallen!
=bsize&&feof(fp)==0)
{
log("fread()failure\n");
}
if(Fchg32(sendbuf,BID,0,(char*)&i,0)<0)
{
log("Fchg32(BID)failure:
%s\n",Fstrerror32(Ferror32));
}
printf("bid=%ld\n",i);
if(Fchg32(sendbuf,FDATA,0,filebuf,(FLDLEN32)reallen)<0)
{
log("Fchg32(FDATA)failure:
%s\n",Fstrerror32(Ferror32));
}
ret=tpacall("CALL",(char*)sendbuf,0,0);
if(ret==-1)
{
log("atpcall()failure:
tperrno=%ld,errstr=%s\n",tperrno,tpstrerror(tperrno));
}
cd[j]=ret;
j++;
if(j%50==0)
{
for(j=0;j<50;j++)
{
if(tpgetrply(&cd[j],(char**)&sendbuf,&rcvlen,(long)0)==-1)
{
log("tpgetrply()failure:
cd=%ld,errstr=%s\n",cd,tpstrerror(tperrno));
}
}
j=0;
}
}
log("finished\n");
}
8.3会话方式
采用会话通讯方式,通讯双方在建立连接之后,可以多次发送或接收数据,TUXEDO中采用的是半双工的通讯方式,这种方式特别适用于大批量的数据传输。
名称解释:
发起者(originator,initiator):
发起该会话的进程,它调用tpconnect()与服务端的一个SERVICE建立连接
从属者(subordinate):
tpconnect()中指定的SERVICE
发送者(sender):
当前拥有发送权的进程,它只能发送数据
接收者(receiver):
当前拥有发送权的进程,它只能接收数据
函数说明:
inttpconnect(char*name,char*data,longlength,longflags)
描述:
与名为name的SERVICE建立连接
参数:
name:
SERVICE的名字
*data:
要发送的数据
length:
数据的长度
flags:
可以为TPNOTRAN,TPNOTIME,TPNOBLOCK,TPSIGRSTRT
TPSENDONLY:
发送者只能发送数据,被调用的SERVICE只能接收数据
TPRECVONLY:
发送者只能接收数据,被调用的SERVICE只能发送数据
返回值:
成功返回一个标识该连接的标识符,失败为-1
inttpsend(intcd,char*data,longlength,longflags,long*revent)
描述:
用于发送数据
参数:
cd:
tpconnect()的返回值,用于标识该连接
data:
要发送的数据
length:
要发送的数据的长度
flags:
(TPNOBLOCK,TPNOTIME,TPSIGRSTRT
TPRECVONLY:
把发送权交给接受者,在接受者那里会产生事件TPEV_SENDONLY。
revent:
当返回值为-1时,如果tperrno=TPEEVENT,那么表明有事件发生。
可能的事件有:
TPEV_DISCONIMM:
当会话的发起者调用tpdiscon(),tpreturn(),tpcommit()时,会话的
从属者会收到该事件。
如果有网络故障等,那么会话的发起者也会收到该
事件。
TPEV_SVCFAIL:
会话的发起者会收到该事件,表明会话的从属者调用tpreturn(TPFAIL)
或tpreturn(TPEXIT),并且该会话的从属者不在拥有该控制权
TPEV_SVCERR:
会话的发起者会收到该事件,表明会话的从属者调用
tpreturn(TPSUCCESS,..)返回,并且该会话的从属者不在拥有该控制权.
返回值:
失败为-1,如果tperrno=TPEEVENT,那么导致该调用失败的事件保存在revent中
inttprecv(intcd,char**data,long*length,longflags,long*revent)
描述:
用于接收数据
data:
接收的数据放到该缓冲区中
length:
接收大的数据的长度
flags:
(TPNOCHANGE,TPNOBLOCK,TPNOTIME,TPSIGRSTRT)
revent:
当返回值为-1时,如果tperrno=TPEEVENT,那么表明有事件发生。
可能的事件有:
TPEV_DISCONIMM:
与tpsend()中的含义一样.
TPRECVONLY:
该会话的发送者把发送权交给接受者,在接受者这里会产生事TPEV_SENDONLY。
TPEV_SVCFAIL:
与tpsend()中的含义一样.
TPEV_SVCERR:
与tpsend()中的含义一样.
TPEV_SVCSUCC:
该会话的从属者已成功完成并关闭该会话,那么会话的发起者会收到该事件.表明该会话已成功结束.
返回值:
失败为-1,如果tperrno=TPEEVENT,那么导致该调用失败的事件保存在revent中
inttpdiscon(intcd)
描述:
关闭标识符为cd的会话
参数:
tpconnect()的返回值,用于标识该连接
返回值:
失败为-1
会话通讯方式的整个过程如图所示:
例子:
该例子实现与同步通讯的例子一样的功能,但采用的是会话通讯方式.
服务端程序的内容:
#include
#include
#include
#include"fml32.h"
#include"myfml.h"
longbsize=1024;/*传送的块大小为1024字节*/
FBFR32*rcvbuf;
charfname[256]="";
char*fdata;
tpsvrinit(intargc,char**argv)
{
if((rcvbuf=(FBFR32*)tpalloc("FML32",NULL,(bsize+1024)))==NULL)
{
userlog("tpallocfai