星期一, 11月 06, 2023

2003-08-06 TCPIP SOCKET RPG 程式範例(Echo server)


TCPIP SOCKET RPG 程式範例(Echo server)

前期電子報介紹 RPG SOCKET 程式的參考資訊,各位先進應該看完了吧。

本期我以一個 Echo server 來當作範例,並提供一隻 echo client rpg 程式讓您測試,
當然您也可以直接利用 telnet 程式測試。

此 Echo server socket 程式啟動後會依照所傳參數(AS/400 host ip 及 port number),
將之 bind 連結到 socket  中,然後 listen 傾聽所指定的 port 有無 client 端連線
需求,如果有就 accept 接受連結,接著傳送連結訊息至 client 端,接著等待 client 
輸入任何字串,當 client 端輸入訊息並傳送出去後,Echo server 收到厚利即將原字串
傳回 client 端。當 client 輸入 QUIT 字串時,Echo server 會將此連線中斷,並等待
下一個 client 提出連線需求。
整個流程如下:

    Echo Server           Echo Client

    Create socket         Create socket

    Bind                  Bind(可有可無)

    Listen

 --> Accept   <---------   Connect
 |
 |   Send      --------->  Receive
 |    /\                    ||
 |    ||                    \/
 |   Receive  <----------  Send 
 |   "QUIT"               "QUIT"    
 |    ||                    ||
 |    \/                    \/
 |  Close                 Close
 |  Client socket
 |    ||
 |    \/ 
 ------


File  : QRPGLESRC
Member: SOCKETSVRR  (Echo Server)
Type  : RPGLE
Usage : CRTBNDRPG SOCKETSVRR
OS version: V4R1

     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('QC2LE')
     H Debug
     D Cmd             PR                  ExtPgm('QCMDEXC')
     D   command                    200A   const
     D   length                      15P 5 const

      *-------------------------------------------------------------------
      * prototype definitions
      *-------------------------------------------------------------------
     D @__errno        PR              *   ExtProc('__errno')

     D strerror        PR              *   ExtProc('strerror')
     D    errnum                     10I 0 value

     D perror          PR                  ExtProc('perror')
     D    comment                      *   value options(*string)

     D errno           PR            10I 0

      *-------------------------------------------------------------------
      * socket C API prototype definitions
      *-------------------------------------------------------------------
     D getservbyname   PR              *   ExtProc('getservbyname')
     D  service_name                   *   value options(*string)
     D  protocol_name                  *   value options(*string)

     D p_servent       S               *
     D servent         DS                  based(p_servent)
     D   s_name                        *
     D   s_aliases                     *
     D   s_port                      10I 0
     D   s_proto                       *

     D inet_addr       PR            10U 0 ExtProc('inet_addr')
     D  address_str                    *   value options(*string)

     D INADDR_NONE     C                   CONST(4294967295)
     D*                                                any address available
     D INADDR_ANY      C                   CONST(0)

     D inet_ntoa       PR              *   ExtProc('inet_ntoa')
     D  internet_addr                10U 0 value

     D p_hostent       S               *
     D hostent         DS                  Based(p_hostent)
     D   h_name                        *
     D   h_aliases                     *
     D   h_addrtype                  10I 0
     D   h_length                    10I 0
     D   h_addr_list                   *
     D p_h_addr        S               *   Based(h_addr_list)
     D h_addr          S             10U 0 Based(p_h_addr)

     D p_linger        S               *
     D linger          DS                  BASED(p_linger)
     D   l_onoff                     10I 0
     D   l_linger                    10I 0

     D gethostbyname   PR              *   extproc('gethostbyname')
     D   host_name                     *   value options(*string)

     D socket          PR            10I 0 ExtProc('socket')
     D  addr_family                  10I 0 value
     D  type                         10I 0 value
     D  protocol                     10I 0 value

     D AF_INET         C                   CONST(2)
     D SOCK_STREAM     C                   CONST(1)
     D IPPROTO_IP      C                   CONST(0)

     D bind            PR            10I 0 ExtProc('bind')
     D   Sock_Desc                   10I 0 Value
     D   p_Address                     *   Value
     D   AddressLen                  10I 0 Value

     D Select          PR            10I 0 extproc('select')
     D   max_desc                    10I 0 VALUE
     D   read_set                      *   VALUE
     D   write_set                     *   VALUE
     D   except_set                    *   VALUE
     D   wait_Time                     *   VALUE

     D listen          PR            10I 0 ExtProc('listen')
     D   SocketDesc                  10I 0 Value
     D   Back_Log                    10I 0 Value

     D accept          PR            10I 0 ExtProc('accept')
     D   Sock_Desc                   10I 0 Value
     D   p_Address                     *   Value
     D   p_AddrLen                   10I 0

     D connect         PR            10I 0 ExtProc('connect')
     D  sock_desc                    10I 0 value
     D  dest_addr                      *   value
     D  addr_len                     10I 0 value

     D p_sockaddr      S               *
     D sockaddr        DS                  based(p_sockaddr)
     D   sa_family                    5I 0
     D   sa_data                     14A
     D sockaddr_in     DS                  based(p_sockaddr)
     D   sin_family                   5I 0
     D   sin_port                     5U 0
     D   sin_addr                    10U 0
     D   sin_zero                     8A

     D send            PR            10I 0 ExtProc('send')
     D   sock_desc                   10I 0 value
     D   buffer                        *   value
     D   buffer_len                  10I 0 value
     D   flags                       10I 0 value

     D recv            PR            10I 0 ExtProc('recv')
     D   sock_desc                   10I 0 value
     D   buffer                        *   value
     D   buffer_len                  10I 0 value
     D   flags                       10I 0 value

     D close           PR            10I 0 ExtProc('close')
     D  sock_desc                    10I 0 value

     D setsockopt      PR            10I 0 ExtProc('setsockopt')
     D   SocketDesc                  10I 0 Value
     D   Opt_Level                   10I 0 Value
     D   Opt_Name                    10I 0 Value
     D   Opt_Value                     *   Value
     D   Opt_Len                     10I 0 Value

     D translate       PR                  ExtPgm('QDCXLATE')
     D   length                       5P 0 const
     D   data                     32766A   options(*varsize)
     D   table                       10A   const

     D die             PR
     D   peMsg                      256A   const
     D*                                                socket layer
     D SOL_SOCKET      C                   CONST(-1)
     D*                                                re-use local address
     D SO_REUSEADDR    C                   55
     D*                                          linger upon close
     D SO_LINGER       C                   30

     D msg             S             50A
     D sock            S             10I 0
     D port            S              5U 0
     D addrlen         S             10I 0
     D ch              S              1A
     D local           s             32A
     D localportc      s              5A
     D IPLocal         s             10U 0
     D p_bindto        S               *
     D p_Connfrom      S               *
     D lsock           S             10I 0
     D csock           S             10I 0
     D RC              S             10I 0
     D Request         S             50A
     D ReqLen          S             10I 0
     D RecBuf          S             50A
     D RecLen          S             10I 0
     D on              S             10I 0 inz(1)
     D err             S             10I 0
     D clientip        S             17A
     D line            S             80A
     D ling            S               *
     D linglen         S             10I 0

     C*************************************************
     C* The user will supply a hostname and port
     C*  for client connect
     C*************************************************
     c     *entry        plist
     c                   parm                    local
     c                   parm                    localportc

     c                   eval      *inlr = *on

     c                   exsr      MakeListener

     c                   dow       1 = 1
     c                   exsr      AcceptConn
     c                   exsr      TalkToClient
     c                   callp     close(csock)
     c                   enddo

     C*===============================================================
     C* This subroutine sets up a socket to listen for connections
     C* include socket, bind, listen API
     C*===============================================================
     CSR   MakeListener  begsr
      *
     C* Get the 32-bit network IP address for
     C* local that was supplied by the user:
      *
     c                   If        local <> *blanks
     c                   eval      IPLocal = inet_addr(%trim(local))
     c                   if        IPLocal = INADDR_NONE
     c                   eval      p_hostent = gethostbyname(%trim(local))
     c                   if        p_hostent = *NULL
     c                   callp     die('Unable to find that local!')
     c                   return
     c                   endif
     c                   eval      IPLocal = h_addr
     c                   endif
     c                   Else
     c                   eval      IPlocal = INADDR_ANY
     c                   EndIf
     c
     c                   if        localportc <> *blanks
     c                   move      localportc    port
     c                   else
     c                   callp     die('Wrong port specified !')
     c                   return
     c                   endif

     C* Create a socket
     c                   eval      sock = socket(AF_INET: SOCK_STREAM:
     c                                           IPPROTO_IP)
     c                   if        sock < 0
     c                   callp     die('socket(): ' + %str(strerror(errno)))
     c                   return
     c                   endif

     C*** Tell socket that we want to be able to re-use the server
     C***  port without waiting for the MSL timeout:
     c                   callp     setsockopt(sock: SOL_SOCKET:
     c                                SO_REUSEADDR: %addr(on): %size(on))

     C* create space for a linger structure
     c                   eval      linglen = %size(linger)
     c                   alloc     linglen       ling
     c                   eval      p_linger = ling

     C* tell socket to only linger for 2 minutes, then discard:
     c                   eval      l_onoff = 1
     c                   eval      l_linger = 1
     c                   callp     setsockopt(lsock: SOL_SOCKET: SO_LINGER:
     c                                ling: linglen)

     C* bind the socket to local port , of any IP address
     C* Allocate some space for some socket addresses
     c                   eval      addrlen = %size(sockaddr_in)
     c                   alloc     addrlen       p_bindto
     c                   alloc     addrlen       p_connfrom

     c                   eval      p_sockaddr = p_bindto

     c                   move      localportc    port
     c                   eval      sin_family = AF_INET
     c                   eval      sin_addr = IPLocal
     c                   eval      sin_port = port
     c                   eval      sin_zero = *ALLx'00'

     c                   if        bind(sock: p_bindto: addrlen) < 0
     c                   eval      err = errno
     c                   callp     close(sock)
     c                   callp     die('bind(): ' + %str(strerror(err)))
     c                   return
     c                   endif

     C* Indicate that we want to listen for connections
     c                   if        listen(sock: 5) < 0
     c                   eval      err = errno
     c                   callp     close(sock)
     c                   callp     die('listen(): ' + %str(strerror(err)))
     c                   return
     c                   endif
     C
     CSR                 endsr
     C*===============================================================
     C* This subroutine accepts a new socket connection
     C*===============================================================
     CSR   AcceptConn    begsr
     C*------------------------
     c                   dou       addrlen = %size(sockaddr_in)

     C* Accept the next connection.
     c                   eval      addrlen = %size(sockaddr_in)
     c                   eval      csock = accept(sock: p_connfrom: addrlen)
     c                   if        csock < 0
     c                   eval      err = errno
     c                   callp     close(sock)
     c                   callp     die('accept(): ' + %str(strerror(err)))
     c                   return
     c                   endif

     C* tell socket to only linger for 2 minutes, then discard:
     c                   eval      l_onoff = 1
     c                   eval      l_linger = 120
     c                   callp     setsockopt(csock: SOL_SOCKET: SO_LINGER:
     c                                ling: linglen)

     C* If socket length is not 16, then the client isn't sending the
     C*  same address family as we are using...  that scares me, so
     C*  we'll kick that guy off.
     c                   if        addrlen <> %size(sockaddr_in)
     c                   callp     close(csock)
     c                   endif

     c                   enddo

     c                   eval      p_sockaddr = p_connfrom
     c                   eval      clientip = %str(inet_ntoa(sin_addr))
     c     clientip      dsply
     C*------------------------
     CSR                 endsr
     C*===============================================================
     C*  This does a quick little conversation with the connecting
     c*  client.
     C*===============================================================
     CSR   TalkToClient  begsr
     C*------------------------
     c                   eval      line ='Connection from ' +
     c                                   %trim(clientip)
     c                   exsr      WrLine
     c                   eval      line ='Please enter your name now!'
     c                   exsr      WrLine

     c                   eval      recbuf = *blanks
     c                   Dow       %SubSt(recbuf : 1 : 4) <> 'QUIT'
     c                   exsr      RdLine
     c                   If        reclen > 0
     c                   eval      line = 'Server response: ' + recbuf
     c                   exsr      WrLine
     c                   EndIf
     c                   Enddo

     c                   eval      line ='Goodbye '
     c                   exsr      WrLine

     c                   dealloc(E)              p_connfrom
     c                   callp     Cmd('DLYJOB DLY(1)': 200)

     C*------------------------
     CSR                 endsr
     C*===============================================================
     C* This subroutine send data to socket client with CRLF
     C*===============================================================
     CSR   WrLine        begsr

     c                   eval      reqlen = %len(%trim(line))
     c                   callp     Translate(reqlen: line: 'QTCPASC')
     c                   eval      line = %trim(line) + X'0D0A'
     c                   eval      reqlen = %len(%trim(line))
     c*    'dmptxt'      dump
     c                   eval      rc= send(csock: %addr(line): reqlen:0)
     c                   if        rc < reqlen
     c                   callp     close(csock)
     c                   callp     die('Unable to send entire request!')
     c                   return
     c                   endif

     CSR                 endsr
     C*===============================================================
     C* This subroutine receives what we send to server and
     C*  displays it on the screen using the DSPLY op-code
     C*===============================================================
     CSR   RdLine        begsr
     C*------------------------
     C*************************************************
     C* Receive one line of text from the socket client
     C*  note that "lines of text" vary in length,
     C*  but always end with the ASCII values for CR
     C*  and LF.  CR = x'0D' and LF = x'0A'
     C*
     C* The easiest way for us to work with this data
     C* is to receive it one byte at a time until we
     C* get the LF character.   Each time we receive
     C* a byte, we add it to our receive buffer.
     C*************************************************
     c                   eval      reclen = 0
     c                   eval      recbuf = *blanks

     c                   dou       reclen = 80 or ch = x'0A'
     c                   eval      rc = recv(csock: %addr(ch): 1: 0)
     c                   if        rc < 1
     c     'rcvfail'     dsply
     c                   callp     close(csock)
     c                   callp     die('Unable to receive data !')
     c                   return
     c                   endif
     c                   if        ch<>x'0D' and ch<>x'0A'
     c                   eval      reclen = reclen + 1
     c                   eval      %subst(recbuf:reclen:1) = ch
     c                   endif
     c                   enddo

     C*************************************************
     C* translate the line of text into EBCDIC
     C* (to make it readable) and display it
     C*************************************************
     c                   if        reclen > 0
     c                   callp     Translate(reclen: recbuf: 'QTCPEBC')
     c     recbuf        dsply
     c                   endif
     C*------------------------
     Csr                 endsr

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      *  This ends this program abnormally, and sends back an escape.
      *   message explaining the failure.
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P die             B
     D die             PI
     D   peMsg                      256A   const

     D SndPgmMsg       PR                  ExtPgm('QMHSNDPM')
     D   MessageID                    7A   Const
     D   QualMsgF                    20A   Const
     D   MsgData                    256A   Const
     D   MsgDtaLen                   10I 0 Const
     D   MsgType                     10A   Const
     D   CallStkEnt                  10A   Const
     D   CallStkCnt                  10I 0 Const
     D   MessageKey                   4A
     D   ErrorCode                32766A   options(*varsize)

     D dsEC            DS
     D  dsECBytesP             1      4I 0 INZ(256)
     D  dsECBytesA             5      8I 0 INZ(0)
     D  dsECMsgID              9     15
     D  dsECReserv            16     16
     D  dsECMsgDta            17    256

     D wwMsgLen        S             10I 0
     D wwTheKey        S              4A

     c                   eval      wwMsgLen = %len(%trimr(peMsg))
     c                   if        wwMsgLen<1
     c                   return
     c                   endif

     c                   callp     SndPgmMsg('CPF9897': 'QCPFMSG   *LIBL':
     c                               peMsg: wwMsgLen: '*ESCAPE':
     c                               '*PGMBDY': 1: wwTheKey: dsEC)

     c                   return
     P                 E
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      *  This procedure return call socket C API errno
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P errno           B
     D errno           PI            10I 0
     D p_errno         S               *
     D wwreturn        S             10I 0 based(p_errno)
     C                   eval      p_errno = @__errno
     c                   return    wwreturn
     P                 E


File  : QRPGLESRC
Member: SOCKETCLTR  (Echo Client)
Type  : RPGLE
Usage : CRTBNDRPG SOCKETCLTR
OS version: V4R1

     H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('QC2LE')
     H Debug
      *-------------------------------------------------------------------
      * prototype definitions
      *-------------------------------------------------------------------
     D @__errno        PR              *   ExtProc('__errno')

     D strerror        PR              *   ExtProc('strerror')
     D    errnum                     10I 0 value

     D perror          PR                  ExtProc('perror')
     D    comment                      *   value options(*string)

     D errno           PR            10I 0

      *-- Sleep --- Sleep function (delay job) ------------------------
      *   unsigned int sleep( unsigned int seconds );
     D sleep           Pr            10U 0 ExtProc('sleep')
     D                               10U 0 Value

      * socket C API prototype definitions
      *-------------------------------------------------------------------
     D getservbyname   PR              *   ExtProc('getservbyname')
     D  service_name                   *   value options(*string)
     D  protocol_name                  *   value options(*string)

     D p_servent       S               *
     D servent         DS                  based(p_servent)
     D   s_name                        *
     D   s_aliases                     *
     D   s_port                      10I 0
     D   s_proto                       *

     D inet_addr       PR            10U 0 ExtProc('inet_addr')
     D  address_str                    *   value options(*string)

     D INADDR_NONE     C                   CONST(4294967295)

     D inet_ntoa       PR              *   ExtProc('inet_ntoa')
     D  internet_addr                10U 0 value

     D p_hostent       S               *
     D hostent         DS                  Based(p_hostent)
     D   h_name                        *
     D   h_aliases                     *
     D   h_addrtype                  10I 0
     D   h_length                    10I 0
     D   h_addr_list                   *
     D p_h_addr        S               *   Based(h_addr_list)
     D h_addr          S             10U 0 Based(p_h_addr)

     D gethostbyname   PR              *   extproc('gethostbyname')
     D   host_name                     *   value options(*string)

     D socket          PR            10I 0 ExtProc('socket')
     D  addr_family                  10I 0 value
     D  type                         10I 0 value
     D  protocol                     10I 0 value

     D AF_INET         C                   CONST(2)
     D SOCK_STREAM     C                   CONST(1)
     D IPPROTO_IP      C                   CONST(0)

     D bind            PR            10I 0 ExtProc('bind')
     D   Sock_Desc                   10I 0 Value
     D   p_Address                     *   Value
     D   AddressLen                  10I 0 Value

     D connect         PR            10I 0 ExtProc('connect')
     D  sock_desc                    10I 0 value
     D  dest_addr                      *   value
     D  addr_len                     10I 0 value

     D p_sockaddr      S               *
     D sockaddr        DS                  based(p_sockaddr)
     D   sa_family                    5I 0
     D   sa_data                     14A
     D sockaddr_in     DS                  based(p_sockaddr)
     D   sin_family                   5I 0
     D   sin_port                     5U 0
     D   sin_addr                    10U 0
     D   sin_zero                     8A

     D send            PR            10I 0 ExtProc('send')
     D   sock_desc                   10I 0 value
     D   buffer                        *   value
     D   buffer_len                  10I 0 value
     D   flags                       10I 0 value

     D recv            PR            10I 0 ExtProc('recv')
     D   sock_desc                   10I 0 value
     D   buffer                        *   value
     D   buffer_len                  10I 0 value
     D   flags                       10I 0 value

     D close           PR            10I 0 ExtProc('close')
     D  sock_desc                    10I 0 value

     D setsockopt      PR            10I 0 ExtProc('setsockopt')
     D   SocketDesc                  10I 0 Value
     D   Opt_Level                   10I 0 Value
     D   Opt_Name                    10I 0 Value
     D   Opt_Value                     *   Value
     D   Opt_Len                     10I 0 Value

     D translate       PR                  ExtPgm('QDCXLATE')
     D   length                       5P 0 const
     D   data                     32766A   options(*varsize)
     D   table                       10A   const

     D die             PR
     D   peMsg                      256A   const
     D*                                                socket layer
     D SOL_SOCKET      C                   CONST(-1)
     D*                                                re-use local address
     D SO_REUSEADDR    C                   55

     D msg             S             50A
     D sock            S             10I 0
     D port            S              5U 0
     D addrlen         S             10I 0
     D ch              S              1A
     D host            s             32A
     D hostportc       s              5A
     D local           s             32A
     D localportc      s              5A
     D IPHost          s             10U 0
     D IPLocal         s             10U 0
     D p_bindto        S               *
     D p_Connto        S               *
     D RC              S             10I 0
     D Request         S             50A
     D ReqLen          S             10I 0
     D RecBuf          S             50A
     D RecLen          S             10I 0
     D on              S             10I 0 inz(1)
     D err             S             10I 0

     C*************************************************
     C* The user will supply a hostname and file
     C*  name as parameters to our program...
     C*************************************************
     c     *entry        plist
     c                   parm                    host
     c                   parm                    hostportc
     c                   parm                    local
     c                   parm                    localportc

     c                   eval      *inlr = *on

     c                   exsr      SktCnn
     c                   exsr      TalkToSktSvr

     C*************************************************
     C* SOCKET   CONNECTION
     C*************************************************
     C     SktCnn        BegSr
     C*************************************************
     C* Get the 32-bit network IP address for the host
     C* & local that was supplied by the user:
     C*************************************************
     c                   eval      IPHost = inet_addr(%trim(host))
     c                   if        IPHost = INADDR_NONE
     c                   eval      p_hostent = gethostbyname(%trim(host))
     c                   if        p_hostent = *NULL
     c                   callp     die('Unable to find that host!')
     c                   return
     c                   endif
     c                   eval      IPHost = h_addr
     c                   endif

     c                   If        local <> *blanks
     c                   eval      IPLocal = inet_addr(%trim(local))
     c                   if        IPLocal= INADDR_NONE
     c                   eval      p_hostent = gethostbyname(%trim(local))
     c                   if        p_hostent = *NULL
     c                   callp     die('Unable to find that local!')
     c                   return
     c                   endif
     c                   eval      IPLocal = h_addr
     c                   endif
     c                   endif

     C*************************************************
     C* Create a socket
     C*************************************************
     c                   eval      sock = socket(AF_INET: SOCK_STREAM:
     c                                           IPPROTO_IP)
     c                   if        sock < 0
     c                   callp     die('socket(): ' + %str(strerror(errno)))
     c                   return
     c                   endif

     C*** Tell socket that we want to be able to re-use the server
     C***  port without waiting for the MSL timeout:
     c                   callp     setsockopt(sock: SOL_SOCKET:
     c                                SO_REUSEADDR: %addr(on): %size(on))

     C                   if        local      <> *blanks  And
     C                             localportc <> *blanks
     C* bind the socket to local port , of any IP address
     C* Allocate some space for some socket addresses
     c                   eval      addrlen = %size(sockaddr_in)
     c                   alloc     addrlen       p_bindto
     c                   eval      p_sockaddr = p_bindto

     c                   move      localportc    port
     c                   eval      sin_family = AF_INET
     c                   eval      sin_addr = IPLocal
     c                   eval      sin_port = port
     c                   eval      sin_zero = *ALLx'00'
     c                   if        bind(sock: p_bindto: addrlen) < 0
     c                   eval      err = errno
     c                   callp     close(sock)
     c                   callp     die('bind(): ' + %str(strerror(err)))
     c                   return
     c                   endif
     c                   endif

     C*************************************************
     C* Create a socket address structure that
     C*   describes the host & port we wanted to
     C*   connect to
     C*************************************************
     c                   eval      addrlen = %size(sockaddr)
     c                   alloc     addrlen       p_connto
     c                   eval      p_sockaddr = p_connto

     c                   move      hostportc     port
     c                   eval      sin_family = AF_INET
     c                   eval      sin_addr = IPHost
     c                   eval      sin_port = port
     c                   eval      sin_zero = *ALLx'00'

     C*************************************************
     C* Connect to the requested host
     C*************************************************
     C                   if        connect(sock: p_connto: addrlen) < 0
     c                   eval      err = errno
     c                   callp     close(sock)
     c                   callp     die('Connect(): ' + %str(strerror(err)))
     c                   return
     c                   endif
     C                   EndSr

     C*************************************************
     C* TALK TO SOCKET SERVER
     C*************************************************
     C     TalktoSktSvr  BegSr
     C*************************************************
     C* Format a request and tralslate to ASCII and
     C* send to socket server depend on your purpose
     C*************************************************
     C                   Dow       *In99 = *Off
      * once connect , receive socket server
      * two welcome message
     c  N90              do        2
     C                   exsr      RecvResponse
     c                   eval      *In90 = *on
     c                   enddo
      * input anything you want
     c                   clear                   request
     c     'Input String'Dsply
     c                   Dsply                   request
     c                   eval      reqlen = %len(%trim(request))
     c                   If        reqlen = 0
     c                   iter
     c                   EndIf
     c                   If        %SubSt(request : 1 : 4) = 'QUIT'
     c                   eval      *In99 = *On
     c                   EndIf
     c*                  eval      request = 'Any data to send to socket server'
     c                   callp     Translate(reqlen: request: 'QTCPASC')

     C*************************************************
     c* Append ASCII X'0D0A' to request means end of
     C* line and send the request to the socket server
     C*************************************************
     c                   eval      request = %trim(request) + X'0D0A'
     c                   eval      reqlen = %len(%trim(request))
     c                   eval      rc = send(sock: %addr(request): reqlen:0)
     c                   if        rc < reqlen
     c                   callp     close(sock)
     c                   callp     die('Unable to send entire request!')
     c                   return
     c                   endif
     c*    'sended'      dsply

     C                   exsr      RecvResponse
     C*************************************************
     C* Get back the server's response
     C*************************************************

     C                   enddo
      * get 'GoodBye' message
     C                   exsr      RecvResponse
     C*************************************************
     C*  We're done, so close the socket.
     C*   do a dsply with input to pause the display
     C*   and then end the program
     C*************************************************
     c                   callp     close(sock)
     c                   dsply                   pause             1
     c                   return
     C                   EndSr

     C*===============================================================
     C* This subroutine receives what we send to server and
     C*  displays it on the screen using the DSPLY op-code
     C*===============================================================
     CSR   RecvResponse  begsr
     C*------------------------
     C*************************************************
     C* Receive one line of text from the socket server.
     C*  note that "lines of text" vary in length,
     C*  but always end with the ASCII values for CR
     C*  and LF.  CR = x'0D' and LF = x'0A'
     C*
     C* The easiest way for us to work with this data
     C* is to receive it one byte at a time until we
     C* get the LF character.   Each time we receive
     C* a byte, we add it to our receive buffer.
     C*************************************************
     c                   eval      reclen = 0
     c                   eval      recbuf = *blanks

     c                   dou       reclen = 50 or ch = x'0A'
     c                   eval      rc = recv(sock: %addr(ch): 1: 0)
     c                   if        rc < 1
     c                   leave
     c                   endif
     c                   if        ch<>x'0D' and ch<>x'0A'
     c                   eval      reclen = reclen + 1
     c                   eval      %subst(recbuf:reclen:1) = ch
     c                   endif
     c                   enddo

     C*************************************************
     C* translate the line of text into EBCDIC
     C* (to make it readable) and display it
     C*************************************************
     c                   if        reclen > 0
     c                   callp     Translate(reclen: recbuf: 'QTCPEBC')
     c                   endif
     c     recbuf        dsply
     C*------------------------
     Csr                 endsr

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      *  This ends this program abnormally, and sends back an escape.
      *   message explaining the failure.
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P die             B
     D die             PI
     D   peMsg                      256A   const

     D SndPgmMsg       PR                  ExtPgm('QMHSNDPM')
     D   MessageID                    7A   Const
     D   QualMsgF                    20A   Const
     D   MsgData                    256A   Const
     D   MsgDtaLen                   10I 0 Const
     D   MsgType                     10A   Const
     D   CallStkEnt                  10A   Const
     D   CallStkCnt                  10I 0 Const
     D   MessageKey                   4A
     D   ErrorCode                32766A   options(*varsize)

     D dsEC            DS
     D  dsECBytesP             1      4I 0 INZ(256)
     D  dsECBytesA             5      8I 0 INZ(0)
     D  dsECMsgID              9     15
     D  dsECReserv            16     16
     D  dsECMsgDta            17    256

     D wwMsgLen        S             10I 0
     D wwTheKey        S              4A

     c                   eval      wwMsgLen = %len(%trimr(peMsg))
     c                   if        wwMsgLen<1
     c                   return
     c                   endif

     c                   callp     SndPgmMsg('CPF9897': 'QCPFMSG   *LIBL':
     c                               peMsg: wwMsgLen: '*ESCAPE':
     c                               '*PGMBDY': 1: wwTheKey: dsEC)

     c                   return
     P                 E
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      *  This procedure return call socket C API errno
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P errno           B
     D errno           PI            10I 0
     D p_errno         S               *
     D wwreturn        S             10I 0 based(p_errno)
     C                   eval      p_errno = @__errno
     c                   return    wwreturn
     P                 E

執行方式:
1. 執行 Echo server
SBMJOB CMD(CALL SOCKETSVRR('your-as/400-ip' 'port')) JOB(SOCKETSVR)
or 
SBMJOB CMD(CALL PGM(SOCKETSVRR) PARM('172.16.15.35' '04000')) JOB(SOCKETSR)
                                          
2. 執行 Echo client
CALL PGM(SOCKETcltR) PARM('your-as/400 ip' 'port' 'local-as/400 ip' 'local port')
or 
CALL PGM(SOCKETCLTR) PARM('172.16.15.35' '04000' '172.16.15.35' '21000')
or
在 PC DOS 視窗上執行 telnet AS/400IPAddress PORT
telnet AS/400IP PORT
telnet 172.16.15.35 4000

本 Echo server 範例程式目前僅做 ASCII, EBCDIC 轉換,位支援 big5 中文轉換,
你可以使用 API iconv() 或 API QDCXLATE 轉換,或自行轉碼。 相關轉碼請參閱:
http://publib.boulder.ibm.com/iseries/v5r1/ic2924/info/apis/iconv.htm

http://publib.boulder.ibm.com/iseries/v5r1/ic2924/index.htm?info/apis/QDCXLATE.htm





沒有留言: