cics 教程1

来源:百度文库 编辑:神马文学网 时间:2024/05/23 13:53:27
概 述
计算机体系结构经历了从主机集中的终端方式、C/S结构,以及现在越来越普遍的三层客户机服务器结构。在当今中国,从银行、电信,到保险、证券的各个行业,还有不容忽视的电子商务、普遍运算,都越来越多地使用三层结构作为核心系统的标准体系结构。但是,由于三层结构提高了开发的起点,加上具体介绍三层次应用开发的书籍并不象介绍C/S的书脊那样普遍,对于大多数开发人员来说,三层结构依然是一种理想,而不是一个能够立即在现实中使用的方法。甚至,由于缺乏对于工具的了解,有不少开发人员自行开发了简易的中间件来满足其对三层结构的需求。正因为此,给三层结构开发的普及带来了很大的障碍。
本书详细介绍了三层客户机服务器结构的系统结构,从计算机体系结构的变迁,三层结构的优点,一些常见概念,如数据的一致性、两阶段提交、分布式事务处理、事务处理器以及XA规范的系统说明,到CICS是如何构造以成为一个优秀的三层结构中间件,在第一章中都有详细阐述。
如果您对于三层结构的理论已经有所了解,可以在第二章中学习如何使用CICS编制应用,并且使用VB、Delphi、C++ Builder、PowerBuilder、Java和C进行前台界面的开发。如果要进一步使用CICS的底层功能,第四章的内容是非常有用的。
在CICS应用服务器端,采用嵌入式SQL(E-SQL)编程和各种数据库进行连接。第六章同时详细介绍了DB2、SYBASE、ORACLE、INFORMIX等数据库的嵌入式SQL编程,即使您不使用CICS,这也是一个很好的参考。
第五章中,介绍了对CICS进行性能调优的方法以及一些参考数据,您可以根据您的系统需求来选择合适的硬件环境,满足对性能的需求。
特别的,本书所附光盘包含使用CICS在Windows NT平台上搭建三层结构的所有软件,以及本书提及的所有示例程序。根据第四章的步骤,您可以自己建立一个实验环境,亲自体验开发三层结构应用的感觉。
第二章 编程
我经常听一些人大谈把两层C/S结构的应用转为三层C/S结构的应用,无论说的,还是听的,都兴高采烈,频
频点头:好,好!转吧。不过,具体怎么“转”呢?是不是把两层C/S结构的程序放到什么容器里“煮”一下,再取
出来就可以“吃”了?当然不行,看来一个“转”字还颇有点儿学问。如果您原来靠游泳过河,那我教您一种划船过
河的方法,这条船就是中间件CICS——当然您不能靠划船的经验来驱动它,CICS需要的是——编程。学划船很
简单,学CICS编程也一样简单,读了本章的内容就会知道。
如果读者想用COBOL或JAVA来开发CICS的服务程序,请参阅CICS的其它技术资料,这里只提供了C语言的例
子。不过,这里提供了几乎所有常用的前端开发工具作为CICS客户的例子,也许这正是您所需要的,那么,请
认真阅读后面的内容。
如果您已经有足够多的预备知识,可以先阅读下一章,在建好一个实验环境后,再回到本章。
第一节 建立一个简单的CICS应用
1.1 您的第一个CICS程序:GETTIME
我们将要看到的这个CICS程序基本没有用到CICS强大的事务处理监控能力,所以更象是一个两层C/S的应
用。但是因为它如此简单,我还是把它做为您学习CICS的入门程序。
做过UNIX或NT的服务程序(UNIX经常叫DAEMON程序)朋友,会发现CICS服务程序非常容易实现,因为您不必
去处理Socket、Named Pipe或FIFO之类的东西。是的,如果不考虑价格因素,用CICS去实现许多一般的服务程
序可是个省事的好办法。
设想某公司要投资开发一个叫GETTIME的服务程序,其功能是公布服务器的时间,供他们的各种前端客户程
序使用。这些程序必须能运行于各种常用的UNIX平台和WINDOWS NT,甚至可以移植到AS400和IBM大型机
上。正在公司的编程高手们纷纷摩拳擦掌,准备大干一场时,一个初级的CICS程序员突然宣布他已在5分钟内完
成了任务,并将得到一笔可观的报酬——有这种好事吗?那我们不妨就来看看GETTIME的CICS解决方案。
这是C语言作的CICS服务程序的清单(注意,这个源程序可以不加修改的运行在支持CICS的各种操作系统平台
上):
#include
#include "easycics.h"
void main(){
struct tm *newtime;
time_t aclock;
if( InitEasyCics() ) ExitEasyCics(); /* [A] */
BeginWrite(); /* [B] */
time( &aclock );
newtime= localtime( &aclock );
SetValue( "TIME", asctime(newtime) ); /* [C] */
ExitEasyCics(); /* [D] */
}
清单 2-1-1 (gettime.ccs)
客户程序更加简单,下面是一些例子:
1、ANSI C的客户程序见清单2-1-2:
#include "ec.h"
void main(){
char s[200];
ConnectServer( "CICSNT01", "TEST", "TEST" ); /* [A] */
CallProgramAndCommit("GETTIME"); /* [B] */
GetValue( "TIME", s ); /* [C] */
puts(s);
}
清单 2-1-2
以下是运行结果:
D:\cics>gettime
Thu Jan 27 17:35:14 2000
清单 2-1-3
2、使用OLE可以支持Windows上的各种开发工具,例如:Visual C,Visual Basic,Power Builder,Delphi,
C++Builder,Lotus Notes,Internet Explorer等。下面是Visual Basic的例子(PowerBuilder和Delphi的客户程序几
乎可以照搬这段代码):
Sub main()
Dim oEc As Object
Dim r%
Set oEc = CreateObject("EasyCics.App") ‘[A]
r = oEc.ConnectServer("CICSNT01", "TEST", "TEST") ‘[B]
oEc.CallProgramAndCommit "GETTIME" ‘[C]
MsgBox oEc.GetValue("TIME") ‘[D]
End Sub
清单 2-1-4
以下是运行结果:
图 2-1-1
3、如果使用JAVA,可以无须重新编译地移植您的程序。下面是JAVA的例子:
import easycics.*;
public class GetTime{
static public void main( String astrArg[] ){
try{
App oEc = new easycics.App(); //[A]
oEc.ConnectServer("CICSNT01", "TEST", "TEST"); //[B]
oEc.CallProgramAndCommit("GETTIME"); //[C]
System.out.println(oEc.GetValue("TIME")); //[D]
}
catch(ServerErrorException se){ //[E]
System.out.println(se.getMessage());
System.out.println(se.getErrorCode());
}
}
}
清单 2-1-6
以下是运行结果:
D:\cics>java GetTime
Sat Jan 29 21:22:16 2000
清单 2-1-7
我还能罗列出一大堆编程工具访问CICS的源码,是的,它们非常类似。您可能注意到了GetValue、SetValue、
ConnectServer、CallProgramAndCommit,是的,记住这些就差不多了,常用的调用很少,使用CICS确实非常
简单。
因为所以高梁玉米蟋蟀蚂蚁 ..... 在这个城市里,一个人,会不会孤单碰见你,两个人,会不会比较不孤单
我们先来分析一下服务程序,就是清单2-1-1展示的C程序。这个程序采用的接口方法叫做EasyCICS,所以我们引入了“easycics.h”头文件,上面列举的那些函数都是EasyCICS的函数。
InitEasyCics函数的作用是初始化环境,如果返回值非零,表示初始化失败。ExitEasyCics函数的作用是退出CICS服务程序,并把返回信息传给客户程序。注意,任何情况下退出CICS服务程序,必须调用ExitEasyCics函数,或与其相当的CICS API,不能使用操作系统调用exit或_exit等。程序在[A]处的意思是,如果初始化失败,就退出CICS服务程序。
程序在[B]处调用了BeginWrite函数,表示开始写通信用的公共数据区,它的真正作用是清除该公共数据区。
程序在[C]处调用了SetValue函数,其作用是把一个字符串作为值赋予一个关键字(也是一个字符串),并存储在公共数据区。在这里,”TIME”是关键字,日期和时间字符串(由asctime函数获得)是值。这样做的意义何在?我们可以把很多值赋予不同的关键字,只要根据关键字就可以取出这些值。于是,客户机和服务器就可以利用这种方法进行通信。
程序在[D]处调用了ExitEasyCics函数,任何情况下退出CICS服务程序,必须调用该函数。
只有C源程序还不够,我们还需要把它编译成执行文件或库文件(在Windows NT系统,CICS服务程序最终要被编译成为.DLL文件,即动态连接库)。一些程序员习惯于使用集成编译工具,但无法使用在UNIX等操作系统。我们采用更加通用的makefile方式进行编译。以下是在NT系统中,编译GETTIME服务程序的makefile(在各种UNIX系统,要进行必要的修改):
gettime.dll: gettime.ccs
set USERLIB=easycics.obj
cicstcl -e -d -lC gettime.ccs
清单 2-1-8
如果您使用的是CICS for Windows NT,您可以使用图形界面把编译好的程序(gettime.dll)加入CICS域(region)。请参照如下插图:
图 2-1-2 (选择管理界面程序)
图 2-1-3 (在CICS域中选择program资源设置)
图 2-1-4 (program资源设置)
图 2-1- 5(program资源设置)
当然,也可以使用如下指令(注意大小写):
cicsadd -c pd -r CICS域名 你的程序名(GETTIME) PathName=路径 RSLKey=public
再看看ANSI C的客户程序,就是清单2-1-2展示的C程序。这个程序采用的接口方法也是EasyCICS,所以我们引入了“ec.h”头文件(注意服务程序使用的是叫做“easycics.h”的头文件)。
程序在[A]处执行了ConnectServer函数。该函数的第一个参数是CICS的系统名称,相当于CICS域(Region)的连接字符串;函数的后两个参数分别是CICS的用户名称和口令。
程序在[B]处执行了CallProgramAndCommit函数,我们一般使用此函数来调用服务程序(Program)。该函数的唯一参数就是要调用的CICS的服务程序名称,在此处,即GETTIME程序。
程序在[C]处执行了GetValue函数,此函数通过其参数指定的关键字来获取服务器方面通过SetValue函数来设置的字符串值。注意,可以通过多个SetValue和GetValue函数来传递多个字符串值。另外,如果客户机方面调用SetValue函数,而服务器方面调用GetValue函数也完全可以。SetValue和GetValue函数对是EasyCICS传递值的标准方法之一。
这个客户程序的makefile如下:
all: gettime.exe
gettime.exe: gettime.obj
link gettime.obj ec.obj cclwin32.lib
gettime.obj: gettime.c
cl -c gettime.c
清单 2-1-9
再看看使用Visual Basic的客户程序,就是清单2-1-4展示的程序。这个程序采用EasyCICS组件。使用面向对象的术语,我们将反复提到组件的“方法”,或接口的“方法”,而不能说组件或接口的函数。
程序在[A]处调用了VB的函数CreateObject创建了连接EasyCICS的对象。
程序在[B]处执行了组件的ConnectServer方法。该方法的第一个参数是CICS的系统名称,相当于CICS域(Region)的连接字符串;函数的后两个参数分别是CICS的用户名称和口令。
程序在[C]处执行了组件的CallProgramAndCommit方法,我们一般使用此函数来调用服务程序(Program)。该函数的唯一参数就是要调用的CICS的服务程序名称,在此处,即GETTIME程序。
程序在[D]处执行了组件的GetValue方法,此函数通过其参数指定的关键字来获取服务器方面通过SetValue函数来设置的字符串值。注意,可以通过多个SetValue和GetValue函数来传递多个字符串值。另外,如果客户机方面调用SetValue函数,而服务器方面调用GetValue函数也完全可以。SetValue和GetValue函数对是EasyCICS传递值的标准方法之一。
Visual Basic不需要makefile之类的东西,可见使用组件是多么的简单。我们在PowerBuilder和Delphi中,都是通过组件访问CICS。
最后,我们研究一下JAVA的例子。JAVA通过GateWay来访问CICS Client,我们也可以采用EasyCICS,所以,我们首先引入了easycics.*,这为我们访问CICS Client奠定了基础。
程序在[A]处创建了easycics.App的类实例对象。
程序在[B]处执行了类的ConnectServer方法。该方法的第一个参数是CICS的系统名称,相当于CICS域(Region)的连接字符串;函数的后两个参数分别是CICS的用户名称和口令。
程序在[C]处执行了类的CallProgramAndCommit方法,我们一般使用此函数来调用服务程序(Program)。该函数的唯一参数就是要调用的CICS的服务程序名称,在此处,即GETTIME程序。
程序在[D]处执行了类的GetValue方法,此函数通过其参数指定的关键字来获取服务器方面通过SetValue函数来设置的字符串值。注意,可以通过多个SetValue和GetValue函数来传递多个字符串值。另外,如果客户机方面调用SetValue函数,而服务器方面调用GetValue函数也完全可以。SetValue和GetValue函数对是EasyCICS传递值的标准方法之一。
JAVA也不需要makefile之类的东西,而且可以不用重新编译,就移植到各种操作系统平台上。
因为所以高梁玉米蟋蟀蚂蚁 ..... 在这个城市里,一个人,会不会孤单碰见你,两个人,会不会比较不孤单
1.2 EasyCICS的标准示例:TELECOM
也许您对对上面介绍的示例程序GETTIME不以为然,因为它太简单了。那么,下面将介绍另一个示例程序TELECOM,一个同样简单但功能健全的标准示例程序。您可以通过这个程序,清晰地掌握CICS实现三层C/S结构的机制。
之所以我把这个程序称为EasyCICS的标准示例,是因为所有编程工具的EasyCICS演示程序都有这个称为TELECOM的例子。那么,这个例子实现什么功能?TELECOM的客户程序向服务程序提供一个移动电话设备号码,服务程序根据这个号码查出相关的计费单据后返回给客户程序,客户程序立即显示此单据。整个过程都是在线同步执行,这也是一个OLTP的典型例子。
以下是C语言作的CICS服务程序的清单(注意,这个源程序可以不加修改的运行在支持CICS的各种操作系统平台上):
/*****************************************************************************/
/*-------------------------- HEADER FILES -----------------------------------*/
#include "easycics.h"
/*****************************************************************************/
/*------------------------------ DEFINES ------------------------------------*/
#ifdef _WIN32
#define DLLIMPORT __declspec(dllimport)
#define DLLEXPORT __declspec(dllexport)
#define CDECL __cdecl
#else
#define DLLIMPORT
#define DLLEXPORT
#define CDECL
#endif
/* #define either ORA or DB2 here */
#define DB2
#define SQLNOTFOUND 100
#if defined ( DB2 )
#include
#elif defined ( ORA )
#define SQLNOTFOUND 1403
#endif
/*****************************************************************************/
/*--------------------------- Global Variables ------------------------------*/
EXEC SQL INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
char Usr_name[61];
char Dev_no[9];
long Call_flg;
char Called_arno[11];
char Called_no[15];
char Call_dat[21];
double Call_dur;
double Call_rate;
double Call_fee;
double Add_fee;
char as_dev_no[9];
EXEC SQL END DECLARE SECTION;
/*****************************************************************************/
/*Functions*/
/*****************************************************************************/
/*
*/
void GetValueNum(char *Key, char *Value, int Num){
char s[4096];
GetValue( Key, s );
strncpy(Value,s,Num);
Value[Num-1] = '\0';
}
/*
*/
void main(){
char statusbuf[1024], s[30];
if( InitEasyCics() ) ExitEasyCics();
/*Read:*/
GetValueNum( "NO", as_dev_no, sizeof(as_dev_no) );
/*Write:*/
BeginWrite();
SetValue( "VER", "Telecom 1.0");
RsCreate(10);
RsSetColNameList("Usr_name,Dev_no,Call_flg,Called_arno,Called_no,
Call_dat,Call_dur,Call_rate,Call_fee,Add_fee"); /*可省略*/
EXEC SQL DECLARE c1 CURSOR FOR
SELECT bas_infot.Usr_name, auto10a_list.Dev_no, auto10a_list.Call_flg,
auto10a_list.Called_arno, auto10a_list.Called_no, auto10a_list.Call_dat,
auto10a_list.Call_dur, auto10a_list.Call_rate, auto10a_list.Call_fee,
auto10a_list.Add_fee FROM auto10a_list, bas_infot
WHERE ( auto10a_list.Dev_no = bas_infot.Dev_no )
AND auto10a_list.Dev_no = :as_dev_no;
sprintf(statusbuf,"declear cursor code=%d\n", sqlca.sqlcode);
PrintStatus(statusbuf);
EXEC SQL OPEN c1;
sprintf(statusbuf,"open cursor code=%d\n", sqlca.sqlcode);
PrintStatus(statusbuf);
do{
EXEC SQL FETCH c1 INTO
:Usr_name, :Dev_no, :Call_flg, :Called_arno, :Called_no, :Call_dat,
:Call_dur, :Call_rate, :Call_fee, :Add_fee;
sprintf(statusbuf,"fetch code=%d\n", sqlca.sqlcode);
PrintStatus(statusbuf);
if( (sqlca.sqlcode == SQLNOTFOUND) || (sqlca.sqlcode <0) )
break;
else
RsAddRow();
sprintf( statusbuf, "%s,%s,%d,%s,%s,%s,%7.0f,%8.3f,%7.2f,%6.2f\n"
, Usr_name, Dev_no, Call_flg, Called_arno, Called_no, Call_dat
, Call_dur, Call_rate, Call_fee, Add_fee );
PrintStatus(statusbuf);
RsSetCol( 1, Usr_name );
RsSetCol( 2, Dev_no );
sprintf( s, "%lu", Call_flg );
RsSetCol( 3, s );
RsSetCol( 4, Called_arno );
RsSetCol( 5, Called_no );
RsSetCol( 6, Call_dat );
sprintf( s, "%6.2f", Call_dur );
RsSetCol( 7, s );
sprintf( s, "%6.2f", Call_rate );
RsSetCol( 8, s );
sprintf( s, "%6.2f", Call_fee );
RsSetCol( 9, s );
sprintf( s, "%6.2f", Add_fee );
RsSetCol( 10, s );
RsSaveRow();
}while(1);
EXEC SQL CLOSE c1;
/*#ifdef( SYBASE )
EXEC SQL DEALLOCATE CURSOR c1;
#endif*/
sprintf(statusbuf,"close cursor code=%d\n", sqlca.sqlcode);
PrintStatus(statusbuf);
ExitEasyCics();
}
清单 2-1-10 (telecom.sqc)
这是个典型的E-SQL程序(在ORACLE中叫PROC),如果您不熟悉E-SQL编程,不用着急,本书有详细的说明。由于后面的内容有对本程序的详细分析,这里仅简要说明一下程序的流程。
如果不特别注重程序的移植性、健壮性和调试信息,可以把清单2-1-10的程序简化成下面的程序:
#include "easycics.h"
#include
#define SQLNOTFOUND 100
EXEC SQL INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
char Usr_name[61];
char Dev_no[9];
long Call_flg;
char Called_arno[11];
char Called_no[15];
char Call_dat[21];
double Call_dur;
double Call_rate;
double Call_fee;
double Add_fee;
char as_dev_no[9];
EXEC SQL END DECLARE SECTION;
/*
*/
void main(){
char s[30];
if( InitEasyCics() ) ExitEasyCics();
/*Read:*/
GetValue ( "NO", as_dev_no );
/*Write:*/
BeginWrite();
RsCreate(10);
RsSetColNameList("Usr_name,Dev_no,Call_flg,Called_arno,Called_no,
Call_dat,Call_dur,Call_rate,Call_fee,Add_fee"); /*可省略*/
EXEC SQL DECLARE c1 CURSOR FOR
SELECT bas_infot.Usr_name, auto10a_list.Dev_no, auto10a_list.Call_flg,
auto10a_list.Called_arno, auto10a_list.Called_no, auto10a_list.Call_dat,
auto10a_list.Call_dur, auto10a_list.Call_rate, auto10a_list.Call_fee,
auto10a_list.Add_fee FROM auto10a_list, bas_infot
WHERE ( auto10a_list.Dev_no = bas_infot.Dev_no )
AND auto10a_list.Dev_no = :as_dev_no;
EXEC SQL OPEN c1;
do{
EXEC SQL FETCH c1 INTO
:Usr_name, :Dev_no, :Call_flg, :Called_arno, :Called_no, :Call_dat,
:Call_dur, :Call_rate, :Call_fee, :Add_fee;
if( (sqlca.sqlcode == SQLNOTFOUND) || (sqlca.sqlcode <0) )
break;
else
RsAddRow();
RsSetCol( 1, Usr_name );
RsSetCol( 2, Dev_no );
sprintf( s, "%lu", Call_flg );
RsSetCol( 3, s );
RsSetCol( 4, Called_arno );
RsSetCol( 5, Called_no );
RsSetCol( 6, Call_dat );
sprintf( s, "%6.2f", Call_dur );
RsSetCol( 7, s );
sprintf( s, "%6.2f", Call_rate );
RsSetCol( 8, s );
sprintf( s, "%6.2f", Call_fee );
RsSetCol( 9, s );
sprintf( s, "%6.2f", Add_fee );
RsSetCol( 10, s );
RsSaveRow();
}while(1);
EXEC SQL CLOSE c1;
ExitEasyCics();
}
清单 2-1-11 (简化telecom.sqc)
清单2-1-11所示的程序可以用于CICS for NT,访问DB2数据库。我们来简单分析一下简化的telecom.sqc程序:
这个程序采用的接口方法是EasyCICS,所以引入了“easycics.h”头文件。
程序的开始声明了一些宿主变量(在EXEC SQL BEGIN DECLARE SECTION;和EXEC SQL END DECLARE SECTION;之间),所谓“宿主变量”即可以同时用于C语言变量和SQL变量。注意,以EXEC SQL打头的语句都可以通过数据库的预编译程序转化成相应的C语言代码。
在执行部分,程序首先调用InitEasyCics函数来初始化环境。接着调用GetValue函数,此函数通过其参数指定的关键字“NO”来获取客户机方面通过SetValue函数来设置的字符串值。再调用了BeginWrite函数,表示开始写通信用的公共数据区,它的真正作用是清除该公共数据区。
接着调用了几个以“Rs”为字头的函数,表示要设置结果集(ResultSet)。函数RsCreate表示要创建结果集,其参数是结果集的列数。函数RsSetColNameList设置结果集各列的名称,如果客户机仅通过相对位置来获取各列的值(这样效率更高),则可以省略此调用。
接着程序声明并打开SQL游标,并在一个循环中不断获取数值存入宿主变量,直到游标最后结束(sqlca.sqlcode==SQLNOTFOUND)或出错(sqlca.sqlcode <0)。注意每从数据库取出一行,调用RsAddRow函数使EasyCICS的结果集增加一行。
取到宿主变量中的数值可以再通过RsSetCol函数写到EasyCICS的结果集中,注意此函数的第一个参数是列序号(从1开始),第二个参数是字符串值(EasyCICS只接受字符串值)。各列写完之后,要调用RsSaveRow函数存储此行数据。
程序最后在关闭游标后调用了ExitEasyCics函数,注意在任何情况下退出CICS服务程序,必须调用该函数。
只有C源程序还不够,我们还需要把它编译成执行文件或库文件(在Windows NT系统,CICS服务程序最终要被编译成为.DLL文件,即动态连接库)。一些程序员习惯于使用集成编译工具,但无法使用在UNIX等操作系统。我们采用更加通用的makefile方式进行编译。以下是在NT系统中,编译TELECOM服务程序的makefile(在各种UNIX系统,要进行必要的修改):
all: telecom.dll
telecom.ccs: telecom.sqc
db2 connect to cicstest
db2 prep telecom.sqc bindfile
db2 bind telecom.bnd
db2 grant execute on package telecom to public
db2 connect reset
copy telecom.c telecom.ccs
telecom.dll: telecom.ccs
set CICS_MSC_FLAGS=-I$(DB2PATH)\include
set USERLIB=$(DB2PATH)\lib\db2api.lib easycics.obj
cicstcl -e -d -lC telecom.ccs
clean:
del telecom.bnd telecom.c telecom.ccs telecom.dll telecom.exp telecom.lib telecom.obj
清单 2-1-12
再看看ANSI C的客户程序,就是清单2-1-13展示的C程序。
#include "ec.h"
/*
*/
void main(){
int i, j, rc, cc, r;
char s[100], c, cr;
r= ConnectServer( "CICSNT01", "TEST", "TEST" );
printf( "Connect Code: %d\n", r );
printf("Enter Query Number:");
scanf( "%s", s );
scanf( "%c", &cr );
BeginWrite();
SetValue( "NO", s );
r= CallProgramAndCommit("TELECOM");
if(r){
puts("Call Program Error !");
return;
}
RsOpen();
rc = RsGetRowNum();
cc = RsGetColNum();
for( i=1; i<=rc; i++ ){
RsFetchRow();
for(j=1; jRsGetCol(j,s);
printf(s);
printf( "," );
}
puts("");
}
}
清单 2-1-13
以下是运行结果(按提示输入查询的号码,程序返回查询的结果):
D:\cics>testec
Connect Code: 0
Enter Query Number:2020088
宋阮,2020088,105011031,0595,01385995193,Apr 17 1999 10:55PM , 3.00, 1.00, 1.5
0,
宋阮,2020088,105011031,0595,01385990145,Apr 16 1999 12:22PM , 1.00, 1.00, 1.0
0,
宋阮,2020088,105011031,0595,01385922328,Apr 9 1999 6:42PM , 1.00, 1.00, 1.0
0,
宋阮,2020088,105011031,0595,01385922328,Apr 7 1999 12:50PM , 2.00, 1.00, 2.0
0,
宋阮,2020088,105011031,0595,01385995193,Apr 6 1999 12:57PM , 3.00, 1.00, 3.0
0,
宋阮,2020088,105011031,0595,01385995193,Apr 5 1999 11:29AM , 1.00, 1.00, 1.0
0,
宋阮,2020088,105011031,0595,01385995193,Apr 5 1999 10:08AM , 1.00, 1.00, 1.0
0,
宋阮,2020088,105011031,0595,01385995193,Apr 3 1999 3:50PM , 4.00, 1.00, 2.0
0,
宋阮,2020088,105011031,0595,01385995183,Apr 3 1999 10:15AM , 1.00, 1.00, 0.5
0,
宋阮,2020088,105011031,0595,01385995193,Mar 31 1999 9:48PM , 6.00, 1.00, 3.0
0,
宋阮,2020088,105011031,0595,01385995193,Mar 29 1999 4:49PM , 5.00, 1.00, 5.0
0,
宋阮,2020088,105011031,0595,01385995193,Mar 27 1999 3:03PM , 9.00, 1.00, 4.5
0,
宋阮,2020088,105011031,0595,01385995193,Mar 21 1999 10:48PM , 3.00, 1.00, 1.5
0,
清单 2-1-14
这个程序采用的接口方法也是EasyCICS,所以我们引入了“ec.h”头文件(注意服务程序使用的是叫做“easycics.h”的头文件)。
程序首先执行了ConnectServer函数。该函数的第一个参数是CICS的系统名称,相当于CICS域(Region)的连接字符串;函数的后两个参数分别是CICS的用户名称和口令。
接着根据用户输入的号码调用SetValue函数,其作用是把一个字符串作为值赋予一个关键字(也是一个字符串),并存储在公共数据区。在这里,”NO”是关键字。注意所谓关键字是用户随意定义的,但最好客户程序和服务程序能相互匹配,如果没有通过SetValue函数设置某关键字的值就直接调用GetValue函数取此关键字的值,则取出空字符串。
再下面程序执行了CallProgramAndCommit函数,我们一般使用此函数来调用服务程序(Program)。该函数的唯一参数就是要调用的CICS的服务程序名称,在此处,即TELECOM程序。
接下来程序调用了一些结果集函数(以“Rs”为字头)。RsOpen函数用于打开结果集。注意,RsCreate和RsOpen函数对是EasyCICS传递二维值的标准方法,而SetValue和GetValue函数对是EasyCICS传递单值(零维值)的标准方法。结果集的行数和列数可以通过函数RsGetRowNum 和RsGetRowNum得到。函数RsFetchRow用于取出结果集的一行,而函数RsGetCol用于取出当前行的一列值。所有返回的值经格式化后写到屏幕上。
这个客户程序的makefile如下:
all: testec.exe
testec.exe: testec.obj
link testec.obj ec.obj cclwin32.lib
testec.obj: testec.c
cl /c testec.c
清单 2-1-15
下面是Visual Basic客户程序的源代码:
Option Explicit
Dim oEc As New EasyCics.App
Private Sub btnAbout_Click()
oEc.About
End Sub
Private Sub btnQuery_Click()
Dim r%, s$, i%, j%, rc%, cc%
lstTest.Clear
oEc.BeginWrite
s = txtNo.Text
oEc.SetValue "NO", s
oEc.CallProgramAndCommit "TELECOM"
s = oEc.GetErr
If s <> "" Then
MsgBox "Got an error when call CICS Server program:" + Chr(13) + Chr(10) + s
Exit Sub
End If
oEc.RsOpen
rc = oEc.RsGetRowNum
cc = oEc.RsGetColNum
s = ""
For i = 1 To rc
oEc.RsFetchRow
For j = 1 To cc
s = s + oEc.RsGetCol(j) + ","
Next
lstTest.AddItem s
s = ""
Next
End Sub
Private Sub Form_Load()
Dim r%
r = oEc.ConnectServer("CICSNT01", "TEST", "TEST")
If r <> 0 Then
MsgBox "Can't connect"
Exit Sub
End If
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set oEc = Nothing
End Sub
清单 2-1-16
因为所以高梁玉米蟋蟀蚂蚁 ..... 在这个城市里,一个人,会不会孤单碰见你,两个人,会不会比较不孤单
Visual Basic程序采用EasyCICS组件(PowerBuilder和Delphi也是通过组件访问CICS)。使用面向对象的术语,我们将反复提到组件的“方法”,或接口的“方法”,而不能说组件或接口的函数。程序预先创建了连接EasyCICS的对象。
程序首先执行了组件的ConnectServer方法。该方法的第一个参数是CICS的系统名称,相当于CICS域(Region)的连接字符串;函数的后两个参数分别是CICS的用户名称和口令。
接着根据用户输入的到文本框中的号码调用了组件的SetValue方法,其作用是把一个字符串作为值赋予一个关键字(也是一个字符串),并存储在公共数据区。在这里,”NO”是关键字。注意所谓关键字是用户随意定义的,但最好客户程序和服务程序能相互匹配,如果没有通过SetValue方法设置某关键字的值就直接调用GetValue方法取此关键字的值,则取出空字符串。
再下面程序执行了组件的CallProgramAndCommit方法,我们一般使用此方法来调用服务程序(Program)。该函数的唯一参数就是要调用的CICS的服务程序名称,在此处,即TELECOM程序。
接下来程序调用了一些结果集方法(以“Rs”为字头)。RsOpen方法用于打开结果集。注意,RsCreate和RsOpen方法对是EasyCICS传递二维值的标准方法,而SetValue和GetValue方法对是EasyCICS传递单值(零维值)的标准方法。结果集的行数和列数可以通过RsGetRowNum方法 和RsGetRowNum方法得到。RsFetchRow方法用于取出结果集的一行,而RsGetCol方法用于取出当前行的一列值。所有返回的值经格式化后加入一个列表框里。
以下是运行结果(在文本框中输入号码,点击查询按钮):
图 2-1-6
最后是JAVA的例子:
package ec;
import easycics.*;
/*****************************************************************************/
public class Telecom{
static public void main( String astrArg[] ){
long stime = System.currentTimeMillis();
try{
App oEc = new App();
//oEc.strJGateName = "local:";
oEc.ConnectServer("CICSNT01", "TEST", "TEST");
oEc.BeginWrite();
oEc.SetValue("NO", "2020088");
oEc.CallProgramAndCommit("TELECOM");
oEc.RsOpen();
int rc = oEc.RsGetRowNum();
int cc = oEc.RsGetColNum();
System.out.println("-----------------------------");
for(int i = 1; i <= rc; i++) {
oEc.RsFetchRow();
for (int j = 1; j < cc; j++) {
System.out.println(oEc.RsGetCol(j));
}
System.out.println("-----------------------------");
}
}
catch(ServerErrorException se){
System.out.println(se.getMessage());
System.out.println(se.getErrorCode());
}
catch(ResultSetErrorException re){
System.out.println(re.getMessage());
System.out.println(re.getErrorCode());
}
long etime = System.currentTimeMillis();
System.out.println( "Time used:" + (etime-stime)/1000. + "s" );
}
}
清单 2-1-17
以下是运行结果:
D:\cics>java ec.Telecom
-----------------------------
宋阮
2020088
105011031
0595
01385995193
Apr 17 1999 10:55PM
3.00
1.00
1.50
-----------------------------
宋阮
2020088
105011031
0595
01385990145
Apr 16 1999 12:22PM
1.00
1.00
1.00
-----------------------------
宋阮
2020088
105011031
0595
01385922328
Apr 9 1999 6:42PM
1.00
1.00
1.00
-----------------------------
宋阮
2020088
105011031
0595
01385922328
Apr 7 1999 12:50PM
2.00
1.00
2.00
-----------------------------
宋阮
2020088
105011031
0595
01385995193
Apr 6 1999 12:57PM
3.00
1.00
3.00
-----------------------------
宋阮
2020088
105011031
0595
01385995193
Apr 5 1999 11:29AM
1.00
1.00
1.00
-----------------------------
宋阮
2020088
105011031
0595
01385995193
Apr 5 1999 10:08AM
1.00
1.00
1.00
-----------------------------
宋阮
2020088
105011031
0595
01385995193
Apr 3 1999 3:50PM
4.00
1.00
2.00
-----------------------------
宋阮
2020088
105011031
0595
01385995183
Apr 3 1999 10:15AM
1.00
1.00
0.50
-----------------------------
宋阮
2020088
105011031
0595
01385995193
Mar 31 1999 9:48PM
6.00
1.00
3.00
-----------------------------
宋阮
2020088
105011031
0595
01385995193
Mar 29 1999 4:49PM
5.00
1.00
5.00
-----------------------------
宋阮
2020088
105011031
0595
01385995193
Mar 27 1999 3:03PM
9.00
1.00
4.50
-----------------------------
宋阮
2020088
105011031
0595
01385995193
Mar 21 1999 10:48PM
3.00
1.00
1.50
-----------------------------
Time used:1.853s
清单 2-1-18
我们来分析一下这个程序。最后,我们研究一下JAVA的例子。JAVA通过GateWay来访问CICS Client,我们也可以采用EasyCICS,所以,我们首先引入了easycics.*,这为我们访问CICS Client奠定了基础。
程序首先创建了easycics.App的类实例对象,并执行了类的ConnectServer方法。该方法的第一个参数是CICS的系统名称,相当于CICS域(Region)的连接字符串;函数的后两个参数分别是CICS的用户名称和口令。
接着根据用户输入的到文本框中的号码调用了类的SetValue方法,其作用是把一个字符串作为值赋予一个关键字(也是一个字符串),并存储在公共数据区。在这里,”NO”是关键字。注意所谓关键字是用户随意定义的,但最好客户程序和服务程序能相互匹配,如果没有通过SetValue方法设置某关键字的值就直接调用GetValue方法取此关键字的值,则取出空字符串。
程序在[C]处执行了类的CallProgramAndCommit方法,我们一般使用此函数来调用服务程序(Program)。该函数的唯一参数就是要调用的CICS的服务程序名称,在此处,即TELECOM程序。
接下来程序调用了一些结果集方法(以“Rs”为字头)。RsOpen方法用于打开结果集。注意,RsCreate和RsOpen方法对是EasyCICS传递二维值的标准方法,而SetValue和GetValue方法对是EasyCICS传递单值(零维值)的标准方法。结果集的行数和列数可以通过RsGetRowNum方法 和RsGetRowNum方法得到。RsFetchRow方法用于取出结果集的一行,而RsGetCol方法用于取出当前行的一列值。所有返回的值经格式化后打印到屏幕上。
看到这里,我相信没有人认为CICS开发很艰深。是的,对我们大多数人来说,不必象莱特兄弟那样自己动手造飞机,我们只须享受坐飞机的便利就够了。如果您熟悉的编程工具不在上述之列,没有关系。在本章的后续部分,我们将解析一个更加健全的例子,并展示13种常用开发工具访问CICS的编程方法。 ...
因为所以高梁玉米蟋蟀蚂蚁 ..... 在这个城市里,一个人,会不会孤单碰见你,两个人,会不会比较不孤单