810 likes | 1.66k Views
开发 (2) – 使用 CICS API 和 ECI. 刘睿. 概要. TXSeries 编程框架 TXSeries/CICS 客户机程序 TXSeries 服务器程序. TXSeries 编程框架. 基于 TXSeries 的三层应用开发环境. TXSeries 的应用开发支持框架. 交易 (Transaction) ,任务 (Task) 和逻辑处理单元 (LUW) 的概念.
E N D
概要 • TXSeries编程框架 • TXSeries/CICS客户机程序 • TXSeries服务器程序
交易(Transaction),任务(Task)和逻辑处理单元(LUW)的概念交易(Transaction),任务(Task)和逻辑处理单元(LUW)的概念 • 交易(Transaction):一个交易可以对应于一支或多支CICS服务器端程序的执行。交易的执行多是由终端发出的请求:在终端键入一个四位的交易ID号。在一个交易的执行过程中,可能会触发一个或多个任务的执行。CICS允许一个交易程序被很多用户同时请求执行,而交易之间互不妨碍。这个交易(Transaction)的概念对应一个TD。 • 任务(Task):它是交易执行的一个单一实例。CICS与操作系统相结合,通过分配系统进程给每个任务,这样当一个任务处于等待状态时,操作系统可以将控制权交给另外一个任务。 • 逻辑处理单元(LUW, logical unit of work, also termed a unit of work)每个逻辑处理单元是一组对数据的修改。比如说在一个帐户系统中一个逻辑处理单元由更新可支付帐户,更新帐簿,创建一张支票组成。每一个逻辑处理单元所作的工作是完全独立于由其它逻辑处理单元的工作。在一个逻辑处理单元中修改的资源或是全部成功或全部失败。这个逻辑处理单元(LUW)的概念对应SYNCPOINT之间的代码。
Logical Unit of Work • LUW--交易中两个相邻的提交/回滚之间的处理 • Server Program 可以控制LUW • EXEC CICS SYNCPOINT; • EXEC CICS SYNCPOINT ROLLBACK; • ECI Client 可以控制LUW • eci_extend_mode参数 • ECI_NO_EXTEND结束一个LUW • ECI_EXTENDED将LUW延续至下一次ECI调用 • eci_luw_token参数 • 说明LUW的编号 • ECI_LUW_NEW本次CALL 作为一个LUW
使用交易分类(TClass) TRN1: ProgName = PROG1 TClass = 2 • 11个交易类 • 1 -10,“NONE” (默认) • 交易类1-10可以限制并发运行数 • TClass定义在TD stanza 建议 • 用户交易定义TCLass • CICS交易使用NONE • MaxServers = sum(ClassMaxTasks) 示例 • 1 instance of TRN2. Limit = 5 • Allowed to run • 2 instances of TRN1. Limit =1 • 1 allowed to run, 1 queued TRN1: ProgName = PROG1 TClass = 2 TRN2: ProgName = PROG2 TClass = 7 TClass Class Max Tasks
设置交易分类 • 制作类似CPMI的交易定义,修改TClass为1~10。例如“LPMI”:cicsadd -r CICSNT01 -c td -m CPMI LPMI TClass=1 • 酌情修改RD:ClassMaxTasks (缺省:“1,1,1,1,1,1,1,1,1,1”),RD:ClassMaxTaskLim (缺省:“0,0,0,0,0,0,0,0,0,0”)。 • 修改ECI程序之EciParms::eci_version=ECI_VERSION_1A,EciParms::eci_tpn为新的TD名(例如“LPMI”)。#注:EasyCICS使用SetTransId函数/方法。
CICS Communication Area • CICS通讯区域,由CICS 自动传递。 • 长度不大于32 K (32500)。 • EXEC CICS ADDRESS COMMAREA。 • 被异步启动的交易程序通讯区域长度为0。
CICS通信区要用NULL填充 abcd : LINKAGE SECTION 01 DFHCOMMAREA PIC X(500). : : LINK PROGRAM (abcd) COMMAREA (comm) LENGTH (500) : • A CICS optimisation • Applies to LINK and RETURN commareas 0 20 21 500 500 bytes received Data x’00’ 500 bytes sent 20 bytes transmitted LESS DATA TRANSMITTED
CICS Client编程概述 • 功能 • 从非CICS程序的客户程序调用CICS Server交易 • 编程方式 • External Call Interface,简称ECI • 基于对Server程序(Program)的请求 • 通过通讯缓冲数据区(COMMAREA)与Server交换数据 • ECI应用程序被Server视为发出DPL请求的对等Server • External Presentation Interface,简称EPI • 基于对Server交易(Transaction)的请求 • 通过3270数据流与Server交换数据 • EPI 应用程序被Server视为3270终端 • 多用于内部管理应用
ECI Client程序示例 (C语言) #include <cics_eci.h> ECI_PARMS EciParms; char commArea[1024]; memset (&EciParms, 0, sizeof (ECI_PARMS)); memset(commArea,0,sizeof(commArea)); EciParms.eci_version = ECI_VERSION_1A; EciParms.eci_call_type = ECI_SYNC; memcpy(&EciParms.eci_program_name, "SERV0001", 8); memcpy(&EciParms.eci_userid, "CICSUSER", 8); memcpy(&EciParms.eci_password, "CICSUSER", 8); memcpy(&EciParms.eci_system_name, "CICSRG01", 8); EciParms.eci_commarea = commArea; EciParms.eci_commarea_length = sizeof(commArea); EciParms.eci_extend_mode = ECI_NO_EXTEND; EciParms.eci_luw_token = ECI_LUW_NEW; EciParms.eci_timeout = 0; memcpy(EciParms.tpn_name, "BPMI", 4); Rc= CICS_ExternalCall (&EciParms);
ECI Client程序示例 (Java语言) byte[] abytCommarea = new byte[iCommareaSize]; javaGatewayObject = new JavaGateway(“local:”, 0); //local gateway //javaGatewayObject = new JavaGateway(“tcp://localhost”, 2006); //remote gateway String strServer = "CICS01"; //strServer= “tcp://9.181.108.101:1436”; //Use IPIC ECIRequest requestObject = new ECIRequest(ECIRequest.ECI_SYNC, strServer, "TEST", "TEST", strProgram, null, abytCommarea, iCommareaSize, ECIRequest.ECI_NO_EXTEND, 0); int iRc = javaGatewayObject.flow(requestObject); if(requestObject.getCicsRc() == ECIRequest.ECI_NO_ERROR) System.out.print(Integer.toHexString(abytCommarea[i])); javaGatewayObject.close();
ECI函数调用 • CICS_ExternalCall • cics_sshort_t CICSCALL CICS_ExternalCall(ECI_PARMS CICSPTR *EciParms); • 实现了ECI的大部分功能 • 只有一个参数,称为ECI参数模块(ECI parameter block) • 该模块描述了ECI调用实现的功能及输入输出的数据 • CICS_EciListSystems • 获得Client定义的可连接的Server名称及描述
ECI CICS_ExternalCall调用分类 CICS_ExternalCall 通过设置ECI参数模块中的eci_call_type栏位来控制调用类型。 • 程序执行调用(Program link calls)请求执行Server程序 • 同步调用 • 异步调用(异步调用后必须使用回复信息查询调用获得结果) • 状态查询调用(Status information calls)查询Server属性及状态信息 • 同步调用 • 异步调用 • 回复查询调用(Reply solicitation calls)获得异步调用的结果 • 获得任何类型的异步调用结果 • 获得指定异步调用的返回结果(eci_message_qualifier)
ECI CICS_ExternalCall参数设置 • eci_system_name CICS Server名称 • Region Name ( RPC Client ) • Client定义的Server Instance 名称 ( Universal Client ) • eci_userid • eci_password • eci_commarea 通讯数据区(线性缓冲区) • 调用前存放将要传至Server的数据 • 调用返回后,其中存放Server传回的数据 • eci_commarea_length 数据区的长度 • 该值应设为上传和返回数据长度两者中的较大值 • 若上传实际数据长度小于该值,数据后的空间应以NULL字符填充 • eci_call_type 调用类型
程序执行调用(Program link calls) • eci_program_name请求执行的Server程序名 • 同步调用eci_call_type = ECI_SYNC • 异步调用eci_call_type = ECI_ASYNC • eci_message_qualifier = xxxx (可选)标示每一个异步调用,回复查询调用时使用 , 以便获得特定的调用返回结果 • eci_callback回调函数
逻辑工作单元( Logical Unit of Work ) 的管理 • LUW可以由唯一一个程序执行调用构成,或通过扩展(Extend)调用由多个顺序执行的程序调用构成 • eci_luw_token栏位来标识LUW • eci_luw_token取值由ECI自动生成 • LUW中的第一个程序调用时 , eci_luw_token应设为ECI_LUW_NEW,该调用返回后,eci_luw_token中即保存了ECI生成的数值 • 该LUW中后续程序调用的eci_luw_token应保持该值不变 • eci_extend_mode栏位LUW是否扩展、提交或回滚 • ECI_NO_EXTEND • ECI_EXTENDED • ECI_COMMIT(不能和eci_program_name栏位同时设置) • ECI_BACKOUT (不能和eci_program_name栏位同时设置)
状态查询调用(Status information calls) • ECI状态模块 • 状态信息存放在ECI状态模块(ECI status block) 中 • 状态模块的输入输出通过eci_commarea栏位完成 • ECI中包括如下信息: • 连接类型(连接到Server、Client 或Nothing) • Server状态(available, unavailable, or unknown) • Client状态(available, not applicable, or unknown) • 状态查询调用可以完成的功能 • 请查询当前状态 • 检测状态变化 • 取消状态检测
如何请查询当前状态 • eci_commarea 指向ECI状态模块的指针,返回结果存放其中 • eci_commarea_length = ECI_STATUS_LENGTH • eci_extend_mode = ECI_STATE_IMMEDIATE • 同步调用eci_call_type = ECI_STATE_SYNC • 异步调用 • eci_call_type = ECI_STATE_ASYNC • eci_message_qualifier = xxxx (可选) • 标示每一个异步调用 • 回复查询调用时使用 , 以便获得特定的调用返回结果
如何检测状态变化 • 为ECI指定一个特定的状态, • 一旦实际状态与指定状态不符, 将得到ECI提示 • 只能是异步调用 • eci_commarea 指向ECI状态模块的指针,返回结果存放其中 • eci_commarea_length = ECI_STATUS_LENGTH • eci_extend_mode = ECI_STATE_CHANGED • eci_call_type = ECI_STATE_ASYNC • eci_message_qualifier = xxxx (可选) • 标示每一个异步调用 • 回复查询调用时使用 , 以便获得特定的调用返回结果 • eci_luw_token = ECI_LUW_NEW调用返回后, 该栏位存放一个有ECI生成的值, 标示该检测用于取消检测时,指定操作对象
如何取消状态检测 • 取消一个状态检测请求 • eci_commarea = NULL • eci_commarea_length = 0 • eci_extend_mode = ECI_STATE_CANCEL • eci_call_type = ECI_STATE_SYNC • eci_luw_token 请求检测状态调用该栏位的返回值
回复查询调用(Reply solicitation calls) • 获得异步调用的返回结果 • 回复查询调用分为如下类型: • ECI_GET_REPLY获得任何异步调用的返回结果 ,若无回应,立即返回 • ECI_GET_REPLY_WAIT获得任何异步调用的返回结果 ,若无回应,等待 • ECI_GET_SPECIFIC_REPLY获得指定异步调用的返回结果,若无回应,立即返回 • ECI_GET_SPECIFIC_REPLY_WAIT获得指定异步调用的返回结果,若无回应,等待
使用ECI_GET_REPLY或ECI_GET_REPLY_WAIT • eci_call_type • ECI_GET_REPLY • ECI_GET_REPLY_WAIT • eci_commarea • 若取得程序执行调用的回复,其中存放Server返回的数据 • 若取得状态查询调用的回复,其中存放ECI状态模块 • eci_commarea_length相应COMMAREA的长度
使用ECI_GET_SPECIFIC_REPLY或ECI_GET_SPECIFIC_REPLY_WAIT • eci_call_type • ECI_GET_SPECIFIC_REPLY • ECI_GET_SPECIFIC_REPLY_WAIT • eci_message_qualifier设为相应异步调用该栏位的返回值 • eci_commarea • 若取得程序执行调用的回复,其中存放Server返回的数据 • 若取得状态查询调用的回复,其中存放ECI状态模块 • eci_commarea_length相应COMMAREA的长度
EPI程序的常用函数 • 环境设置 • CICS_EpiInitialize • CICS_EpiDelTerminal • 调用服务 • CICS_EpiStartTran • 收发数据 • CICS_EpiGetEvent • CICS_EpiReply
CTG/CUC的C程序的编译链接 宏定义:-DCICS_W32, -DCICS_AIX, -DCICS_SOL, -DCICS_HPUX, -DCICS_SCO 库: cclwin32.lib, -lcclaix, -lcclsol, -lcclhpux, -lcclsco 对UNIX,一般要加上-lpthread WIN32: cl /c /DCICS_W32 /DWIN32 /D_WIN32 /D_X86_=1 prg.c link prg.obj cclwin32.lib AIX: cc_r -c -DCICS_AIX -I/usr/lpp/ctg/include prg.c cc_r -o prg prg.o -lpthreads -lc_r -lcclaix Solaris: cc_r -c -DCICS_SOL -I/opt/ctg/include prg.c cc_r -o prg prg.o -lcclsol -lpthread HP-UX: cc_r -c -DCICS_HPUX -I/opt/ctg/include prg.c cc_r -o prg prg.o -lcclhpux -lpthread SCOUNIX: cc_r -c -DCICS_SCO -I/opt/K/SCO/cics/include prg.c cc_r -dy -o prg prg.o –lcclsco • 注:RPC Client使用宏定义:-DSELECT,库使用:-lcicsecico -lcicsepico
编写CICS Client程序的注意事项 • 对C语言的程序,注意CUC/CTG与RPC Client使用不同的头文件和库,以及编译选项。注意混用CUC/CTG与RPC Client的头文件和库后可以造成各种错误。 • 推荐尽量选择CUC/CTG,因为CUC/CTG 更稳定,而且在TXSeries v6以后, RPC Client被淘汰。
实现ECI用户出口程序的步骤 • CICS 客户机端 ECI 用户出口使用 • 编写用户出口,实现 cicsecix.dll (cicsecix.c); • 拷贝至 客户端应用程序的可执行文件目录中(…\bin); • 启动客户端程序
编写用户出口程序的规则和指导 • 不允许在程序中使用 ECI 和 EPI调用; • 应当避免在出口程序中,避免有等待或长时间运行的代码; • 不能作为一个 RPC服务器来登记; • 应参照编写DCE应用程序指南的多线程处理建议来执行; • 出口调用参数应按照如下分类处理:参数分为输入、输出、输入输出类型; • 输入参数在出口程序中,只能被查看,不能被修改; • 输出参数在出口程序中,不能被查看,且必须在其中存储一个值; • 输入输出参数在出口程序中,既能被查看,又能在其中存储一个值。
使用Channel & Container的应用示例 String cicsServ= "tcp://host1:1436“, channelName= "CHANNEL1“, programlName= "CC0"; Channel reqChannel, respChannel; gateway = new JavaGateway("local:", 2006); reqChannel = new Channel(channelName); reqChannel.createContainer("CONTAINER1", "Hello CICS".getBytes()); ECIRequest eciReq= new ECIRequest( ECIRequest.ECI_SYNC, //ECI call type cicsServ, //CICS server null, //CICS username null, //CICS password programlName, //Program to run null, //Transaction to run reqChannel, //Channel ECIRequest.ECI_NO_EXTEND, //ECI extend mode 0 //ECI LUW token ); gateway.flow(eciReq); cicsRc = eciReq.getRc(); if (eciReq.hasChannel()) respChannel = eciReq.getChannel(); System.out.println( "BIT Data = " + new String( cont.getBITData()) );
C语言的remote client示例 (ECI v2) rc = openGatewayConnection(&gatewayToken, hostname, port, connTimeout); memset(&eciParms, 0, sizeof(CTG_ECI_PARMS)); memset(commarea, 0, COMMAREA_SIZE); eciParms.eci_version = ECI_VERSION_2; eciParms.eci_call_type = ECI_SYNC; eciParms.eci_commarea = commarea; eciParms.eci_commarea_length = COMMAREA_SIZE; eciParms.commarea_outbound_length = 0; eciParms.commarea_inbound_length = 0; eciParms.eci_extend_mode = ECI_NO_EXTEND; eciParms.eci_luw_token = ECI_LUW_NEW; eciParms.eci_timeout = 0; memcpy(&eciParms.eci_program_name, program, strlen(program)); memcpy(&eciParms.eci_system_name, serverName, strlen(serverName)); memcpy(&eciParms.eci_transid, transId, strlen(transId)); memcpy(&eciParms.eci_tpn, tpn, strlen(tpn)); memcpy(&eciParms.eci_userid, userId, strlen(userId)); memcpy(&eciParms.eci_password, passWd, strlen(passWd)); rc = CTG_ECI_Execute(gatewayToken, &eciParms); if (rc == CTG_OK) printf("\nProgram %s returned with data: %s\n\n", program, commarea); closeGatewayConnection(&gatewayToken);
C#的ECI程序示例 using (GatewayConnection gwyConnection = new GatewayConnection(gwyHostName, gwyPort)) { eciReq = new EciRequest(); eciReq.ServerName = cicsServer; eciReq.Program = ProgramName; eciReq.ExtendMode = EciExtendMode.EciNoExtend; eciReq.SetCommareaData(new byte[CommareaLength]); gwyConnection.Flow(eciReq); byte[] commarea = eciReq.GetCommareaData(); }
Server 程序框架- C int main(){ unsigned long respCode; char *commArea; EXEC CICS ADDRESS EIB(dfheiptr) RESP(respCode); if (respCode != DFHRESP(NORMAL)) { fprintf(stderr, "Error occurred addressing commarea, rc = %d\n", respCode); EXEC CICS RETURN; } EXEC CICS ADDRESS COMMAREA(commArea) RESP(respCode); if (respCode != DFHRESP(NORMAL)) { fprintf(stderr, "Error occurred addressing commarea, rc = %d\n", respCode); EXEC CICS RETURN; } ... EXEC SQL ... ... EXEC CICS SYNCPOINT RESP(respCode); if (respCode != DFHRESP(NORMAL)) { …; EXEC CICS RETURN; } EXEC CICS RETURN; }
Server 程序框架- COBOL IDENTIFICATION DIVISION. PROGRAM-ID. xxx. DATA DIVISION. WORKING-STORAGE SECTION. ... ... LINKAGE SECTION. 01 DFHCOMMAREA. ... ... PROCEDURE DIVISION. ... ... EXEC CICS ... END-EXEC. ... ... EXEC CICS RETURN END-EXEC. EXIT.
编译CICS程序 • 数 据 库 预 编 译 • db2 prep -- db2 • proc -- Oracle • cpre -- Sybase • CICS预编译cicstran -lC server.ccs • C编译/连接 • xlc_r4/xlc_r, cc_r • cl • 预编译 + C编译/连接cicstcl -lC server.ccs
程序与交易 • 程序 • 完成一定功能的代码段 • 交易 • CICS程序运行的特定环境 • 本身无实际的代码 • 第一个程序(First Program),链接其他程序
LINK PROGAM (B) Program A XCTL PROGAM (E) Program D RETURN Program E Call C LINK PROGAM (D) Program B GOBACK Program C CICS程序的Logical Levels Level 0 CICS Level 1 Level 2 Level 3
CICS API • 提供CICS 服务,由服务器端程序调用 • 分类 • 逻辑控制 • 数据及存储服务 • 时间服务 • 程序跟踪 • APPC 通讯 • ... • 通过CICS API 调用- EXEC CICS ...
Error Handling • Default Actions • COBOL: Most error conditions will abend the task. • If the error is a 'busy' condition, CICS will wait the task. • Some conditions will be ignored. • RESP • respond code • Code the RESP option and CICS will return the condition value. • test respond code after invoke a commandif respcode = DFHRESP(NORMAL) then ...... • use of RESP implies NOHANDLE • HANDLE CONDITION • COBOL & PL/I only. • Identify a routine (label) to handle selected conditions. • Also: NOHANDLE and IGNORE CONDITION.
通用的CICS API选项(1) • RESP • Command response (return code) • RESP2 • Extended response fields (INQ/SET) • Applies to INQUIRE and SET commands only • NOHANDLE • Ignore 'handle condition' • Implicitly for C or C++ languages • NOEDF • Ignore execution diagnostic facility (CEDF)
通用的CICS API选项(2) • LENGTH • Optional for COBOL and PL/I • Must specify for data area in C/C++except on the SEND MAP, RECEIVE MAP, READ, READNEXT, READPREV, REWRITE, WRITE, DEQ and ENQ commands • A signed 16-bit binary value (Max 32767) • FLENGTH • Same as LENGTH • full word or 32-bit binary value (But Max 2G) • INTO and SETWhen receive data for CICS • INTO : AP provides a suitable buffer to hold data for CICS • SET : CICS Allocate a suitably sized buffer for data. CICS may reuse the buffers at a later time
接口参数块-EIB • EIB - EXEC Interface Block • 常用内容 • EIBCALEN - 传输区长度 • EIBDATE,EIBTIME - 程序启动时间 • EIBREQID - 请求编号 • EIBRESP - 回应代码 • EIBRESP2 - 详细回应代码 • EIBTASKN - 任务编号 • EIBTRNID- 交易名称 • 一些可通过CICS API 获得
交易内数据共享 • 使用COMMAREA - LINK 或XTCL • EXEC CICS LINK... COMMAREA() • EXEC CICS XCTL... COMMAREA() • 使用CICS 私有存储区 • EXEC CICS GETMAIN SET() • TWA - Transaction Work Area • 同一交易内所有程序共享 • TD中定义大小 • TWASize (Transaction Work Area Size) • 范围0 - 32767 Bytes • EXEC CICS ADDRESS TWA() • 程序自身数据段( 如COBOL CALL) • CALL USING...