Tivoli 服务台 6.0 开发工具包接口设计器指南
通信公用程序设计接口(CPIC)为负责应用程序间通信的应用程序提供统一的 API。CPIC 接口使用 SNA 的 LU 6.2 创建一组应用程序间服务,包括:
将 CPIC 命令创建为 TSD 脚本语言,以便为 TSD 脚本编程人员扩展这些服务。选择基本 APPC 宏上的 CPIC,以确保平台间的一致性。
本节为 TSD 脚本编程人员提供如何使用 CPIC 来创建 TP 的指南。有关 SAA CPIC 程序设计的详细信息,请参考 IBM 手册:Systems Application Architecture Common Programming Interface for Communications Reference, SC26-4399。
要使用任何 CPIC 命令,都必须安装 CPIC。如果未正确安装 CPIC,则使用 CPIC 命令会导致 Tivoli 服务台(TSD)开发工具包显示一条错误消息,指示不能装入 CPIC。
APPC 是高级对等通信。
基本对话是指应用程序以标准字节流格式交换数据的对话类型。此格式包含两个字节的长度字段(称为 LL),用来指定紧跟在后面的缓冲区长度。LL 数据的每个分组称为逻辑记录。
对话是两个应用程序之间的逻辑连接,使用 CPIC 或 APPC 来交换数据。有两种对话类型:映射对话和基本对话。对话使用会话与应用程序连接。CPIC 应用程序与 APPC 应用程序对话的方式可能和它与另一个 CPIC 应用程序对话的方式相同。
DDF(数据说明文件)是一种文件,用于映射 TSD 脚本记录结构和传输的字节缓冲区之间的关系。
LU(逻辑单元)是有效的虚拟机器。尽管可能指定每个物理机器作为 LU,也可能在一个物理机器中配置多个 LU。请注意 CPIC 只使用 LU 型 6.2 类节点。
映射对话是指允许伙伴以预先确定的格式交换任意数据记录的对话类型。
在对话期间,APPC 用模式名称指定 LU 之间的会话属性。这些属性包括服务的类。
节点服务是为 LU 提供基本公用程序功能的一个应用程序或一组应用程序。提供的服务包括补充信息的处理、应用程序启动处理和应用程序终止处理。OS/2 的节点服务由通信管理器(CM)或通信管理器/2(CM/2)提供。
伙伴是在 CPIC 对话上交换数据的两个 CPIC 应用程序。
CPIC 对话可以是全双工的。这表示在 CPIC 对话期间的任意给定时间段内,允许一方发送数据,而另一方处于接收状态(即已准备好接收数据)。当处于接收状态的应用程序需要发送数据时,它可以发出一个发送请求。通知对方发出了此请求,且请求应用程序在 StatusReceived 参数中接收通知。
SDN(符号目的地名称)是通信管理器/2 中的 CPIC 配置名称,它可使应用程序为对话分配请求指明一组要使用的属性。
会话是两个 LU 之间的逻辑连接。LU 通过会话进行通信。
在尝试建立对话期间由 CPIC 使用的初始化信息。补充信息包括伙伴 LU 名称、模式名称和 TP 名称。此信息在对话前配置。
注:补充信息由 SDN 引用。
SNA 网络是 LU 的逻辑网络。
同步级别指示 CPIC 对话使用的同步化程度。同步级别可以为下列项之一:
SYNC_POINT 指示您的应用程序支持完全 SAA 资源恢复操作(如“承诺”和“回退”通知)。
注:在 OS/2 中不支持 SYNC_POINT。
TP(事务程序)是使用 CPIC 或 APPC 命令参与对话的应用程序。
TP 名称是事务应用程序的名称。在补充信息中指定此名称。根据操作系统的不同,TP 名称可能为目标 LU 的节点服务应用程序指定一个表条目。用此表查找启动 TP 所需的信息。
下面是应用程序开始与另一个应用程序对话时,所用方法的简短实例。
TSD 脚本不允许直接控制内存结构的指定大小,这使得编程人员不必担心自己所声称的记录大小。
尽管这是第四代语言的吸引人的一个属性,但是在使用 CPIC 应用程序时这会造成困难。CPIC 应用程序发送并接收特定大小和格式的字节缓冲区。伙伴应用程序可能使用与本地应用程序不同的存储器格式,包括非 Intel 整数和 EBCDIC 字符串。
数据说明文件(或 DDF)说明不同缓冲区大小的可能性。DDF 定义传输的字节缓冲区的精确格式,并指定格式翻译/转换。TSD 开发工具包使用这些 DDF 作为 CPIC 应用程序的出网和入网缓冲区的“过滤器”。
DDF 的基本结构是:
-- Double dashes are comment to end of line. -- The first section is the partner section. *PARTNER -- character conversion types EBCDIC=TRUE -- integer byte order NON_INTEL=TRUE -- character conversion table. If not specified, TSD Developer's Toolkit will -- use the CM/2 AE table. This default table -- may be insufficient for your use (for example, it -- converts embedded spaces to x'00'). If you want a -- more normal conversion table, set the CM/2 translation -- table file name to ACSGTAB.DAT, which is provided with -- CM/2. Then set CUSTOM_CONVERT to TRUE. CUSTOM_CONVERT=TRUE -- This section is the field section. It is used -- to describe each field of the record and its byte -- mapping and translation. Essentially, this section -- shows how the data buffer should look just after it -- is received (before conversion), or just before a -- send (after conversion). *FIELDS -- Fieldname Type ByteWidth SendUnknowns? Default name CHAR 20 FALSE street CHAR 20 TRUE age INTEGER 20 TRUE birthDate CCYYMMDD 8 FALSE
在此例中,伙伴应用程序在带有非 Intel 风格的整数(例如 IBM 系统 370)的 EBCDIC 机器上运行。发送的记录在 TSD 脚本中说明如下:
SomeRecordName IS RECORD name :STRING; street :STRING; age :INTEGER; birthDate :DATE; description:STRING; END;
说明字段不包括在 DDF 中,这表示在 CPIC 通信期间不传送此说明字段。
DDF 的此部分说明伙伴应用程序的机器类型。此部分的开头用文本 *PARTNER 标记。伙伴部分指示 TSD 开发工具包执行的数据转换类型。例如,设置 EBCDIC=TRUE 表示当与伙伴应用程序通信时,TSD 开发工具包将所有字符串转换为 EBCDIC 或将 EBCDIC 转换为字符串。
在伙伴部分,应设置下列属性。未设置的任意属性采用指定的缺省值。
DDF 的此部分指定要在 CPIC 数据缓冲区中打包和解包的字段和字段类型。此部分以包含“*FIELDS”的行开头。字段部分中的每行应用一个 TSD 脚本传送的记录字段。这些行的格式如下:
{fieldname} {fieldtype} {bytewidth} {sendunknowns?} {default}
每列用空白分隔;这里列出了列定义:
$INCLUDE 命令简化 DDF 的体系结构。此命令提供动态“链接”其他文件的能力。当 TSD 开发工具包遇到 $INCLUDE 命令时,它装入指定的 DDF 并将其字段定义放入当前的 DDF 中。
在字段部分的任何地方都可以包含 $INCLUDE 命令。$INCLUDE 命令的格式为:
$INCLUDE({DDFname})
如果此文件不在当前目录中,则 TSD 开发工具包搜索此文件的 DPATH。如果找不到,则 TSD 开发工具包返回一个错误。
$SIZEOF 命令自动重新计算包含文件的大小。如果将另一个字段添加到包含文件,则不必手动重算包含文件的大小。
在特殊情况下(如设置向量形式的缓冲区时)使用 $SIZEOF 和 $INCLUDE 命令。可以以下列组合形式使用它们:
*PARTNER EBCDIC =TRUE NON_INTEL =TRUE CUSTOM_CONVERT =TRUE *FIELDS GDS1310 INT 2 TRUE 4880 GDS1311LEN INT 2 TRUE $SIZEOF(1311.DDF) + 2 $INCLUDE(1311.DDF) GDS1549LEN INT 2 TRUE $SIZEOF(1549.DDF) + 2 $INCLUDE(1549.DDF) DataLen INT 2 TRUE $SIZEOF(RTRNDATA.DDF) + 2 $INCLUDE(RTRNDATA.DDF)
DDF 处理可识别的类型是:
在尝试编写 OS/2 CPIC 应用程序之前应了解几个细节。这些细节可通过您系统上的节点服务类型来分组。
因为节点服务通过设置 TP 来接收入网分配,因此 OS/2 CPIC 应用程序不能是 SNA 服务 TP。仔细阅读下列总结如何处理入网分配的步骤:
如果有多个要为之设置 TP 的 TSD 脚本应用程序,则必须进行特别的设置。通信管理器/2 只允许指定 kml.exe 作为一个 TP 定义的 OS/2 应用程序 PATH 和文件。对于其它 TP 定义,创建包含下列命令的 OS/2 命令文件:
SET APPCTPN={your TP name} START /C KML /U{path to your KB} {your KB name} EXIT
通信管理器/2 允许单个 CPIC 进程接受多个对话。此外,只要以前尚未发出 Accept 命令,则 CPIC 应用程序可能发出一个 Initialize 命令。
本节为创建简单 CPIC 应用程序的进程提供简要的案例研究。此应用程序用于完成文件传送操作。
为了说明 CPIC 的优点,本案例研究包含两个实例模块。应用程序是在第一个实例模块中创建的。在第二个实例模块中,为了提高性能,对此应用程序进行了少量的修改。
在本案例研究中,假定您对 CPIC、通信管理器/2 和一般的通信处理很熟悉。例如,假定您对通信管理器/2 CMSETUP 公用程序很熟悉。
开始时,需仔细阅读用 REXX 编写的伙伴应用程序。
REXX 伙伴应用程序名为 RCV.CMD。实质上,此应用程序接收数据并将数据存储在词干变量中,一直到状态接收参数指示此应用程序现在可以发送数据。
紧接着此代码实例之后是一些解释,提供有关此应用程序的其他详细信息。
/* RCV.CMD */ /* Receives data strings, building a buffer of all data. /*Upon completion of*/ /* receiving, sends back the buffer. */ /* CPIC commands used: CMACCP */ /* CMCFMD */ /* CMDEAL */ /* CMRCV */ /* CMSEND */
/* a few useful constants */ CM_OK = 0 /* status received */ CM_SEND_RECEIVED = 1 CM_CONFIRM_RECEIVED = 2 /* data received */ CM_NO_DATA_RECEIVED = 0
MaxLength = 257; BufferLen = 0; FileBuffer.0 = 0; 'CPICREXX'
address cpicomm 'CMACCP Conv_ID RetC'; if \(RetC = CM_OK) then do SAY 'ACCP = 'Retc end;
'CMRCV Conv_ID Data MaxLength DataReceived ReceivedLength StatusRecvd ReqToSendRecvd Retc'; if \(RetC = CM_OK) then do SAY 'RCV = 'Retc end;
do while (RetC = CM_OK) & (StatusRecvd \= CM_SEND_RECEIVED) if (DataReceived \= CM_NO_DATA_RECEIVED) then do /* SAY Data */ FileBuffer.0 = FileBuffer.0 + 1; i = FileBuffer.0; FileBuffer.i = Data; end; if (StatusRecvd = CM_CONFIRM_RECEIVED) then do 'CMCFMD Conv_ID RetC'; end; 'CMRCV Conv_ID Data MaxLength DataReceived ReceivedLength StatusRecvd ReqToSendRecvd Retc'; if (RetC \= CM_OK) then do SAY 'RCV = 'Retc end; end;
SAY 'Re-transmitting file'
DO i = 1 TO FileBuffer.0 BufferLen = LENGTH(FileBuffer.i); Data = FileBuffer.i; 'CMSEND Conv_ID Data BufferLen ReqToSendRecvd RetC'; if (RetC \= CM_OK) then do SAY 'SND = 'Retc end; END; 'CMDEAL Conv_ID RetC'; address cmd 'EXIT'
此应用程序的作用是读取一个文本文件,并将每行传送给伙伴应用程序。应用程序完成文件传送后,它开始接收传回的相同文件,并在显示窗口中显示每行。
从步骤 3 开始,在通信管理器/2 的补充信息表中设置一个条目。在对话初始化期间使用补充信息表。初始化过程如下:
使用此方法,可以使编写的 CPIC 应用程序不含硬编码的站点特定信息。它还可为所有 CPIC 应用程序提供一种标准方法来访问这种信息类型。
从步骤 8 开始,创建一个 TP 定义。此条目告知节点服务如何启动某个 TP。
分配对话时,请求分配的 LU 向目标 LU 节点服务系统发送期望的 TP 名称。节点服务系统检查是否在系统上定义了此 TP 名称。如果已定义,则节点服务按有关启动此 TP 的指令去做。当为此 TP 设置了“Attach Manager started”时,如果节点服务可成功启动应用程序,则可启动此 TP。TP 然后发出 CPICAccept。请求的 LU 获得一个成功指示,且启动对话。
对于此 REXX 应用程序,启动一个 OS/2 命令处理器(CMD.EXE)。此参数字符串告知 CMD.EXE 在命令完成时(/C)退出以及要运行什么命令(RCV.CMD)。
本案例研究下一部分的内容为:从 OS/2 命令行启动 RCV.CMD 文件。
此命令在两个应用程序间来回传输源文件,并在窗口中显示结果。
完成双向传送可能要花费一些时间。在窗口中的文件列表下面,可查看定时结果。
此外,注意此文件每行的行号。这些行号与文本文件的每行一起被来回传送。
在编号的行之后是有关此文件的讨论。
1 2 KNOWLEDGEBASE FILESND; 3 4 ROUTINES 5 PROCEDURE DoConversation(VAL Args:List of String); 6 (* sdn, infile *) 7 8 9 PRIVATE 10 11 CONSTANTS 12 CPIC_SUCCESS IS 1; 13 14 TYPES 15 FileRec IS RECORD 16 LineNbr:Integer; 17 Buff:String; 18 END; 19 20 ROUTINES 21 22 FUNCTION RcvData(REF w:WINDOW, VAL Conv:Conversation) :INTEGER IS 23 VARIABLES 24 totalBuff :FileRec; 25 dataRcvd :integer; 26 statRcvd :integer; 27 reqTSRcvd :integer; 28 rc :integer; 29 ACTIONS 30 IF (not(Known(w))) THEN 31 WinCreateScrollWindow($DESKTOP,w, 32 $NullHandler, 1,1,67,7, 'FileSnd','', 0, $WinBorder+ $WinTitle+ $WinHScroll+ $WinVScroll+ $WinSysMenu+ $WinResize); END; 33 REPEAT 34 rc := CPICReceive(Conv,'FILEREC.DDF', totalBuff,DataRcvd, StatRcvd,ReqTSRcvd); 35 IF (rc > 0) THEN 36 IF ((StatRcvd = $CPICConfirmReceived) or 37 (StatRcvd = $CPICConfirmSend Received)) THEN 38 rc := CPICConfirmed(Conv); 39 END; 40 totalBuff.buff := StrTrim (totalBuff.buff); 41 WinWriteLn(w,totalBuff.lineNbr:5&' :'&totalBuff.buff); 42 END; 43 UNTIL ((rc <> 1) OR ((StatRcvd = $CPICSendReceived) OR 44 (StatRcvd = $CPICConfirmSend Received))); 45 Exit(rc); 46 END; -- RcvData 47 48 49 --------------------------------------------- 50 -- Description: Reads in the specified file, transmitting each line via CPIC 51 -- to the partner specified through the given SDN. 52 --------------------------------------------- 53 PROCEDURE DoConversation(VAL Args:List of String) IS 54 VARIABLES 55 Conv :Conversation; 56 fRec :FileRec; 57 ReqTSRcvd:INTEGER; 58 rc :INTEGER; 59 inf :FILE; 60 w :WINDOW; 61 t1,t2 :TIME; 62 ACTIONS 63 t1 := $NOW; 64 IF (ListLength(Args) <2) THEN WinMessageBox($DESKTOP,覐ops椰 $MBOK,覌ML FILESND {SDN} {INFILE}药; Exit; END; FOpen(inf,Args[2],$Read); rc :="CPICInitialize(Conv,Args[1]);" IF (rc <CPIC_SUCCESS) THEN WinMessageBox($DESKTOP, 覂PIC Error椰$MBOK, 覊nit returns 薛rc); Exit; END; rc :="CPICSetSyncLevel(Conv," $CPICNone); IF (rc <CPIC_SUCCESS) THEN WinMessageBox($DESKTOP, 覂PIC Error椰$MBOK, 覔SL returns 薛rc); END; rc :="CPICAllocate(Conv);" IF (rc < CPIC_SUCCESS) THEN WinMessageBox($DESKTOP, 覂PIC Error椰$MBOK, 襾llc returns 薛rc); Exit; END; rc :="CPICSetPrepareToReceiveType" (Conv, $CPICPrepToReceiveFlush); IF (rc < CPIC_SUCCESS) THEN WinMessageBox($DESKTOP, 覂PIC Error椰$MBOK, 覔PTR returns 薛rc); END; fRec.lineNbr :="0;" while (FReadLn(inf,fRec.Buff)> <2) THEN 65 WinMessageBox($DESKTOP,'Oops', $MBOK,'KML FILESND {SDN} {INFILE}'); 66 Exit; 67 END; 68 69 FOpen(inf,Args[2],$Read); 70 71 rc := CPICInitialize(Conv,Args[1]); 72 IF (rc < CPIC_SUCCESS) THEN 73 WinMessageBox($DESKTOP, 'CPIC Error',$MBOK, 'Init returns '&rc); 74 Exit; 75 END; 76 rc := CPICSetSyncLevel(Conv, $CPICNone); 77 IF (rc < CPIC_SUCCESS) THEN 78 WinMessageBox($DESKTOP, 'CPIC Error',$MBOK, 'SSL returns '&rc); 79 END; 80 rc := CPICAllocate(Conv); 81 IF (rc < CPIC_SUCCESS) THEN 82 WinMessageBox($DESKTOP, 'CPIC Error',$MBOK, 'Allc returns '&rc); 83 Exit; 84 END; 85 86 rc := CPICSetPrepareToReceiveType (Conv, $CPICPrepToReceiveFlush); 87 IF (rc < CPIC_SUCCESS) THEN 88 WinMessageBox($DESKTOP, 'CPIC Error',$MBOK, 'SPTR returns '&rc); 89 END; 90 91 fRec.lineNbr := 0; 92 while (FReadLn(inf,fRec.Buff) > 0) do 93 fRec.Buff := fRec.Buff & Char(13) & Char(10); -- add CR LF 94 fRec.lineNbr := fRec.lineNbr + 1; 95 rc := CPICSend(Conv, 'FILEREC.DDF', fRec, ReqTSRcvd); 96 IF (rc < CPIC_SUCCESS) THEN 97 WinMessageBox($DESKTOP, 'CPIC Error',$MBOK, 'Send returns '&rc); 98 ExitLoop; 99 END; 100 CPICFlush(Conv); 101 END; 102 FClose(inf); 103 104 IF (rc = CPIC_SUCCESS) THEN 105 CPICPrepareToReceive(Conv); -- Indicates Partner may send now. 106 t2 := $NOW; 107 RcvData(w,Conv); 108 END; 109 110 CPICDeallocate(Conv); 111 WinWriteLn(w,'<<<<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>'); 112 WinWriteLn(w,'Elapsed time for outgoing transmission: '& 113 TimeDif(t2,t1,$SECONDS)&' seconds'); 114 WinWait(w); 115 END; 116 117
之后是一个回顾,解释前面的代码样本。
第 42 行包含一些残余代码。最初编写此应用程序是为了使用同步级别 $CPICConfirm,且 RcvData 必须检测和识别伙伴所做的任何确认。因为在第 80 行将同步级别设置为 $CPICNone,因此这种情况不会出现。
第 75-93 行包含对话设置命令。$CPICNone 是对话的缺省值,因此不需要设置。
在第 90 行中,在 CPICAllocate 之后,设置接收准备类型。它指示每当调用 CPICPrepareToReceive 时要采取的操作类型。选择刷新,以便一准备好接收数据就传送最后一个缓冲区。
在第 96-105 行中完成文件传输。请注意只有使用两个 CPIC 命令(CPICSend 和 CPICFlush)时才出现这样的情况。发送在第 15-17 行中定义的记录。
映射文件 FILEREC.DDF 与下列实例相似:
1 2 *PARTNER 3 EBCDIC = FALSE 4 NON_INTEL = FALSE 5 CUSTOM_CONVERT = TRUE 6 7 *FIELDS 8 LineNbr INTEGER 2 TRUE 9 Buff ASE_STRING VAR TRUE 10
将行号和行内容传送给伙伴应用程序。因为 REXX 应用程序将缓冲区作为一个字符串来处理,因此可以发回此缓冲区,且 TSD 开发工具包可再次提取这两个字段。
在第 104 行刷新缓冲区。这将使传送给 CPICSend 的数据立即被传送给伙伴。
在传送文件后,通知伙伴可以开始发送数据。第 22 行的 RcvData 函数处理入网数据。
RcvData 接收入网 FILEREC 数据,直到出现错误(包括伙伴解除分配对话)或此应用程序再次收到发送通知。
在第 114 行解除分配对话。
这是第二个实例模块。此应用程序的作用与第一个实例相同。不同之处在于更改了一些代码以提高性能。
对于 FILESND2,可使用 FILESND 所用的相同 SDN。
这里是 FILESND2.KB 的列表:
1 2 -- A little more efficient example. 3 -- Note that certain lines have been commented out. These were vestiges 4 -- from the original FILESND.KB. New lines are marked by (* NEW *). 5 6 KNOWLEDGEBASE FILESND2; 7 8 ROUTINES 9 PROCEDURE DoConversation(VAL Args: List of String); 10 (* sdn, infile *) 11 12 13 PRIVATE 14 15 CONSTANTS 16 CPIC_SUCCESS IS 1; 17 18 TYPES 19 FileRec IS RECORD 20 LineNbr:Integer; 21 Buff:String; 22 END; 23 24 ROUTINES 25 26 FUNCTION RcvData(REF w:WINDOW, VAL Conv: Conversation):INTEGER IS 27 VARIABLES 28 totalBuff :FileRec; 29 dataRcvd :integer; 30 statRcvd :integer; 31 reqTSRcvd :integer; 32 rc :integer; 33 ACTIONS 34 IF (not(Known(w))) THEN 35 WinCreateScrollWindow($DESKTOP,w, 36 $NullHandler, 37 1,1,67,7, 'FileSnd2','', 0, $WinBorder+ $WinTitle+ $WinHScroll+ $WinVScroll+ 38 $WinSysMenu+ $WinResize); 39 END; 40 REPEAT 41 rc := CPICReceive(Conv,'FILEREC.DDF', totalBuff,DataRcvd, StatRcvd,ReqTSRcvd); 42 IF (rc > 0) THEN 43 IF ((StatRcvd = $CPICConfirmReceived)or 44 (StatRcvd=$CPICConfirmSendReceived)) THEN 45 rc := CPICConfirmed(Conv); 46 END; 47 totalBuff.buff := StrTrim (totalBuff.buff); 48 WinWriteLn(w,totalBuff.lineNbr:5&': '&totalBuff.buff); 49 END; 50 UNTIL ((rc <> 1) OR ((StatRcvd = $CPICSendReceived) OR 51 StatRcvd= $CPICConfirmSendReceived))); 52 Exit(rc); 53 END; -- RcvData 54 55 56 --------------------------------------------- 57 -- Description: Reads in the specified file, transmitting each line via CPIC 58 -- to the partner specified through the given SDN 59 --------------------------------------------- 60 PROCEDURE DoConversation(VAL Args: List of String) IS 61 VARIABLES 62 Conv :Conversation; 63 fRec :FileRec; 64 ReqTSRcvd :INTEGER; 65 rc :INTEGER; 66 inf :FILE; 67 w :WINDOW; 68 t1,t2 :TIME; 69 ACTIONS 70 t1 := $NOW; 71 IF (ListLength(Args) < 2) THEN 72 WinMessageBox($DESKTOP,'Oops', $MBOK,'KML FILESND {SDN} {INFILE}'); 73 Exit; 74 END; 75 76 FOpen(inf,Args[2],$Read); 77 78 rc := CPICInitialize(Conv,Args[1]); 79 IF (rc < CPIC_SUCCESS) THEN 80 WinMessageBox($DESKTOP,'CPIC Error', $MBOK,'Init returns '&rc); 81 Exit; 82 END; 83 rc := CPICSetSyncLevel(Conv, $CPICNone); 84 IF (rc < CPIC_SUCCESS) THEN 85 WinMessageBox($DESKTOP,'CPIC Error', $MBOK,'SSL returns '&rc); 86 END; 87 rc := CPICAllocate(Conv); 88 IF (rc < CPIC_SUCCESS) THEN 89 WinMessageBox($DESKTOP,'CPIC Error', $MBOK,'Allc returns '&rc); 90 Exit; 91 END; 92 rc := CPICSetPrepareToReceiveType(Conv, 93 $CPICPrep ToReceiveFlush); 94 IF (rc < CPIC_SUCCESS) THEN 95 WinMessageBox($DESKTOP,'CPIC Error', $MBOK,'SPTR returns '&rc); 96 END; 97 98 fRec.lineNbr := 0; 99 while (FReadLn(inf,fRec.Buff) > 0) do 100(* NEW *) 101-- By knowing if you are at the end of the file, you can set the appropriate 102-- send type. This allows you to avoid calling CPICPrepareToReceive later 103-- and it avoids making the node services system do an extra transmission 104-- to the partner. 105 IF (FEnd(inf)) THEN 106 CPICSetSendType(Conv, $CPICSendAndPrep ToReceive); END; 107 (* END NEW *) 108 fRec.Buff := fRec.Buff & Char(13) & Char(10); -- add CR LF 109 fRec.lineNbr := fRec.lineNbr + 1; 110 rc := CPICSend(Conv, 'FILEREC.DDF', fRec, ReqTSRcvd);
111 IF (rc < CPIC_SUCCESS) THEN 112 WinMessageBox($DESKTOP,'CPIC Error', $MBOK,'Send returns '&rc); ExitLoop; 113 END; 114-- Let CM/2 do buffering. The other end will still see the 115-- same number of sent buffers. CM/2 may batch some 116-- of the buffers for efficiency 117 (* CPICFlush(Conv); *) 118 119 END; 120 FClose(inf); 121 122 IF (rc = CPIC_SUCCESS) THEN 123-- Don't have to do this, because this notification sent along with last send. 124 CPICPrepareToReceive(Conv); -- Indicates Partner may send now. -- 125 t2 := $NOW; 126 RcvData(w,Conv); 127 END; 128 129 CPICDeallocate(Conv); 130 WinWriteLn(w,'<<<<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>'); 131 WinWriteLn(w,'Elapsed time for outgoing transmission: '& TimeDif(t2,t1,$SECONDS)&' seconds'); WinWait(w); 132END;
正如您所看到的,没有花很大的力气使此应用程序运行得更快些。只是添加了第 105-108 行,删除了第 117 和 124 行(已注释出)。
在 FILESND2.KB 中进行的更改为:
使用 CPIC 进行数据缓冲有几个缺陷。主要问题是您的应用程序不能频繁地与伙伴应用程序“联系”。在本节所述的实例中,这没有影响。但是,在很多情况下,伙伴应用程序需要能请求动态发送的权限。在这种情况下,最好控制缓冲区的刷新,以尽可能多地接收伙伴应用程序的标志。
Tivoli 服务台 6.0 开发工具包旧 API 指南