Tivoli 服务台 6.0 开发工具包接口设计器指南

第 7 章:使用 CPIC

返回目录


简介

概述

通信公用程序设计接口(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

APPC 是高级对等通信。

基本对话

基本对话是指应用程序以标准字节流格式交换数据的对话类型。此格式包含两个字节的长度字段(称为 LL),用来指定紧跟在后面的缓冲区长度。LL 数据的每个分组称为逻辑记录

对话

对话是两个应用程序之间的逻辑连接,使用 CPIC 或 APPC 来交换数据。有两种对话类型:映射对话基本对话。对话使用会话与应用程序连接。CPIC 应用程序与 APPC 应用程序对话的方式可能和它与另一个 CPIC 应用程序对话的方式相同。

DDF

DDF(数据说明文件)是一种文件,用于映射 TSD 脚本记录结构和传输的字节缓冲区之间的关系。

LU

LU(逻辑单元)是有效的虚拟机器。尽管可能指定每个物理机器作为 LU,也可能在一个物理机器中配置多个 LU。请注意 CPIC 只使用 LU 型 6.2 类节点。

映射对话

映射对话是指允许伙伴以预先确定的格式交换任意数据记录的对话类型。

模式名称

在对话期间,APPC 用模式名称指定 LU 之间的会话属性。这些属性包括服务的类。

节点服务

节点服务是为 LU 提供基本公用程序功能的一个应用程序或一组应用程序。提供的服务包括补充信息的处理、应用程序启动处理和应用程序终止处理。OS/2 的节点服务由通信管理器(CM)或通信管理器/2(CM/2)提供。

伙伴

伙伴是在 CPIC 对话上交换数据的两个 CPIC 应用程序。

CPIC 对话可以是全双工的。这表示在 CPIC 对话期间的任意给定时间段内,允许一方发送数据,而另一方处于接收状态(即已准备好接收数据)。当处于接收状态的应用程序需要发送数据时,它可以发出一个发送请求。通知对方发出了此请求,且请求应用程序在 StatusReceived 参数中接收通知。

SDN

SDN(符号目的地名称)是通信管理器/2 中的 CPIC 配置名称,它可使应用程序为对话分配请求指明一组要使用的属性。

会话

会话是两个 LU 之间的逻辑连接。LU 通过会话进行通信。

补充信息

在尝试建立对话期间由 CPIC 使用的初始化信息。补充信息包括伙伴 LU 名称、模式名称和 TP 名称。此信息在对话前配置。

注:补充信息由 SDN 引用。

SNA 网络

SNA 网络是 LU 的逻辑网络。

同步级别

同步级别指示 CPIC 对话使用的同步化程度。同步级别可以为下列项之一:

SYNC_POINT

SYNC_POINT 指示您的应用程序支持完全 SAA 资源恢复操作(如“承诺”和“回退”通知)。

注:在 OS/2 中不支持 SYNC_POINT。

TP

TP(事务程序)是使用 CPIC 或 APPC 命令参与对话的应用程序。

TP 名称

TP 名称是事务应用程序的名称。在补充信息中指定此名称。根据操作系统的不同,TP 名称可能为目标 LU 的节点服务应用程序指定一个表条目。用此表查找启动 TP 所需的信息。

开始与另一个程序对话

简单对话实例

下面是应用程序开始与另一个应用程序对话时,所用方法的简短实例。

  1. 程序 A 发出 CPICInitialize 命令,准备启动对话。它给出 SDN,以指定程序 C 作为此对话的目标。程序 A 接收此对话的唯一标识符。
  2. 程序 A 使用此对话标识符发出 CPICAllocate 命令。
  3. 通过节点服务,CPIC 告知伙伴 LU(在步骤 1 中使用的补充信息中指定)应启动程序 C 来接受新对话。
    结果:程序 C 启动,然后发出 CPICAccept 命令。它接收一个对话标识符,以在以后的 CPIC 命令中使用,在对话期间交换这些命令。

TSD 脚本数据说明文件

概述

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 命令

$INCLUDE 命令简化 DDF 的体系结构。此命令提供动态“链接”其他文件的能力。当 TSD 开发工具包遇到 $INCLUDE 命令时,它装入指定的 DDF 并将其字段定义放入当前的 DDF 中。

在字段部分的任何地方都可以包含 $INCLUDE 命令。$INCLUDE 命令的格式为:

$INCLUDE({DDFname})

如果此文件不在当前目录中,则 TSD 开发工具包搜索此文件的 DPATH。如果找不到,则 TSD 开发工具包返回一个错误。

$SIZEOF 命令

$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 字段类型

DDF 处理可识别的类型是:

通过通信管理器/2 使用 CPIC

概述

在尝试编写 OS/2 CPIC 应用程序之前应了解几个细节。这些细节可通过您系统上的节点服务类型来分组。

入网分配

因为节点服务通过设置 TP 来接收入网分配,因此 OS/2 CPIC 应用程序不能是 SNA 服务 TP。仔细阅读下列总结如何处理入网分配的步骤:

  1. 节点服务启动一个进程并设置名为 APPCTPN 的环境变量与 TP 名称相等。
  2. 当应用程序发出 Accept 命令时,节点服务检查接受应用程序的环境的 APPCTPN
  3. 节点服务扫描等待入网分配的列表,查找具有相同 TP 名称的名称。
  4. 如果找到了此名称,则节点服务完成此调用。因为 SNA 服务 TP 名称以十六进制数开头,因此不能在 OS/2 环境变量中设置这些名称。

多个带有 TP 的 TSD 脚本应用程序

如果有多个要为之设置 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 版本 1.1(CM/2)

通信管理器/2 允许单个 CPIC 进程接受多个对话。此外,只要以前尚未发出 Accept 命令,则 CPIC 应用程序可能发出一个 Initialize 命令。

TSD 脚本 CPIC 案例研究

概述

本节为创建简单 CPIC 应用程序的进程提供简要的案例研究。此应用程序用于完成文件传送操作。

为了说明 CPIC 的优点,本案例研究包含两个实例模块。应用程序是在第一个实例模块中创建的。在第二个实例模块中,为了提高性能,对此应用程序进行了少量的修改。

假定

在本案例研究中,假定您对 CPIC、通信管理器/2 和一般的通信处理很熟悉。例如,假定您对通信管理器/2 CMSETUP 公用程序很熟悉。

伙伴应用程序(RCV.CMD)

开始时,需仔细阅读用 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'

实例模块 1 - FILESND.KB

此应用程序的作用是读取一个文本文件,并将每行传送给伙伴应用程序。应用程序完成文件传送后,它开始接收传回的相同文件,并在显示窗口中显示每行。

  1. 用命令 KP FILESND 分析此文件。
  2. 从 CM/2 资料夹启动 CMSETUP 应用程序。
    结果:出现“CPI 通信管理器配置公用程序”对话框。
  3. 在此框中输入名称 FILESND。
  4. 从“CPI 通信”菜单中选择“SNA 功能”。
    结果:出现“CM/2 配置定义”对话框。
  5. 设置补充信息条目。
  6. 在“SNA 功能”对话框中,选择“CPI 通信补充信息”项。
  7. 选择“创建”。
  8. 在对话框中输入下列内容:
    SDN = FILESND
    Target LU = {此处的目标机器名称}
    TP Name = FILERCV
    Security = NONE
    Mode = #INTER
  9. 选择“确认”。
  10. 选择“事务程序定义”项。
  11. 选择“创建”。
  12. 在对话框中输入这些值:
    Service TP = deselected
    TP Name = FILERCV
    OS/2 Program PATH and Filename = CMD.EXE
    Conversation security required = deselected
    Program Parameters = /C {教学指导代码的 PATH}RCV.CMD
  13. 选择“继续”。
  14. 输入下列内容:
    Presentation Type = Background
    Operation Type = Queued, Attach Manager started

仔细检查设置过程

从步骤 3 开始,在通信管理器/2 的补充信息表中设置一个条目。在对话初始化期间使用补充信息表。初始化过程如下:

  1. 应用程序调用 CPICInitialize,将 SDN 作为参数传送。SDN 充当补充信息表的键。
  2. CPIC 使用 SDN 设置新对话的属性。这些属性可代表目标机器和 TP。

使用此方法,可以使编写的 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)。

从命令行启动 RCV.CMD 文件

本案例研究下一部分的内容为:从 OS/2 命令行启动 RCV.CMD 文件。

  1. 设置一个指示器,以告知 CM/2 哪个 TP 正在等待入网对话。通过为命令会话设置一个环境变量做到这点:

    SET APPCTPN=FILERCV

    (可选)为避免无限制地等待入网分配,可编辑 CMLIB 目录中的节点定义文件(NDF)。此文件的名称与通信管理器/2 配置文件的名称相同。
  2. 查找定义 FILERCV TP 属性的部分(搜索 FILERCV)。
  3. 将 INCOMING_ALLOCATE_TIMEOUT 和 RECEIVE_ALLOCATE_TIMEOUT 更改为正整数(单位为秒,分别取 180 秒较好)。
  4. 保存此文件。
  5. 为了使更改生效,需要启动 CM 设置公用程序并对数据字段进行充分的更改,以使 CM 设置公用程序动态地重新验证并应用这些更改。
  6. 通过输入 RCV 并按 ENTER,来运行 REXX 应用程序。
    结果:暂停此应用程序,直到一个分配到达,或超过了 RECEIVE_ALLOCATE_TIMEOUT 的超时值。完成后,此应用程序退出当前的命令进程。
    注:在已准备好启动 FILESND.KB 之前不要启动 REXX 应用程序。

运行 FILESND.KB

此命令在两个应用程序间来回传输源文件,并在窗口中显示结果。

完成双向传送可能要花费一些时间。在窗口中的文件列表下面,可查看定时结果。

此外,注意此文件每行的行号。这些行号与文本文件的每行一起被来回传送。

FILESND.KB 行列表

在编号的行之后是有关此文件的讨论。

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 命令(CPICSendCPICFlush)时才出现这样的情况。发送在第 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 行解除分配对话。

实例模块 2 - FILESND2.KB

这是第二个实例模块。此应用程序的作用与第一个实例相同。不同之处在于更改了一些代码以提高性能。

对于 FILESND2,可使用 FILESND 所用的相同 SDN。

运行 FILESND2

  1. 分析 FILESND2。
  2. 在命令行,输入:
    KML FILESND2 FILESND {文件名}
  3. 此应用程序运行之后,在列表结尾查看经历的时间。它的运行速度应比实例模块 1 快。

文件行列表

这里是 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 指南

返回目录

版权所有