System API で NETSTAT 情報の取得 (V5R4)

V5R4 では、netstat コマンドの出力は画面で見るしかありません。
ある IP とのセッションの情報(セッション数だったり Bytes in/out だったり)を継続に監視したいような場合は、ツールを作成する必要があります。

System API を使用することで netstat コマンドと同様の情報の取得はできるので、これを使ってそういう情報を取得するツールの例を今回は紹介します。

知り合いの人からいただいたプログラムを(許可をもらって)ちょっと修正して載せています。


RPG

実際に情報を取得して、DB テーブルに書き出すプログラムです。

System API プログラミングの基礎 (3) - ユーザースペース使用用の汎用プロシージャの作成 -」で作った crtusrspcp プロシージャを利用しています。

ローカルとリモートの IP アドレスおよび/またはポートを指定して情報を取得するようにしています。
IP アドレスがブランクの場合はすべての IP アドレス、ポートが 0 の場合はすべてのポート、というのが特殊値ですね。
IP アドレスの範囲指定などは仕様にいれませんでした。そこまでの汎用性は必要ありませんでしたので。

IP アドレスの文字列からバイナリへの変換

あと、若干今回新機軸なのが、IP アドレスの変換です。
指定は文字列(おなじみの 'xxx.xxx.xxx.xxx' ですね)の方が便利なのですが、コンピュータにとってはそうではありません。
別に System i に限ったことではなく、バイナリーに変換してやる必要があります。

通常は inet_pton などといった関数を使用しますが、 今回は急いでいたこともあり、また IPv4 しか対象がないこともあり、
IPv4 でしか使えない(= IPv6 には対応できない)inet_addr 関数を使用して IP アドレスを文字列から API に渡すための値に変換しました。

     D inet_addr       Pr            10u 0 ExtProc( 'inet_addr' )                                   
     D  srcAddr                        *   value options(*string)                                   
                  NCLQ0100.LclAddrLow = inet_addr(%trimR(lAddr)) ;                                  

(本当は戻り値をチェックして -1 なら後続しない、とするべきなのですが、ちょっと端折っています。。。)

あとはそんなに難しいことはないと思います。

     H bnddir('QC2LE')                                                                              
      *                                                                                             
      *  CREATE TABLE NETSTAT/NETSTAT_INF                                                           
      *        (REMOTE_ADDR CHAR ( 15) NOT NULL WITH DEFAULT,                                       
      *         REMOTE_PORT CHAR ( 5) NOT NULL WITH DEFAULT,                                        
      *         LOCAL_ADDR CHAR ( 15) NOT NULL WITH DEFAULT,                                        
      *         LOCAL_PORT CHAR ( 5)  NOT NULL WITH DEFAULT,                                        
      *         TCP_STATE CHAR ( 11) NOT NULL WITH DEFAULT,                                         
      *         IDLE_TIME DEC ( 10, 0),                                                             
      *         BYTES_IN DEC ( 10, 0),                                                              
      *         BYTES_OUT DEC ( 10, 0),                                                             
      *         OPEN_TYPE CHAR ( 11) NOT NULL WITH DEFAULT,                                         
      *         CONNECTION_TYPE CHAR ( 10) NOT NULL WITH DEFAULT,                                   
      *         USER_PROFILE CHAR ( 10) NOT NULL WITH DEFAULT,                                      
      *         INQUIRED_DATE TIMESTAMP NOT NULL WITH DEFAULT)                                      
      *                                                                                             
      *                                                                                             
      *  CRTSQLRPGI OBJ(NETSTAT/GETNETSTAT) SRCFILE(NETSTAT/QRPGLESRC)                              
      *             COMMIT(*NONE) OBJTYPE(*MODULE) DBGVIEW(*SOURCE)                                 
      *                                                                                             
      *  CRTPGM PGM(NETSTAT/GETNETSTAT)                                                             
      *         MODULE(NETSTAT/GETNETSTAT NETSTAT/CRTUSRSPCP)                                       
      *                                                                                             
      *                                                                                             
     D GetNetStat      PR                                                                           
     D  lAddr                        15a                                                            
     D  lPort                         5a                                                            
     D  rAddr                        15a                                                            
     D  rPort                         5a                                                            
      *                                                                                             
     D GetNetStat      PI                                                                           
     D  lAddr                        15a                                                            
     D  lPort                         5a                                                            
     D  rAddr                        15a                                                            
     D  rPort                         5a                                                            
      *                                                                                             
     D CrtUsrspcP      PR              *                                                            
     D  Name                         20a                                                            
      *                                                                                             
     D LstNetCnn       Pr                  ExtProc( 'QtocLstNetCnn' )                               
     D  pUsrspcName                  20a   Const                                                    
     D  pFormatName                   8a   Const                                                    
     D  pCnnQual                     64a   Const                                                    
     D  pCnnQualSiz                  10i 0 Const                                                    
     D  pCnnQualFmt                   8a   Const                                                    
     D  ErrorCode                          like(APIErr)                                             
      *                                                                                             
     D inet_addr       Pr            10u 0 ExtProc( 'inet_addr' )                                   
     D  srcAddr                        *   value options(*string)                                   
      *                                                                                             
     D GenericHeader   DS                  Qualified Based(usPtr)                                   
     D  userarea                     64a                                                            
     D  size                         10i 0                                                          
     D  releaselevel                  4                                                             
     D  formatname                    8                                                             
     D  APIused                      10                                                             
     D  DateCreated                  13                                                             
     D  InforSts                      1                                                             
     D  sizeUsed                     10i 0                                                          
     D  offsetInput                  10i 0                                                          
     D  sizeInput                    10i 0                                                          
     D  offsetHeader                 10i 0                                                          
     D  sizeHeader                   10i 0                                                          
     D  offsetList                   10i 0                                                          
     D  sizeList                     10i 0                                                          
     D  numberList                   10i 0                                                          
     D  sizeEntry                    10i 0                                                          
     D  CCSID                        10i 0                                                          
     D  cntryID                       2                                                             
     D  langID                        3                                                             
     D  subsetInd                     1                                                             
     D  rsvd                         42                                                             
      *                                                                                             
     D jlPtr           S               *                                                            
     D NCNN0100        DS                  Qualified Based(jlPtr)                                   
     D  RmtAddr                      15a                                                            
     D  rsvd1                         1a                                                            
     D  RmtAddrBin                   10i 0                                                          
     D  LclAddr                      15a                                                            
     D  rsvd2                         1a                                                            
     D  LclAddrBin                   10i 0                                                          
     D  RmtPort                      10i 0                                                          
     D  LclPort                      10i 0                                                          
     D  TcpState                     10i 0                                                          
     D  IdleMs                       10i 0                                                          
     D  BytesIn                      20i 0                                                          
     D  BytesOut                     20i 0                                                          
     D  ConnOpenT                    10i 0                                                          
     D  NetConnT                     10a                                                            
     D  rsvd3                         2a                                                            
     D  UsrPrf                       10a                                                            
     D  rsvd4                         2a                                                            
      *                                                                                             
     D NCLQ0100        DS                  Qualified                                                
     D  NetConnT                     10a   inz('*ALL      ')                                        
     D  LstReqT                      10a   inz('*SUBSET   ')                                        
     D  rsvd                         12a   inz('            ')                                      
     D  LclAddrLow                   10u 0 inz(0)                                                   
     D  LclAddrUpp                   10u 0 inz(0)                                                   
     D  LclPortLow                   10i 0 inz(0)                                                   
     D  LclPortUpp                   10i 0 inz(0)                                                   
     D  RmtAddrLow                   10u 0 inz(0)                                                   
     D  RmtAddrUpp                   10u 0 inz(0)                                                   
     D  RmtPortLow                   10u 0 inz(0)                                                   
     D  RmtPortUpp                   10u 0 inz(0)                                                   
      *                                                                                             
     D pName           S             20a                                                            
     D usPtr           S               *                                                            
      *                                                                                             
     D APIErr          DS                  Qualified                                                
     D  ErrSize                      10i 0 inz(%size(APIErr))                                       
     D  ErrLen                       10i 0 inz(0)                                                   
     D  ErrID                         7a                                                            
     D  rsvd                          1a                                                            
     D  ErrData                   32767a                                                            
      *                                                                                             
     D i               S              5  0                                                          
     D wSECs           S             29p 2                                                          
     D wMINs           S             29p 5                                                          
     D wHOURs          S             29p 5                                                          
     D wDAYs           S             29p 5                                                          
     D status          S             11a                                                            
      *                                                                                             
     D RcvSize         S             10  0 INZ(16776704)                                            
      *                                                                                             
     D HandleErr       PR                                                                           
      *                                                                                             
     D RemoteAddr      s             15a                                                            
     D RemotePort      s              5a                                                            
     D LocalAddr       s             15a                                                            
     D LocalPort       s              5a                                                            
     D IdleMS          s             10p 0                                                          
     D BytesIn         s             10p 0                                                          
     D BytesOut        s             10p 0                                                          
     D OpenType        s             11a                                                            
      *                                                                                             
      /Free                                                                                         
                                                                                                    
              if lAddr = *blank ;                                                                   
                  NCLQ0100.LclAddrLow = 0 ;                                                         
              else ;                                                                                
                  NCLQ0100.LclAddrLow = inet_addr(%trimR(lAddr)) ;                                  
                  NCLQ0100.LclAddrUpp = 0 ; // *only                                                
              endif ;                                                                               
                                                                                                    
              if lPort = *blanks ;                                                                  
                  NCLQ0100.LclPortLow = 0 ; // all local ports                                      
              else ;                                                                                
                  NCLQ0100.LclPortLow = %INT(lPort) ;                                               
              endif ;                                                                               
                                                                                                    
              if rAddr = *blank ;                                                                   
                  NCLQ0100.RmtAddrLow = 0 ;                                                         
              else ;                                                                                
                  NCLQ0100.RmtAddrLow = inet_addr(%trimR(rAddr)) ;                                  
                  NCLQ0100.RmtAddrUpp = 0 ; // *only                                                
              endif ;                                                                               
                                                                                                    
              if rPort = *blanks ;                                                                  
                  NCLQ0100.RmtPortLow = 0 ; // all local ports                                      
              else ;                                                                                
                  NCLQ0100.RmtPortLow = %INT(rPort) ;                                               
              endif ;                                                                               
                                                                                                    
              pName =    'GETNETSTATQTEMP     ' ;                                                   
              usPtr = CrtUsrspcP  (pName ) ;                                                        
                                                                                                    
              LstNetCnn ( pName                                                                     
                         :'NCNN0100'                                                                
                         :NCLQ0100                                                                  
                         :%Size( NCLQ0100 )                                                         
                         :'NCLQ0100'                                                                
                         :APIErr ) ;                                                                
                                                                                                    
              If APIErr.ErrLEN <> 0 ;                                                               
                HandleErr() ;                                                                       
                return ;                                                                            
              endif ;                                                                               
                                                                                                    
              If GenericHeader.numberList = 0 ;                                                     
                return ;                                                                            
              endif ;                                                                               
                                                                                                    
              jlPtr = usPtr + GenericHeader.offsetList ;                                            
                                                                                                    
              for i = 1 to GenericHeader.numberList ;                                               
           //   dsply NCNN0100.NetConnT ;                                                           
           //   dsply NCNN0100.LclAddr ;                                                            
           //   dsply NCNN0100.LclPort ;                                                            
           //   dsply NCNN0100.RmtAddr ;                                                            
           //   dsply NCNN0100.RmtPort ;                                                            
                                                                                                    
                Select ;                                                                            
                  when NCNN0100.TcpState  = 0 ;                                                     
                     Status  = 'Listen     ' ;                                                      
                  when NCNN0100.TcpState  = 1 ;                                                     
                     Status  = 'SYN-sent   ' ;                                                      
                  when NCNN0100.TcpState  = 2 ;                                                     
                     Status  = 'SYN-recived' ;                                                      
                  when NCNN0100.TcpState  = 3 ;                                                     
                     Status  = 'Established' ;                                                      
                  when NCNN0100.TcpState  = 4 ;                                                     
                     Status  = 'FIN-wait-1 ' ;                                                      
                  when NCNN0100.TcpState  = 5 ;                                                     
                     Status  = 'FIN-wait-2 ' ;                                                      
                  when NCNN0100.TcpState  = 6 ;                                                     
                     Status  = 'Close-wait ' ;                                                      
                  when NCNN0100.TcpState  = 7 ;                                                     
                     Status  = 'Closing    ' ;                                                      
                  when NCNN0100.TcpState  = 8 ;                                                     
                     Status  = 'Last-ACK   ' ;                                                      
                  when NCNN0100.TcpState  = 9 ;                                                     
                     Status  = 'Time-wait  ' ;                                                      
                  when NCNN0100.TcpState  = 10 ;                                                    
                     Status  = 'Closed     ' ;                                                      
                  when NCNN0100.TcpState  = 11 ;                                                    
                     Status  = 'Not Support' ;                                                      
                  Other ;                                                                           
                     Status  = 'Unknown    ' ;                                                      
                endsl ;                                                                           
            //  dsply Status ;                                                                      
                                                                                                    
                Select ;                                                                            
                  when NCNN0100.ConnOpenT = 0 ;                                                     
                     OpenType  = 'Passive    ' ;                                                    
                  when NCNN0100.ConnOpenT = 1 ;                                                     
                     OpenType  = 'Active     ' ;                                                    
                  when NCNN0100.ConnOpenT = 2 ;                                                     
                     OpenType  = 'Not Support' ;                                                    
                  Other ;                                                                           
                     OpenType  = 'Unknown    ' ;                                                    
                endsl ;                                                                           
                                                                                                    
                RemoteAddr = %trimR(NCNN0100.RmtAddr:x'00') ;                                   
                RemotePort = %char(NCNN0100.RmtPort) ;                                          
                LocalAddr = %trimR(NCNN0100.LclAddr:x'00') ;                                    
                LocalPort = %char(NCNN0100.lCLPort) ;                                           
                IdleMS    = %dec(NCNN0100.IdleMs) ;                                             
                BytesIn   = %dec(NCNN0100.BytesIn) ;                                            
                BytesOut  = %dec(NCNN0100.BytesOut) ;                                           
                                                                                                    
            //  wSECs = NCNN0100.IdleMs/1000 ;                                                      
            //  wMINs = wSECs/60 ;                                                                  
            //  wHOURs = wMINs/60 ;                                                                 
            //  wDAYs = wHOURs/60 ;                                                                 
                                                                                                    
            //  dsply wSECs ;                                                                       
                                                                                                    
                Exec sql                                                                            
                  INSERT INTO NETSTAT/NETSTAT_INF                                                   
                    VALUES( :RemoteAddr ,                                                           
                            :RemotePort ,                                                           
                            :LocalAddr,                                                             
                            :LocalPort,                                                             
                            :Status,                                                                
                            :IdleMS,                                                                
                            :BytesIn,                                                               
                            :BytesOut,                                                              
                            :OpenType,                                                              
                            :NCNN0100.NetConnT,                                                     
                            :NCNN0100.UsrPrf,                                                       
                            CURRENT_TIMESTAMP                                                       
                          ) ;                                                                       
                                                                                                    
                jlPtr =  jlPtr + GenericHeader.sizeEntry ;                                          
              endfor ;                                                                              
                                                                                                    
              *inLR = *on ;                                                                         
              return ;                                                                              
                                                                                                    
      /End-Free                                                                                     
      *                                                                                             
      *                                                                                             
     P HandleErr       B                                                                            
     D HandleErr       PI                                                                           
      *                                                                                             
      /Free                                                                                         
                                                                                                    
      /End-Free                                                                                     
      *                                                                                             
     P HandleErr       E                                                                           

コマンドを作って使いやすくする

このプログラムを直接呼び出すのはなかなか使いやすいものではないと思いますので、呼び出し用のコマンドを作成しました。
どれくらいの間隔で情報を取り、何回もしくは何時になったら終了にするのか、を指定します。

     /*                                          */                             
     /*  CRTCMD CMD(NETSTAT/GETNETSTAT)          */                             
     /*         PGM(NETSTAT/GETNSDATAC)          */                             
     /*         SRCFILE(NETSTAT/QCMDSRC)         */                             
     /*                                          */                    
         
             CMD        PROMPT('NETSTAT データの取得 ')                
             PARM       KWD(LCLIPADDR) TYPE(*CHAR) LEN(15) DFT(' ') +  
                          PROMPT(' ローカル IP アドレス ')             
             PARM       KWD(LOCALPORT) TYPE(*DEC) LEN(5 0) DFT(0) +    
                          RANGE(0 99999) PROMPT(' ローカル・ポート ')  
             PARM       KWD(RMTIPADDR) TYPE(*CHAR) LEN(15) DFT(' ') +  
                          PROMPT(' リモート IP アドレス ')             
             PARM       KWD(REMOTEPORT) TYPE(*DEC) LEN(5 0) DFT(0) +   
                          RANGE(0 99999) PROMPT(' リモート・ポート ')  
             PARM       KWD(INTERVAL) TYPE(*DEC) LEN(3 0) RANGE(1 +    
                          999) PROMPT(' インターバル ')                
             PARM       KWD(ENDOPT) TYPE(*CHAR) LEN(6) RSTD(*YES) +    
                          DFT(*COUNT) VALUES(*COUNT *TIME) +           
                          PROMPT(' 終了オプション ')                   
             PARM       KWD(ENDCOUNT) TYPE(*DEC) LEN(5 0) RANGE(1 +    
                          99999) PMTCTL(ENDCOUNTS) PROMPT(' 回数 ')    
             PARM       KWD(ENDTIME) TYPE(*TIME) PMTCTL(ENDTIME) +     
                          PROMPT(' 時間 ')                             
                                                                                
 ENDCOUNTS:  PMTCTL     CTL(ENDOPT) COND((*EQ '*COUNT'))                        
 ENDTIME:    PMTCTL     CTL(ENDOPT) COND((*EQ '*TIME'))                         

コマンドのパラメータの切替

オプションで、何回(*COUNT)か何時(*TIME)かを選択し、それに応じたパラメータをセットさせるようにしたところがちょっとした工夫でしょうか。

コマンドを処理する RPG 呼び出し用 CL

コマンドを処理する CL はこちらです。
V5R4 で使用できる SELECT/WHEN や DOループサブルーチンなどの機能はせっかくなので活用してみました。

/*                                                      */                      
/*   CRTBNDCL PGM(NETSTAT/GETNSDATAC)                   */                      
/*            SRCFILE(NETSTAT/QCLSRC) DBGVIEW(*SOURCE)  */                      
/*                                                      */                      
                                                                                
             PGM        PARM(&LADDR &LPORT &RADDR &RPORT &INTERVAL +            
                          &OPTION &TARGET &ENDTIME)                             
                                                                                
             DCL        VAR(&OPTION) TYPE(*CHAR) LEN(6)                         
             DCL        VAR(&TIME) TYPE(*CHAR) LEN(6)                           
             DCL        VAR(&ENDTIME) TYPE(*CHAR) LEN(6)                        
             DCL        VAR(&INTERVAL) TYPE(*DEC) LEN(3 0)                      
             DCL        VAR(&COUNT) TYPE(*DEC) LEN(5 0)                         
             DCL        VAR(&COUNTC) TYPE(*CHAR) LEN(5) VALUE('0')              
             DCL        VAR(&TARGET) TYPE(*DEC) LEN(5 0)                        
             DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)                          
             DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(64) VALUE(' ')             
             DCL        VAR(&JOBTYPE) TYPE(*CHAR) LEN(1)                        
             DCL        VAR(&LPORT) TYPE(*DEC) LEN(5 0)                         
             DCL        VAR(&LPORTC) TYPE(*CHAR) LEN(5)                         
             DCL        VAR(&RPORT) TYPE(*DEC) LEN(5 0)                         
             DCL        VAR(&RPORTC) TYPE(*CHAR) LEN(5)                         
             DCL        VAR(&LADDR) TYPE(*CHAR) LEN(15)                         
             DCL        VAR(&RADDR) TYPE(*CHAR) LEN(15)                         
                                                                                
             DCL        VAR(&I) TYPE(*INT)                                      
             DCL        VAR(&ENDFLAG) TYPE(*LGL) VALUE('0')                     
                                                                                
             IF         COND(&INTERVAL = 0) THEN(GOTO CMDLBL(EXIT))             
             SELECT                                                             
             WHEN       COND(&OPTION = '*COUNT') THEN(DO)                       
             IF         COND(&TARGET = 0) THEN(GOTO CMDLBL(EXIT))               
             ENDDO                                                              
             WHEN       COND(&OPTION = '*TIME') THEN(DO)                        
             IF         COND(&ENDTIME = '000000') THEN(GOTO +                   
                          CMDLBL(EXIT))                                         
             RTVSYSVAL  SYSVAL(QTIME) RTNVAR(&TIME)                             
             IF         COND(&TIME > &ENDTIME) THEN(GOTO CMDLBL(EXIT))          
             ENDDO                                                              
             ENDSELECT              
                                            
             CHGVAR     VAR(&COUNT) VALUE(0)                                    
             RTVJOBA    TYPE(&JOBTYPE)                                          
             IF         COND(&LPORT = 0) THEN(CHGVAR VAR(&LPORTC) +             
                          VALUE(' '))                                           
             ELSE       CMD(CHGVAR VAR(&LPORTC) VALUE(&LPORT))                  
             IF         COND(&RPORT = 0) THEN(CHGVAR VAR(&RPORTC) +             
                          VALUE(' '))                                           
             ELSE       CMD(CHGVAR VAR(&RPORTC) VALUE(&RPORT))                  
                                                                                
             DOUNTIL    COND(&ENDFLAG = '1')                                    
             CALL       PGM(NETSTAT/GETNETSTAT) PARM(&LADDR &LPORTC +            
                          &RADDR &RPORTC)                                       
             CHGVAR     VAR(&COUNT) VALUE(&COUNT + 1)                           
             CALLSUBR   SUBR(TRIMZERO)                                          
          /* SUBR(TRIMZERO) DOES CHGVAR AND        */                           
          /*                REMOVES TRADING ZEROS  */                           
          /* CHGVAR     VAR(&COUNTC) VALUE(&COUNT) */                           
             CHGVAR     VAR(&MSGDTA) VALUE(&COUNTC |< +                         
                          ' 回目のデータを取得しました ')                    
             CHGVAR     VAR(&MSGID) VALUE(CPF9898)                              
             SNDPGMMSG  MSGID(&MSGID) MSGF(QCPFMSG) MSGDTA(&MSGDTA) +           
                          TOPGMQ(*EXT) MSGTYPE(*STATUS)                         
             IF         COND(&JOBTYPE = '0') THEN(DO)                           
             SNDPGMMSG  MSGID(&MSGID) MSGF(QCPFMSG) MSGDTA(&MSGDTA) +           
                          TOPGMQ(*EXT) MSGTYPE(*INFO)                           
             ENDDO                                                              
             SELECT                                                             
             WHEN       COND(&OPTION = '*COUNT') THEN(DO)                       
             IF         COND(&COUNT = &TARGET) THEN(CHGVAR +                    
                          VAR(&ENDFLAG) VALUE('1'))                             
             ENDDO                                                              
             WHEN       COND(&OPTION = '*TIME') THEN(DO)                        
             RTVSYSVAL  SYSVAL(QTIME) RTNVAR(&TIME)                             
             IF         COND(&TIME > &ENDTIME) THEN(CHGVAR +                    
                          VAR(&ENDFLAG) VALUE('1'))                             
             IF         COND(&TIME = &ENDTIME) THEN(CHGVAR +                    
                          VAR(&ENDFLAG) VALUE('1'))                             
             ENDDO                                                              
             ENDSELECT                                                          
             IF         COND(&ENDFLAG = '0') THEN(DLYJOB +                      
                          DLY(&INTERVAL))                                       
             ENDDO  /* DO UNTIL */                                              
                                                                                
 EXIT:       CHGVAR     VAR(&MSGDTA) VALUE(&COUNTC |< +                         
                          ' 件データを取得しました ')                    
             CHGVAR     VAR(&MSGID) VALUE(CPF9898)                              
             SNDPGMMSG  MSGID(&MSGID) MSGF(QCPFMSG) MSGDTA(&MSGDTA) +           
                          MSGTYPE(*INFO)                                        
                                                                                
             SUBR       SUBR(TRIMZERO)                                          
             CHGVAR     VAR(&COUNTC) VALUE(&COUNT)                              
             DOFOR      VAR(&I) FROM(1) TO(4) BY(1)                             
             IF         COND(%SST(&COUNTC &I 1) = '0') THEN(CHGVAR +            
                          VAR(%SST(&COUNTC &I 1)) VALUE(' '))                   
             ELSE       CMD(LEAVE)                                              
             ENDDO                                                              
             ENDSUBR                                                            
                                                                                
             ENDPGM                                                             

先行ゼロをブランクに

NETSTAT 情報を取得するたびにカウントを状況メッセージで表示するようにしているのですが、サブルーチンの中で先行ゼロをブランクに変換させています。

             SUBR       SUBR(TRIMZERO)                                          
             CHGVAR     VAR(&COUNTC) VALUE(&COUNT)                              
             DOFOR      VAR(&I) FROM(1) TO(4) BY(1)                             
             IF         COND(%SST(&COUNTC &I 1) = '0') THEN(CHGVAR +            
                          VAR(%SST(&COUNTC &I 1)) VALUE(' '))                   
             ELSE       CMD(LEAVE)                                              
             ENDDO                                                              
             ENDSUBR                                                            

GOTO

対応していないリリースでも参考になるように、↑の DOUNTIL をトラディショナルなスタイルに書き直したものもついでに載せておきますね。
ブランク変換をはずしてしまえば DO ループやサブルーチンもなくなるので、V5R4 でなくても動くようにはできるでしょう。

/*                                                      */                      
/*   CRTBNDCL PGM(NETSTAT/GETNSDATAC)                   */                      
/*            SRCFILE(NETSTAT/QCLSRC) DBGVIEW(*SOURCE)  */                      
/*                                                      */                      
                                                                                
             PGM        PARM(&LADDR &LPORT &RADDR &RPORT &INTERVAL +            
                          &OPTION &TARGET &ENDTIME)                             
                                                                                
             DCL        VAR(&OPTION) TYPE(*CHAR) LEN(6)                         
             DCL        VAR(&TIME) TYPE(*CHAR) LEN(6)                           
             DCL        VAR(&ENDTIME) TYPE(*CHAR) LEN(6)                        
             DCL        VAR(&INTERVAL) TYPE(*DEC) LEN(3 0)                      
             DCL        VAR(&COUNT) TYPE(*DEC) LEN(5 0)                         
             DCL        VAR(&COUNTC) TYPE(*CHAR) LEN(5) VALUE('0')              
             DCL        VAR(&TARGET) TYPE(*DEC) LEN(5 0)                        
             DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)                          
             DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(64) VALUE(' ')             
             DCL        VAR(&JOBTYPE) TYPE(*CHAR) LEN(1)                        
             DCL        VAR(&LPORT) TYPE(*DEC) LEN(5 0)                         
             DCL        VAR(&LPORTC) TYPE(*CHAR) LEN(5)                         
             DCL        VAR(&RPORT) TYPE(*DEC) LEN(5 0)                         
             DCL        VAR(&RPORTC) TYPE(*CHAR) LEN(5)                         
             DCL        VAR(&LADDR) TYPE(*CHAR) LEN(15)                         
             DCL        VAR(&RADDR) TYPE(*CHAR) LEN(15)                         
                                                                                
             DCL        VAR(&I) TYPE(*INT)                                      
                                                                                
             IF         COND(&INTERVAL = 0) THEN(GOTO CMDLBL(EXIT))             
             SELECT                                                             
             WHEN       COND(&OPTION = '*COUNT') THEN(DO)                       
             IF         COND(&TARGET = 0) THEN(GOTO CMDLBL(EXIT))               
             ENDDO                                                              
             WHEN       COND(&OPTION = '*TIME') THEN(DO)                        
             IF         COND(&ENDTIME = '000000') THEN(GOTO +                   
                          CMDLBL(EXIT))                                         
             RTVSYSVAL  SYSVAL(QTIME) RTNVAR(&TIME)                             
             IF         COND(&TIME > &ENDTIME) THEN(GOTO CMDLBL(EXIT))          
             ENDDO                                                              
             ENDSELECT                                                          

             CHGVAR     VAR(&COUNT) VALUE(0)                                    
             RTVJOBA    TYPE(&JOBTYPE)                                          
             IF         COND(&LPORT = 0) THEN(CHGVAR VAR(&LPORTC) +             
                          VALUE(' '))                                           
             ELSE       CMD(CHGVAR VAR(&LPORTC) VALUE(&LPORT))                  
             IF         COND(&RPORT = 0) THEN(CHGVAR VAR(&RPORTC) +             
                          VALUE(' '))                                           
             ELSE       CMD(CHGVAR VAR(&RPORTC) VALUE(&RPORT))      
            
 GETDATA:    CALL       PGM(NETSTAT/GETNETSTAT) PARM(&LADDR &LPORTC +            
                          &RADDR &RPORTC)                                       
             CHGVAR     VAR(&COUNT) VALUE(&COUNT + 1)                           
             CALLSUBR   SUBR(TRIMZERO)                                          
          /* SUBR(TRIMZERO) DOES CHGVAR AND        */                           
          /*                REMOVES TRADING ZEROS  */                           
          /* CHGVAR     VAR(&COUNTC) VALUE(&COUNT) */                           
             CHGVAR     VAR(&MSGDTA) VALUE(&COUNTC |< +      
                          ' 回目のデータを取得しました ')                    
             CHGVAR     VAR(&MSGID) VALUE(CPF9898)                              
             SNDPGMMSG  MSGID(&MSGID) MSGF(QCPFMSG) MSGDTA(&MSGDTA) +           
                          TOPGMQ(*EXT) MSGTYPE(*STATUS)                         
             IF         COND(&JOBTYPE = '0') THEN(DO)                           
             SNDPGMMSG  MSGID(&MSGID) MSGF(QCPFMSG) MSGDTA(&MSGDTA) +           
                          TOPGMQ(*EXT) MSGTYPE(*INFO)                           
             ENDDO                                                              
             SELECT                                                             
             WHEN       COND(&OPTION = '*COUNT') THEN(DO)                       
             IF         COND(&COUNT = &TARGET) THEN(GOTO CMDLBL(EXIT))          
             ENDDO                                                              
             WHEN       COND(&OPTION = '*TIME') THEN(DO)                        
             RTVSYSVAL  SYSVAL(QTIME) RTNVAR(&TIME)                             
             IF         COND(&TIME > &ENDTIME) THEN(GOTO CMDLBL(EXIT))          
             IF         COND(&TIME = &ENDTIME) THEN(GOTO CMDLBL(EXIT))          
             ENDDO                                                              
             ENDSELECT                                                          
             DLYJOB     DLY(&INTERVAL)                                          
             GOTO       CMDLBL(GETDATA)                                         
                                                                                
 EXIT:       CHGVAR     VAR(&MSGDTA) VALUE(&COUNTC |< +       
                          ' 件データを取得しました ')                    
             CHGVAR     VAR(&MSGID) VALUE(CPF9898)                              
             SNDPGMMSG  MSGID(&MSGID) MSGF(QCPFMSG) MSGDTA(&MSGDTA) +           
                          MSGTYPE(*INFO)                                        
                                                                                
             SUBR       SUBR(TRIMZERO)                                          
             CHGVAR     VAR(&COUNTC) VALUE(&COUNT)                              
             DOFOR      VAR(&I) FROM(1) TO(4) BY(1)                             
             IF         COND(%SST(&COUNTC &I 1) = '0') THEN(CHGVAR +            
                          VAR(%SST(&COUNTC &I 1)) VALUE(' '))                   
             ELSE       CMD(LEAVE)                                              
             ENDDO                                                              
             ENDSUBR                                                            
                                                                                
             ENDPGM                                                             

DOWHILE

DOUNTIL の終了条件を設定するためにフラグを使用していますが、あまりこうした非直接的なフラグのようなものを使用したくない、という印象を受ける人もいるかもしれませんね。

DOUNTIL については、内容はそのままにして、DOWHILE で条件が適合した時にループを抜ける、というように書きかえられます。そのバージョンが↓になりますので、こちらもよかったらご参考に。

ちなみに、DO WHILE での意図的な無限ループは、プログラミングではよく使用されます。決して"異常"なコーディングではありません。
たとえば、条件を満たすまでの繰り返し回数が不定な場合はそうせざるをありませんよね。
さらに言ってみれば、EOL の RPG での DO *HIVAL と同じものなので、昔ながらの人にはかえってわかりやすいかもしれませんね?!

/*                                                      */                      
/*   CRTBNDCL PGM(NETSTAT/GETNSDATAC)                   */                      
/*            SRCFILE(NETSTAT/QCLSRC) DBGVIEW(*SOURCE)  */                      
/*                                                      */                      
                                                                                
             PGM        PARM(&LADDR &LPORT &RADDR &RPORT &INTERVAL +            
                          &OPTION &TARGET &ENDTIME)                             
                                                                                
             DCL        VAR(&OPTION) TYPE(*CHAR) LEN(6)                         
             DCL        VAR(&TIME) TYPE(*CHAR) LEN(6)                           
             DCL        VAR(&ENDTIME) TYPE(*CHAR) LEN(6)                        
             DCL        VAR(&INTERVAL) TYPE(*DEC) LEN(3 0)                      
             DCL        VAR(&COUNT) TYPE(*DEC) LEN(5 0)                         
             DCL        VAR(&COUNTC) TYPE(*CHAR) LEN(5) VALUE('0')              
             DCL        VAR(&TARGET) TYPE(*DEC) LEN(5 0)                        
             DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)                          
             DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(64) VALUE(' ')             
             DCL        VAR(&JOBTYPE) TYPE(*CHAR) LEN(1)                        
             DCL        VAR(&LPORT) TYPE(*DEC) LEN(5 0)                         
             DCL        VAR(&LPORTC) TYPE(*CHAR) LEN(5)                         
             DCL        VAR(&RPORT) TYPE(*DEC) LEN(5 0)                         
             DCL        VAR(&RPORTC) TYPE(*CHAR) LEN(5)                         
             DCL        VAR(&LADDR) TYPE(*CHAR) LEN(15)                         
             DCL        VAR(&RADDR) TYPE(*CHAR) LEN(15)                         
                                                                                
             DCL        VAR(&I) TYPE(*INT)                                      
                                                                                
             IF         COND(&INTERVAL = 0) THEN(GOTO CMDLBL(EXIT))             
             SELECT                                                             
             WHEN       COND(&OPTION = '*COUNT') THEN(DO)                       
             IF         COND(&TARGET = 0) THEN(GOTO CMDLBL(EXIT))               
             ENDDO                                                              
             WHEN       COND(&OPTION = '*TIME') THEN(DO)                        
             IF         COND(&ENDTIME = '000000') THEN(GOTO +                   
                          CMDLBL(EXIT))                                         
             RTVSYSVAL  SYSVAL(QTIME) RTNVAR(&TIME)                             
             IF         COND(&TIME > &ENDTIME) THEN(GOTO CMDLBL(EXIT))          
             ENDDO                                                              
             ENDSELECT                                                          
             CHGVAR     VAR(&COUNT) VALUE(0)                                    
             RTVJOBA    TYPE(&JOBTYPE)                                          
             IF         COND(&LPORT = 0) THEN(CHGVAR VAR(&LPORTC) +             
                          VALUE(' '))                                           
             ELSE       CMD(CHGVAR VAR(&LPORTC) VALUE(&LPORT))                  
             IF         COND(&RPORT = 0) THEN(CHGVAR VAR(&RPORTC) +             
                          VALUE(' '))                                           
             ELSE       CMD(CHGVAR VAR(&RPORTC) VALUE(&RPORT))                  
                                                                                
             DOWHILE    COND(1 = 1)  /* 無限ループ */                            
             CALL       PGM(NETSTAT/GETNETSTAT) PARM(&LADDR &LPORTC + 
                          &RADDR &RPORTC)                              
             CHGVAR     VAR(&COUNT) VALUE(&COUNT + 1)                 
             CALLSUBR   SUBR(TRIMZERO)                                  
          /* SUBR(TRIMZERO) DOES CHGVAR AND        */                    
          /*                REMOVES TRADING ZEROS  */                  
          /* CHGVAR     VAR(&COUNTC) VALUE(&COUNT) */                 
             CHGVAR     VAR(&MSGDTA) VALUE(&COUNTC |< +                
                          ' 回目のデータを取得しました ')             
             CHGVAR     VAR(&MSGID) VALUE(CPF9898)                     
             SNDPGMMSG  MSGID(&MSGID) MSGF(QCPFMSG) MSGDTA(&MSGDTA) +  
                          TOPGMQ(*EXT) MSGTYPE(*STATUS)                  
             IF         COND(&JOBTYPE = '0') THEN(DO)                      
             SNDPGMMSG  MSGID(&MSGID) MSGF(QCPFMSG) MSGDTA(&MSGDTA) +   
                          TOPGMQ(*EXT) MSGTYPE(*INFO)                     
             ENDDO                                                      
             SELECT                                                   
             WHEN       COND(&OPTION = '*COUNT') THEN(DO)            
             IF         COND(&COUNT = &TARGET) THEN(LEAVE)            
             ENDDO                                                     
             WHEN       COND(&OPTION = '*TIME') THEN(DO)                
             RTVSYSVAL  SYSVAL(QTIME) RTNVAR(&TIME)                    
             IF         COND(&TIME > &ENDTIME) THEN(LEAVE)                
             IF         COND(&TIME = &ENDTIME) THEN(LEAVE)                 
             ENDDO                                                       
             ENDSELECT                                                  
             DLYJOB     DLY(&INTERVAL)                                  
             ENDDO  /* DO WHILE */                                              
                                                                           
 EXIT:       CHGVAR     VAR(&MSGDTA) VALUE(&COUNTC |< +                     
                         ' 件データを取得しました ')                   
             CHGVAR     VAR(&MSGID) VALUE(CPF9898)                         
             SNDPGMMSG  MSGID(&MSGID) MSGF(QCPFMSG) MSGDTA(&MSGDTA) +           
                          MSGTYPE(*INFO)                                        
                                                                                
             SUBR       SUBR(TRIMZERO)                                          
             CHGVAR     VAR(&COUNTC) VALUE(&COUNT)                              
             DOFOR      VAR(&I) FROM(1) TO(4) BY(1)                             
             IF         COND(%SST(&COUNTC &I 1) = '0') THEN(CHGVAR +            
                          VAR(%SST(&COUNTC &I 1)) VALUE(' '))                   
             ELSE       CMD(LEAVE)                                              
             ENDDO                                                              
             ENDSUBR                                                            
                                                                             
             ENDPGM                                                         

結果の確認

モニターの結果として出力されたテーブルに対する検索は、たとえばこんな SQL で行うことができます。

各時間ごとの接続数

SELECT DATE(INQUIRED_DATE),
       TIME(INQUIRED_DATE), 
       COUNT(*) 
  FROM NETSTAT/NETSTAT_INF 
 GROUP BY DATE(INQUIRED_DATE),TIME(INQUIRED_DATE)
 ORDER BY DATE(INQUIRED_DATE),TIME(INQUIRED_DATE)

各時間のポート毎の接続数

SELECT DATE(INQUIRED_DATE),
       TIME(INQUIRED_DATE), 
       LOCAL_PORT ,
       COUNT(*) 
  FROM NETSTAT/NETSTAT_INF 
 GROUP BY  DATE(INQUIRED_DATE),TIME(INQUIRED_DATE), LOCAL_PORT,
 ORDER BY  DATE(INQUIRED_DATE),TIME(INQUIRED_DATE), LOCAL_PORT

↑の SQL をポートのいくつかをわかりやすいように名前で表すようにしたもの

SELECT 
       DATE(INQUIRED_DATE), 
       TIME(INQUIRED_DATE),              
       CASE                                               
          WHEN LOCAL_PORT = '8471' THEN 'database'          
          WHEN LOCAL_PORT = '8475' THEN 'rmtcmd'   
          WHEN LOCAL_PORT = '8476' THEN 'signon'      
          WHEN LOCAL_PORT = '449' THEN 'svrmap'              
          ELSE LOCAL_PORT END AS PORT, 
       COUNT(*) 
  FROM NETSTAT/NETSTAT_INF 
 GROUP BY DATE(INQUIRED_DATE),TIME(INQUIRED_DATE), LOCAL_PORT
 ORDER BY DATE(INQUIRED_DATE),TIME(INQUIRED_DATE), LOCAL_PORT

[Top Pageに戻る]

Ads by TOK2