分类:
2009-07-08 21:19:07
l 简介
l 定义
l ATMI
l UBBconfig
作为对呼叫/应答方式的补充,TUXEDO提供了一种称为会话的通讯方式。该方式用于客户端和服务端需要进行大量、多次数据传输并保持连接时。在一个会话过程中双方会有多次发送和接收。例如,一对客户端/服务端之间传诵一个大的数据库查询结果游标时,需要进行几次传输。
在呼叫/应答方式中,所有的数据必须在一次通讯中传递,不保留任何中间状态信息。在会话模式中,通讯双方使用了一种“半双工”协议。一个进程只能处于发送数据或接收数据状态之一。该通讯协议中,状态信息与数据一同传送。
会话被用来传送大量数据,如:
² 报表
² 数据/图形文件传输
² 大型数据库查询
此模式必须进行另外的ATMI编程才能实现。以下函数协助实现此种连接:
² tpconnect() 建立连接
² tpsend() 发送信息
² tprecv() 接收信息
² discon() 撤消连接(出错时)
在会话持续期间,客户端被绑定在服务上。不利之处是服务在会话期间不能响应其他请求。
ATMI
int tpconnect (char *svc, char *data, long len, long flag)
int tpsend( int cd, char *data, long len, long flag, long *revent)
int tprecev(int cd, char *data, long len, long flag, long *revent)
int tpdiscon(int cd )
ubbconfig应作的改动
*RESOURCES MAXCONV 域内缺省最大会话数
MACHINES MAXCONV 本机器上最大会话数,可以超越*RESOURCES节定义的域内缺省最大会话数
*SERVERS CONV=Y 定义该服务是一个会话方式的服务。
ubbconfig的例子
*RESOURCES
MAXCONV 20
*MACHINES
lcspn1 TUXDIR=”/usr/tuxedo”
MAXCONV=25
*SERVERS
audit SRVGRP=BANKB1 SRVID=1
CONV=Y
CLOPT=”-A”
会话方式的客户端源程序
main(int argc, char *argv[])
{
int ret,cd; /* 循环计数器 */
char *buf; /* 数据指针 */
long len; /* 长度 */
long revent; /* tpsend 失败的事件方式 */
/* 连接TUXEDO – tpinit() */
if ( buf = (char *)tpalloc(“STRING”,NULL,1024)==NULL)
{
printf(“tpaclloc():%s\n”,tpstrerror(tperrno));
tpterm();
exit(-1);
}
if ( cd = tpconnect(“AUDIT”,NULL,0,TPSENDONLY)==-1)
{
printf(“tpconnect():%s”,tpstrerror(tperrno));
tpfree(buf);
tpterm();
exit(-1);
}
strcpy(buf, “humpty dumpty”);
if (tpsend(cd , buf ,(long)strlen(buf), 0 , &revent) == -1)
{
printf(“tpconnect():%s”,tpstrerror(tperrno));
}
strcpy(buf, “mickey mouse”);
if (tpsend(cd , buf ,(long)strlen(buf), 0 , &revent) == -1)
…
if (tpsend(cd , NULL , 0, TPRECVONLY , &revent) == -1)
…
if ( tprecv(cd, &buf , &len, 0, &revent) == -1 )
…
tpfree(buf);
tpterm();
}
连接TUXEDO域;
分配一个1K的ATMI缓冲;
使用tpconnect()连接名为’AUDIT’的一个会话交易;
客户端通过TPSENDONLY将通讯控制权交给服务端。此时无数据传送。返回的通讯描述符存储于cd,用来跟踪绑定在会话上的唯一服务过程;
数据首先被复制到ATMI缓冲中;
数据被发送到会话服务上;
第二部分数据被复制到ATMI缓冲中;
用tpsend()发送到会话服务上;
客户端用TPRECVONLY标志放弃控制权。此处调用tpsend()没有发送数据,客户端准备接收数据;
客户端用tprecv()接收数据。
会话方式的服务端源程序
void CONV(TPSVCINFO *rqst)
{
static state = SRECV;
long len, revent;
for ( ; ;)
{
switch(state)
{
case SRECV:
if ( tprecv(rqst->cd, &buf, &len, 0, &revent ) == -1)
{
if ( tperrno == TPEEVENT && revent == TPEV_SENDONLY)
{
userlog(“state change from receive to send”);
state = SSEND;
}else
{
tpreturn(TPFAIL, 0, rqst->data, 0, 0 );
}
}
break;
case SSEND:
strcpy(buf, “all done & protocol complete”);
if ( tpsend(rqst->cd, buf, 0, 0, &revent)==-1)
{
userlog(“tpsend(%d):%s”,revent,tpstrerror(tperrno));
}else
{
userlog(“SEND MESSAGE”);
}
state = SDONE;
break;
case SDONE:
tpfree(buf);
tpreturn(TPSUCCESS, 0, rqst->data, 0, 0);
break;
}
}
}
#define SRECV 1
#define SSEND 2
#define SDONE 3
以上宏定义在程序中用到;
当客户端刚连接交易时,状态被设为RECEIVE;
此部分代码是会话交易在RECEIVE状态中;
tprecv()用来接收客户端数据;
协议在以下情况把状态由RECEIVE转成SEND:
tprecv()返回-1
tperrno被设成TPEEVNT
revent被设成TPEV_SENDONLY
在状态变成SEND后,服务可以调用tpsend();
如果协议有“部分”失败,服务切断客户端连接去处理错误;
代码将会话交易状态转成SEND;
使用tpsend()发送数据;
在一次数据传送后,服务状态被设成DONE;
注意tpreturn用来结束一个成功的会话;tpdiscon()用于出错时结束会话。