AS/400系统开发工具及开发语言很多,有许多技术性的东西并不是我们能经常碰到的,但这些东西在一些实际应用中很有用处。本人在几年AS/400系统上的开发中,也有一些经验。有些东西如果不把其形成文字,过一段时间后,本人都会很快忘掉,比如我现在要写两年前的经验就很费劲。现把其中一些经验总结出来,与大家共享也行,自娱自乐也行。本文不是学术论文,仅仅是一些开发经验总结,有不严谨的地方必定在所难免。 AS/400开发经验点滴(一) AS/400系统开发工具及开发语言很多,有许多技术性的东西并不是我们能经常碰到的,但这些东西在一些实际应用中很有用处。本人在几年AS/400系统上的开发中,也有一些经验。有些东西如果不把其形成文字,过一段时间后,本人都会很快忘掉,比如我现在要写两年前的经验就很费劲。现把其中一些经验总结出来,与大家共享也行,自娱自乐也行。本文不是学术论文,仅仅是一些开发经验总结,有不严谨的地方必定在所难免。 一 如何在CL程序自动回复询问类消息(Inquiry Message) 在AS/400系统开发中,经常要与各种各样的消息打交道。有一类叫“Escape Message”的消息,是当程序出现错误后,会强迫程序异常结束,并告诉错误类型和原因。但经常时候我们不希望因为这些错误而使程序异常停止,在CL程序中,通常做法是用MONMSG命令来监视这些消息,而后采取相应的正确动作,或者引导程序结束。MONMSG一样还可以监视“Status Message”和“Notify Message”。但是有一类“Inquiry Message”,MONMSG还是无法监视,这类消息通常有多个回复选择项,要求用户必须给一个选择答复,因而通常会暂停程序运行,而显示一个要求用户给消息进行回复的画面。那么如何在程序中让程序自动选择一个正确的回复项回复呢?如能自动答复,就不需要手工再回复了。在作业JOBD里,有INQMSGRPY选择项,有三个选择:*RQD,*DFT,*SYSRPYL,这个INQMSGRPY就是表示指定Inquiry Message的答复方式,通常创建JOBD的时候INQMSGRPY项缺省是*RQD,这就表示需要操作员手工答复方式。而*DFT和*SYSRPYL就表示了两种程序可以自动答复的方式。 1. 消息答复缺省值法 如果在作业JOBD里INQMSGRPY选项指定为*DFT方式,则程序会自动使用消息的缺省答复项,询问消息就不会再在屏幕上显示。消息的缺省答复项,可以用CHGMSGD命令事先手工改好,也可以在程序中加入。比如下面的命令可以先在程序中设定: CHGMSGD MSGID(CPA3E01) MSGF(QCPFMSG) DFT(G) 此语句表示修改QCPFMSG消息文件中的CPA3E01消息的缺省答复为’G’(表示继续执行)。 2. 系统答复列表法 如果在作业JOBD里INQMSGRPY选项指定为*SYSRPYL方式,则程序会自动使用系统答复列表中定义的答复项。AS/400系统有一系统答复列表(System Reply List)。System Reply List允许用户指定某已定义在列表中消息的答复方式。System Reply List包含有序号、消息表示符、答复值、选择比较数据等。可以用WRKRPYLE命令查看System Reply List的所有内容。下面就是用WRKRPYLE命令查看到的内容: [code:1:4399c2b568]2=Change 4=Delete
Sequence Message Opt Number ID Reply Compare Value - 10 CPA0700 D *NONE - 20 RPG0000 D *NONE - 30 CBE0000 D *NONE - 40 PLI0000 D *NONE - 50 CPF7025 I *NONE - 60 CPA3E01 G *NONE - 1111 CPA3708 G *NONE [/code:1:4399c2b568] 可以用ADDRPYLE命令把你自己要定义的消息及缺省答复值加入。注意加入的时候Sequence Number项不能跟System Reply List已存在的重复。但是用系统答复列表法有个缺陷,那就是把ADDRPYLE命令加入到程序中不方便,因为System Reply List里的Sequence Number要求唯一,所以不能重复加入。而且当程序移到不同机器运行时,还必须把消息缺省答复重新加入 System Reply List。除了在JOBD可以指定消息答复方式外,还可以用BCHJOB和SBMJOB提交作业时在INQMSGRPY选择项里指定消息回复类别。BCHJOB和SBMJOB命令将会覆盖JOBD的答复方式。如果使用缺省答复方式和SBMJOB命令结合,可以先编一CL程序,就可以做到自动回复与机器和JOBD无关性,例子如下: [code:1:4399c2b568]CHGMSGD MSGID(CPA3E01) MSGF(QCPFMSG) DFT(G) SBMJOB CMD(CALL PGM(SMCRTRDBCL)) JOB(SMCRTRDBCL) + INQMSGRPY(*DFT)[/code:1:4399c2b568] 二 如何在RPG程序使用BLOCK关键词提高读写文件速度 RPG编程通常要与物理文件、逻辑文件等各类文件打交道。在RPG的F定义行里有一BLOCK关键词,善加使用这一关键词可以大幅度提高文件的读写速度。这在对具有大量数据的文件进行批处理时,效果特别明显。使用方法如下: 定义RPG程序F行(文件描述规范): 文件描述规范里有一BLOCK(*YES|*NO)关键词。它控制着文件的块读写方式。该关键词只对DISK或SEQ类型的文件有效。我们常见的物理文件(PF)或逻辑文件(LF)就是DISK文件。在缺省情况下,即F行关键词位置没有定义BLOCK时,在编译RPG程序时,对于输入记录,BLOCK缺省值为*NO,即文件不会以块的方式读入;对于输出记录,BLOCK缺省直为*YES。但上面编译缺省值需要先符合下面条件: (1) 文件是程序描述文件(program-described)。 (2) 文件如果是外部描述文件(externally-described),则文件应只有一个记录格式(Record Format)。 (3) 在文件规范描述里(F行),不能使用RECNO关键词。 如果要使文件输入记录以块方式(BLOCK)读入,则F行必须指定BLOCK关键词,并赋值为*YES, 比如,下面定义了一外部描述的DISK类型的文件,其读入方式采用BLOCK方式: [code:1:f176636ef4]FJRNRBUFP IF E DISK BLOCK(*YES) [/code:1:f176636ef4] 2.使用CL程序调用,并用OVRDBF覆盖文件属性 光是在RPG的文件描述里定义BLOCK(*YES),并不能使程序按BLOCK方式工作。需要先使用OVRDBF命令改变一下文件的属性。OVRDBF是个不错的命令,它不仅可以在程序内部改变文件名称,还可以在不改变文件名称的情况下,改变文件的一些属性参数,或者同时改变文件名称及文件属性参数。要使BLOCK方式正常工作,就需要先用OVRDBF命令改变文件的属性。要使BLOCK正常工作,需要指定SEQONLY(*YES)属性,即文件是按顺序读,RPG程序中不能有随机读写函数,比如READE等。SEQONLY(*YES)允许把多个记录放进内部数据管理缓冲区(Internal data management buffer),然后在一个时间点一次性把这些记录传给RPG程序。在指定文件为SEQONLY(*YES)属性的同时,还应指定一次读取到内部缓冲区最大记录数,该记录数与缓冲区和记录的大小有关,缓冲区越大,记录长度越小,能够一次读取的最大记录数越多。系统缺省最大记录数为4,实际工作中可以通过反复测试来验证系统能够一次读取的最大记录数,当设定的最大记录数*记录长度>内部缓冲区后,程序会报一错误。OVRDBF修改文件属性示范例子如下:
[code:1:f176636ef4]OVRDBF FILE(JRNRBUFP) SEQONLY(*YES 34)[/code:1:f176636ef4]
上面语句规定了RPG程序可以对JRNRBUFP文件进行顺序BLOCK读写,一次可以读取34条记录进内部缓冲区。
注意事项: (1) 要使用BLOCK方式,必须先用CL命令OVRDBF定义文件属性,然后调用RPG程序,不可以在RPG程序内部调用OVRDBF 。 (2) 使用BLOCK方式,要求文件为顺序读写方式,所以RPG程序中不能使用READE等随机读写函数 (3) 通常对大文件进行批处理时,文件都是顺序读写的,这时候使用BLOCK方式,效果特别明显,实际经验发现速度可以提高5-10倍。 三 如何在RPG程序里捕捉与文件操作有关的系统消息
AS/400系统里有大量各类消息,应用程序经常会因为意外情况被这些消息所打断,应用程序或者弹出消息窗口,或者在作业状态中报MSGW,等待人工干预。在CL程序里可以使用MONMSG命令来捕捉消息或自动答复消息机制来处理各样的消息,使程序始终能够正确地运行。但在RPG程序里,又怎么捕捉消息然后对消息进行特别处理呢?
RPG程序实际主要是对各类各样的文件操作,比如DISK文件(物理文件、逻辑文件)、显示文件、通信文件、打印文件等等。下面以DISK文件为例示范如何在RPG程序里捕捉错误消息。 1. 在文件描述规范(F行)里定义INFDS关键词 在RPG文件描述规范的关键词里,有一INFDS关键词。这个关键词是用来定义文件信息数据结构的,这个结构对每个文件都是唯一的。里面包含有几种Feedback Information。其中从1-80位是File Feedback Information, 在File Feedback Information的第46-52位定义了Message ID,当对文件操作出现错误消息时,这个错误消息就会保存在这个位置。在数据规范定义(D行)里把INFDS结构里的46-52位定义一变量,这样我们就可以获得错误消息了。下面是F行和D行的示范例子 [code:1:7bfbacd568]FTESTMSG O F 3750 DISK USROPN F INFDS(MSGFD)
D MSGFD DS D MSGID 46 52 [/code:1:7bfbacd568] 2. 在文件描述规范里定义INFSR(*PSSR)关键词 实际上如上义后,我们仍然不能捕捉系统错误消息,因为文件出现错误消息后,就会发生以外退出了。在文件规范描述里还有一个INFSR关键词,这个关键词里指定一个子例程,来接收文件意外错误后的控制。这个子例程的名字可以是*PSSR。通常我们是指定这个子例程来对异常错误进行相同的处理。但是如果我们与上面定义的文件信息结构的中MSGID相结合,我们就可以对单独的信息进行特别的处理了,从而实现了对系统消息的捕捉与特别处理。下面是F行改正后例子: [code:1:7bfbacd568]FTESTMSG O F 3750 DISK USROPN F INFDS(MSGFD) F INFSR(*PSSR)
D MSGFD DS D MSGID 46 52 [/code:1:7bfbacd568]
下面是接收错误消息控制的子例程的例子:
[code:1:7bfbacd568]C *PSSR BEGSR C MSGID IFEQ 'CPF5006' C 。。。。。 C GOTO XXXTAG C ENDIF C 。。。。 ** C MOVE '*DETC ' RETURN ** (Continue at the beginning) C ENDSR RETURN[/code:1:7bfbacd568] AS/400开发经验点滴(二): 一个批量修改文件属性的工具 四.一个批量修改文件属性的工具 AS/400上的每个文件都带有大量的属性,文件的属性是在创建文件的时候指定的。在实际应用过程中,可能会需要改变这些文件属性。以PF文件为例,我们可能需要修改文件的Member Size,Maximum Members,Maximum record wait time等等。修改物理文件(PF)属性命令是CHGPF,修改逻辑文件(LF)命令是 CHGLF,遗憾的是这些命令一次只能修改一个文件。如果假设有一个库,库下面有几千个物理文件需要一次性统一修改文件属性,那该怎么办?AS/400并没有提供这样的命令。我做了一个工具命令,可以实现对一个库下的所有文件属性进行批量修改,下面以修改文件Reuse deleted records属性为例来介绍这个工具命令,并附带全部源码。文件Reuse deleted records属性是表示记录在文件物理空间内被插入的方式,缺省情况下Reuse deleted records属性为*NO,这表示新记录将追加到文件尾部,如果Reuse deleted records属性修改为*YES,这表示物理文件中原已删除记录物理空间可以重复使用,当有新记录要加入时,系统会优先把新记录插入到原已删除记录空间里,只有当所有被删除记录空间都被重新使用后,新加记录才会从文件尾部开始追加。这个属性对于文件记录非常多、重整所费时间很长的情况下,还是很有用的。制作修改一个库下所有文件属性的思路是首先应把该库下的所有物理文件名取出来,然后才能循环一个个地修改。以下是主要步骤: 1. 提取某库下所有物理文件名 这主要是通过利用DSPFD来实现的。该命令是用来显示文件描述(File Description)的,它可以一次显示一个库下的一文件描述,也可以一次显示一个库下的所有文件描述。可以在OUTPUT选项里填入*OUTFILE,并在OUTFILE选项里填入接收文件名,就可以把DSPFD的显示内容输出到一个临时PF文件中。该临时文件就包含有文件名字段ATFILE以及库名字段ATLIB。例如下面DSPFD命令就是把定义某库下的所有物理文件名及其基本属性(*BASATR)输出到QGPL库下的 TEMPLIBF文件里: [code:1:b3ca3ab88b]DCL VAR(&CALIB) TYPE(*CHAR) LEN(10) /*定义一个库名变量*/ DSPFD FILE(&CALIB/*ALL) TYPE(*BASATR) + OUTPUT(*OUTFILE) FILEATR(*PF) + OUTFILE(QGPL/TEMPLIBF) [/code:1:b3ca3ab88b] 2. 对包含有文件名的临时文件进行加工 其实因为上面已经把文件名输出到了一个PF文件里,所以这一步可不要。但为了查看方便,我还是把文件名从TEMPLIBF中提出写入到一个更简单的PF文件中。先创建一个名为DTAFNAME的物理文件,如下:
[code:1:b3ca3ab88b]A R DTANAM A FILNAM 10A /*PF文件名*/ A FILLIB 10A /*库名*/[/code:1:b3ca3ab88b] 再用CRTSRCPF命令在QGPL库下建一个CHGTEST源文件目录,在该文件下创建一个SQL脚本文本文件CHGLIBAF,其内容为: INSERT INTO DTAFNAME SELECT ATFILE,ATLIB FROM QGPL/TEMPLIBF 然后在CL程序中,用RUNSQLSTM命令运行SQL脚本文件中的SQL语句: RUNSQLSTM SRCFILE(QGPL/CHGTEST) SRCMBR(CHGLIBAF) 这样就把文件名及库名从复杂的TEMPLIBF文件倒入到简单的DTAFNAME文件中 3. 循环修改文件属性 循环读DTAFNAME文件,取出文件名,就可以一个个地用CHGPF命令修改文件属性了。下面是完整的源代码:
文件名:CHGLIBFACL (CLLE) [code:1:b3ca3ab88b]/*===================================================================*/ /* PROGRAM NAME: CHGLIBFACL */ /* DESCRIPTION : */ /* PROGRAMMER : BLOG LIOU */ /* DATE : */ /*===================================================================*/ PGM PARM(&CALIB &REUSED) DCLF FILE(DTAFNAME) RCDFMT(DTANAM) DCL VAR(&CALIB) TYPE(*CHAR) LEN(10) DCL VAR(&REUSED) TYPE(*CHAR) LEN(4) CHKOBJ OBJ(QGPL/TEMPLIBF) OBJTYPE(*FILE) MONMSG MSGID(CPF9801) CLRPFM FILE(QGPL/TEMPLIBF) MONMSG MSGID(CPF3142) DSPFD FILE(&CALIB/*ALL) TYPE(*BASATR) + OUTPUT(*OUTFILE) FILEATR(*PF) + OUTFILE(QGPL/TEMPLIBF) CLRPFM FILE(DTAFNAME) RUNSQLSTM SRCFILE(QGPL/CHGTEST) SRCMBR(CHGLIBAF) LOOP: RCVF RCDFMT(DTANAM) /* Read a file record */ MONMSG MSGID(CPF0864) EXEC(GOTO EOF) CHGPF FILE(&FILLIB/&FILNAM) WAITFILE(60) + REUSEDLT(&REUSED) GOTO CMDLBL(LOOP) EOF: ENDPGM [/code:1:b3ca3ab88b] 命令文件:CHGLIBFA (CMD) [code:1:b3ca3ab88b] /*===================================================================*/ /* PROGRAM NAME : CHGLIBFA */ /* DESCRIPTION : */ /* PROGRAMMER : BLOG LIOU */ /* DATE : 2003/11/20 */ /*===================================================================*/ CMD PROMPT('Change Database File Attribute') PARM KWD(CHGLIB) TYPE(*NAME) LEN(10) + PROMPT('Change Lib') PARM KWD(REUSEDLT) TYPE(*NAME) LEN(4) + SPCVAL((*YES) (*NO)) PROMPT('Reused + Delete Rows') [/code:1:b3ca3ab88b] 用命令CRTCMD CMD(CHGLIBFA) PGM(CHGLIBFACL)创建CHGLIBFA命令,执行CHGLIBFA,就可以输入库名修改该库下的所有文件的Reuse deleted records的属性了。只需要稍对程序进行修改就可以批量修改文件多个其他属性了。 AS/400开发经验点滴(三) --如何使用分布式关系数据库 五.如何使用分布式关系数据库 我们可以在AS/400系统中使用STRSQL命令来交互执行SQL语句。如果AS/400系统中没有安装交互式SQL工具,那么我们便不能使用SQL语句进行交互式查询等操作。假设有一群连网的AS/400,其中只有一台安装了交互式SQL工具,那么我们能不能只通过这台AS/400的交互SQL工具去对其他没有安装SQL交互工具机器的数据库进行操作呢?答案是肯定的,这就需要使用分布式关系数据库。分布式数据库管理是AS/400系统提供的一个重要功能之一,其功能比较强大,在本文里只能根据作者经验对分布式关系数据库的使用作简单介绍,根据这个简单介绍,你就可以很容易体验分布式关系数据库的使用。要使用分布式关系数据库,首先需要创建关系数据库目录,即Relational Database Diretory。用WRKRDBDIRE可以查看关系数据库目录,其界面如下: [code:1:77907562ca] Work with Relational Database Directory Entries Position to . . . . . . Type options, press Enter. 1=Add 2=Change 4=Remove 5=Display details 6=Print details Relational Remote Option Database Location Text
- PRODUCT PRODUCT - BACKUP *LOCAL[/code:1:77907562ca]该示例显示在BACKUP机器上已经创建了PRODUCT和BACKUP两个Relational Database Directory Entry。对应界面操作选择项命令则分别是ADDRDBDIRE、CHGRDBDIRE、RMVRDBDIRE、DSPRDBDIRE。用ADDRDBDIRE命令可以增加新的Relational Database Directory Entry。这个命令里有两个必填项(其他项可以使用缺省),RDB项是取一个关系数据库的名称,通常选择与机器系统名一致的名称,RMTLOCNAME是给定对方地址名称,如果是定义本地关系数据库,则此项填*LOCAL。如果是定义远程机器数据库,在RMTLOCNAME项实际上要填两个域,先确定通信类型,可选项是*SNA和*IP,分别表示使用SNA协议或TCP/IP协议通信。如果TYPE选择*SNA,则Name or address里需填远程机器location name,这个location name可以在远程机器上执行DSPNETA命令查到。如果TYPE选择*IP,则Name or address可以直接填IP地址。 [code:1:77907562ca] Add RDB Directory Entry (ADDRDBDIRE)
Type choices, press Enter. Relational database . . . . . PRODUCT Remote location: Name or address . . . . . PRODUCT Name, *LOCAL, *ARDPGM Type . . . . . . . . . . . . . *SNA *SNA, *IP Text . . . . . . . . . . . . . . *BLANK [/code:1:77907562ca] 关系数据库目录创建好后,我们就可以在STRSQL命令里连接不同的关系数据库。 用CONNECT TO语句可以第一次连接关系数据库,比如在BACKUP机器上在STRSQL界面里执行CONNECT TO PRODUCT,那么我们就在BACKUP机器上连接上了PRODUCT机器上的数据库,接下来任何SQL语句操作都是对PRODUCT机器上数据库操作,再执行CONNECT TO BACKUP,那么又回到本地数据库操作。如果BACKUP和PRODUCT关系数据库已经连接,那么不能再使用CONNECT TO语句切换连接,切换连接的命令则是SET CONNECTION,比如我们要重新切换到PRODUCT连接,则执行SQL语句:SET CONNECTION PRODUCT。如果我们要关闭关系数据库连接,则可以使用SQL语句DISCONNECT,比如执行DISCONNECT PRODUCT就关闭了PRODUCT的关系数据库连接。如果在使用STRSQL的时候,你启动了事务机制,那么DISCONNECT就不再起作用了,这时候如果要关闭关系数据库连接,需要使用RELEASE语句,比如RELEASE PRODUCT,注意在RELEASE之后,还必须再执行COMMIT或ROLLBACK语句才能彻底关闭关系数据库连接。 综上,与关系数据库操作有关的SQL语句为下面四条: [list:77907562ca]CONNECT TO SET CONNECTION DISCONNECT RELEASE[/list:u:77907562ca] 六.如何利用分布式关系数据库进行分布式编程 我们不仅可以使用STRSQL进行关系数据库的交互操作,还可以用关系数据库的SQL语句进行分布式编程,即我们可以在一台机器的程序里连接另一台机器的关系数据库,从而通过程序实现对另一台机器的数据库操作,这就是分布式数据库编程。下面以ILE RPG程序为例,说明如何进行分布式编程。因为在程序中要使用SQL语句,所以程序类型(或扩展名)是SQLRPGLE。因为在程序中,需要先连接关系数据库,才能打开数据库文件,所以在F行规范定义中,不能使用隐含打开方式,需要指定USROPN关键词来显式打开文件。如下例TESTPF文件就是另一台机器上的文件: FTESTPF IF E K DISK USROPN
连接关系数据库方式如下:
C/EXEC SQL C+ CONNECT TO :RDBNAM C/END-EXEC
如果关系数据库连接已经建立,则返回错误码-842,可以判断此错误码,重新SET一次关系数据库连接:
C SQLCOD IFEQ -842 C/EXEC SQL C+ SET CONNECTION :RDBNAM C/END-EXEC C ENDIF
关系数据库连接建好后,我们就可以显示打开另一台机器的文件TESTPF了:
C OPEN TESTPF
之后就可以对TESTPF进行各种数据库操作了。
要退出程序时,需要关闭数据库连接:
C/EXEC SQL C+ DISCONNECT :RDBNAM C/END-EXEC
如果程序中使用了事务处理机制,需要用RELEASE关闭连接:
C/EXEC SQL C+ RELEASE :RDBNAM C/END-EXEC C…. C/EXEC SQL COMMIT C/END-EXEC
这样子分布式程序就写好可以编译了。分布式程序要正常工作,还需要SQL Package来支持!OS/400系统支持一种叫SQL Package的目标,其目标类型是*SQLPKG。SQL Package包含有分布式程序运行时处理SQL语句的控制和访问计划。建立SQL Package有两种方法,一种方法是在编译分布式程序时,在Relational database(RDB)选择项里填写远程机器的关系数据库名,那么编译器会自动创建一个名字与程序名一样但类型为*SQLPKG的目标。另一种方法是用CRTSQLPKG命令手工创建SQL Package:
Create SQL Package (CRTSQLPKG)
Type choices, press Enter.
Program . . . . . . . . . . . . Name Library . . . . . . . . . . . *LIBL Name, *LIBL, *CURLIB Relational database . . . . . . *PGM RDB user . . . . . . . . . . . . *CURRENT Name, *CURRENT RDB user password . . . . . . . Character value, *NONE, ' ' Default Collection . . . . . . . *PGM Name, *PGM, *NONE Object type . . . . . . . . . . *PGM *PGM, *SRVPGM Module list . . . . . . . . . . *ALL Character value, *ALL + for more values Text 'description' . . . . . . . *PGMTXT 在Program选项里填写上面编译后的分布式程序名,在Relational database选项里填写已经定义的另一台机器的关系数据库名。我们在实际运行分布式程序前,可以根据配置关系数据库名称,用DELSQLPKG删除原来的SQL Package,用CRTSQLPKG重新创建一个新的SQL Package。有了SQL Packge支持,分布式程序就可以正常运行了。 AS/400开发经验点滴(四) --如何在程序中获取系统状态信息 七.如何在程序中获取系统ASP使用率等系统状态信息 AS/400系统管理员都对系统ASP空间增长情况很关心,当系统ASP空间涨满了以后将会引起系统DOWN机等安全问题。系统ASP空间与硬盘空间并不完全等同,如果系统只配置了一个ASP分区,那么系统ASP空间与硬盘空间是等同的,如果系统配置了多个ASP分区,则系统ASP只是ASP 1的分区。用WRKSYSSTS命令查看到的% system ASP used就是表示系统ASP空间的使用率。与系统ASP空间使用率有关的系统值有两个:QSTGLOWLMT和QSTGLOWACN。QSTGLOWLMT系统值设定了最小硬盘空间警告线百分比,比如设定为5,即表示系统ASP使用率达到95%,即引起安全动作,安全动作由系统值QSTGLOWACN设定。能不能在程序中自动获取系统ASP使用率,这样当硬盘空间达到危险值时,由程序提前报警呢?或者在程序中自动执行一些安全动作,比如自动清理一些过时的文件,或停止某些程序运行,以降低系统ASP使用率? OS/400系统提供了一个叫QWCRSSTS的API函数,该函数功能就可以提取用WRKSYSSTS命令看到的系统状态信息,还可以提取更多的用WRKSTSSTS命令看不到的一些其他系统信息。可以在RPG、C、CL等程序里调用该API以获取系统信息。该函数的详细使用说明可以参看《System API Reference》这本书。下面我用一个实际获取系统ASP使用率的CL程序做例子,来看看如何使用QWCRSSTS。 QWCRSSTS共有五个入口参数,第一个参数是接受返回系统状态信息的输出参数,存放的是返回系统状态信息块。该系统状态信息块是按照一定结构来存放各种系统状态信息的。第二个参数是输入参数,指定第一个接受系统状态信息块变量的长度,类型为Binary。第三个参数是指定第一个参数系统状态信息块中的系统信息存放结构名,共有三种不同的结构可选,分别是:SSTS0100、SSTS0200、SSTS0300。第四个参数是表示是否重新设置状态统计,通常我们选*YES。第五个参数是错误码。在本示例CL程序中,指定使用SSTS0200系统状态信息结构。该结构中53-57位存放的就是% system ASP used。该值除上10000,就是正常百分比。在程序中先是提取QSTGLOWLMT系统值,指定100-QSTGLOWLMT-2为程序警告线,比如QSTGLOWLMT如果设为5,那么当系统ASP到93%的时候,程序会向用户发出一个消息。同时把ASP状态返回值设为1,以供其他程序调用,当调用程序判断ASP状态返回值为1的时候,就知道系统ASP空间利用率到了警告线,需要执行一些安全动作了。 [code:1:1ced1f3fa8]/*===================================================================*/ /* */ /*-----------------------------------------------------------------------------------------------------------------*/ /* PROGRAM NAME : MONASP */ /* CREATED BY : BLOG LIOU */ /* CREATED DATE : 2003.11.11 */ /* DESCRIPTION : Monitor ASP Used */ /* MonASPPer: (100-STGLOWLMT)-2 */ /*===================================================================*/ PGM PARM(&ASPFLAG) DCL VAR(&ASPFLAG) TYPE(*CHAR) LEN(1) DCL VAR(&FORMAT) TYPE(*CHAR) LEN(8) + VALUE('SSTS0200') DCL VAR(&LENFLD) TYPE(*CHAR) LEN(4) + VALUE(X'00000044') DCL VAR(&SYSNAM) TYPE(*CHAR) LEN(8) DCL VAR(&SYSUSEC) TYPE(*CHAR) LEN(4) DCL VAR(&SYSUSE) TYPE(*DEC) LEN(9 2) DCL VAR(&SYSINFO) TYPE(*CHAR) LEN(68) DCL VAR(&ERRCODE) TYPE(*CHAR) LEN(8) + VALUE(X'0000000000000000') DCL VAR(&RESETSY) TYPE(*CHAR) LEN(10) VALUE(*YES) DCL VAR(&QMNPER) TYPE(*DEC) LEN(9 2) VALUE(1000000) DCL VAR(&QALARM) TYPE(*DEC) LEN(9 2) VALUE(20000) DCL VAR(&STGLOWLMT) TYPE(*DEC) LEN(9 2) DCL VAR(&SNDMSG) TYPE(*CHAR) LEN(10) CHGVAR VAR(&ASPFLAG) VALUE('0') RTVSYSVAL SYSVAL(QSTGLOWLMT) RTNVAR(&STGLOWLMT) CHGVAR VAR(&STGLOWLMT) VALUE(&STGLOWLMT * 10000) CHGVAR VAR(&QMNPER) VALUE(&QMNPER - &STGLOWLMT) CHGVAR VAR(&QMNPER) VALUE(&QMNPER - &QALARM) CALL PGM(QWCRSSTS) PARM(&SYSINFO &LENFLD &FORMAT + &RESETSY &ERRCODE) MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERREND)) CHGVAR VAR(&SYSUSEC) VALUE(%SST(&SYSINFO 53 4)) CHGVAR VAR(&SYSUSE) VALUE(%BINARY(&SYSUSEC)) CHGVAR VAR(&SYSNAM) VALUE(%SST(&SYSINFO 17 8)) IF COND(&SYSUSE > &QMNPER) THEN(DO) CHGVAR VAR(&SNDMSG) VALUE(&SYSUSE) SNDPGMMSG MSG(&SYSNAM *BCAT ' - (ASP USED + PERCENT)*10000 = ' *BCAT &SNDMSG) + TOMSGQ(MYUSER) SNDPGMMSG MSG('*****SYSTEM OVER MonASP !!! ') + TOMSGQ(MYUSER) MSGTYPE(*INFO) CHGVAR VAR(&ASPFLAG) VALUE('1') ENDDO GOTO CMDLBL(END) ERREND: SNDPGMMSG MSG(' ERROR ON QWCRSSTS CALL') + TOMSGQ(MYUSER) MSGTYPE(*INFO) END: ENDPGM [/code:1:1ced1f3fa8] 该程序也可以与某些报警程序连起来使用,比如当系统ASP空间达到警告线后,程序调用某些拨号程序,就可以给系统管理员手机发短信息等。 如果再设计一个显示文件,把QWCRSSTS获取到的系统状态信息,比如系统ASP使用率、CPU使用率、系统出现Message进程数,都显示出来,我们就实现了一个系统状态信息的监 |