IBM Mainframe Forum Index
 
Log In
 
IBM Mainframe Forum Index Mainframe: Search IBM Mainframe Forum: FAQ Register
 

REXX and TCP/IP socket response time


IBM Mainframe Forums -> CLIST & REXX
Post new topic   Reply to topic
View previous topic :: View next topic  
Author Message
Josh Keller

New User


Joined: 08 Oct 2007
Posts: 36
Location: Columbia, SC

PostPosted: Tue Mar 05, 2013 3:21 am
Reply with quote

I've written an application in REXX that does a little bit of everything as far as DB2, VSAM, file I/O, ISPF tables, and TCP/IP socket request. For the most part everything is quick enough except for the TCP/IP requests. I did some test and pulled out the socket code and ran it just by itself and I can get an end to end response of < 1 second. But when that same request is run from in my application, it takes about 6 seconds to get the socket response.

This application is about 20,000 lines of code, so its large in my opinion. I ran a test without the DB2 connection, reduced the stems allocated, and cut out a good portion of my init routine, but that doesn't seem to help. I've also tried to replicate the slow response on my socket test rexx by creating large stems, or large variables, but it seems unaffected. However if I bring up my application in one screen, then try to run the socket test in another, the response time jumps up to 5+ seconds for the test.

So obviously something I'm doing is affecting the response across my whole ISPF session. Has anyone experienced anything like this, or are you aware of what could affect the socket call so adversely? Thanks in advance.
Back to top
View user's profile Send private message
PeterHolland

Global Moderator


Joined: 27 Oct 2009
Posts: 2481
Location: Netherlands, Amstelveen

PostPosted: Tue Mar 05, 2013 12:06 pm
Reply with quote

Maybe you show your socket calls?
Back to top
View user's profile Send private message
Josh Keller

New User


Joined: 08 Oct 2007
Posts: 36
Location: Columbia, SC

PostPosted: Tue Mar 05, 2013 6:32 pm
Reply with quote

Sure. We use a REXX subroutine to do the calls. Here's my SOCKTEST rexx.
Note: I redacted all the server names.

Code:

/*REXX SOCKTEST */
time_e1 = time('r')         /* reset time */                   
time_e1 = time('L')         /* start elap time */                                                                         
CALL MSG "OFF"                                                 
quote= "'"; Q1= "'"; AudCount= 0; env1 = 'CORP1'               
say "start"                                                     
r_c=lchmp901(env1, 'INITIALIZE_TCPIP_SERVICES')                 
say "init " time('e')                                                                                           
env1 = 'TRIC'                                                   
r_c=lchmp901(env1, 'ESTABLISH_A_SOCKET')                       
say "estl " time('e')                                           
save_sock = substr(r_c,3)                                       
say save_sock                                                   
soapenv1 = ,                                                   
'<soapenv:Envelope',                                           
' xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"',   
' xmlns:hos="http://xxxxx.xxxxxx.xxxxxx.com/">',             
'  <soapenv:Header/>',                                         
'   <soapenv:Body>'                                             
soapenv2 = ,                                                   
'   </soapenv:Body>',                                           
'</soapenv:Envelope>'                                                                                                 
req2= soapenv1,                                                       
'    <hos:getMoveRequestsStatusEdit> ' ,                               
'    </hos:getMoveRequestsStatusEdit> ' ,                             
      soapenv2                                                         
say req2                                                               
r_c=lchmp901(env1, 'POST_COMMAND', save_sock, req2)                   
say "post " time('e')                                                 
r_c=lchmp901(env1, 'READ_FROM_SOCKET', save_sock)                     
say "rest " time('e')                                                 
txtdata=r_c                                                           
txtdata2 = substr(txtdata,1,1000)                                     
r_c=lchmp901(env1, 'CLOSE_SOCKET', save_sock)                         
time_e2 = time('e')       /* get elapsed time */                       
say "clos " time('e')                                                 
SAY 'getting Edit moves elap: ' time_e2  'time now: ' time('l')   


Here is the output when running by itself:

Code:
start                                                                         
init  0.036813                                                                 
estl  0.045441                                                                 
0:1                                                                           
<soapenv:Envelope  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"  x
mlns:hos="http://xxxxx.xxxxxx.xxxxx.com/">   <soapenv:Header/>    <soapenv:B
ody>     <hos:getMoveRequestsStatusEdit>      </hos:getMoveRequestsStatusEdit>
    </soapenv:Body> </soapenv:Envelope>                                       
post  0.050070                                                                 
rest  0.420458                                                                 
clos  0.424179                                                                 
getting Edit moves elap:  0.424174 time now:  07:44:33.085940                 
***     


Notice the total elapse time is .42 seconds.

Here's that same run when my application is up in another screen:

Code:
start                                                                         
init  0.825889                                                                 
estl  1.656567                                                                 
0:1                                                                           
<soapenv:Envelope  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"  x
mlns:hos="http://xxxxx.xxxxx.xxxxx.com/">   <soapenv:Header/>    <soapenv:B
ody>     <hos:getMoveRequestsStatusEdit>      </hos:getMoveRequestsStatusEdit>
    </soapenv:Body> </soapenv:Envelope>                                       
post  3.018480                                                                 
rest  5.020372                                                                 
clos  5.310672                                                                 
getting Edit moves elap:  5.310663 time now:  07:47:01.443479                 
***                                                                           
         



Finally here's the contents of LCHMP901:

Code:
  parse arg env1, arg1, arg2, req2
  env1 = strip(env1)
  upper env1
  URLLine = ""
  if env1 = 'LCAS' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'GA' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'HR' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'TRIC' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'CORP1' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'TEST' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  signal on halt
  signal on syntax
  call Program_Initiation
  select
    WHEN ARG1 = 'INITIALIZE_TCPIP_SERVICES' THEN
                 CALL INITIALIZE_TCPIP_SERVICES
    WHEN ARG1 = 'ESTABLISH_A_SOCKET' THEN
                 CALL ESTABLISH_A_SOCKET
    WHEN ARG1 = 'CLOSE_SOCKET' THEN
                 CALL CLOSE_SOCKET
    WHEN ARG1 = 'TERMINATE_TCPIP_SERVICES' THEN
                 CALL TERMINATE_TCPIP_SERVICES
    WHEN ARG1 = 'POST_COMMAND' THEN
                 CALL POST_COMMAND
    WHEN ARG1 = 'READ_FROM_SOCKET' THEN
                 CALL READ_FROM_SOCKET
    OTHERWISE NOP
  end
  return r_c

/*-------------------------------------------------------------------*/
Post_Command:
/*-------------------------------------------------------------------*/

  parse var arg2  socket  '~'  sk_desc
  URLLine = ""
  if env1 = 'LCAS' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'GA' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'HR' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'TRIC' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'CORP1' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'TEST' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if pos('SPECIALMOVE',env1) > 0 then
  Do
     parse var env1 . '~' movenumber
     movenumber=strip(movenumber)
     URLLine = ,
     ' http://lxxxx/xxxxxxt/'||,
     'allApprovalsReceived.jsp?movenumber='||movenumber
     SAY URLLine
  End
  Parse Var URLLine 'http://' Server '/' Document
  Document = '/' || Document
  Command = 'POST' Document 'HTTP/1.0'
  sendrc = SendCommand(Socket, Command)
  command="Accept-Encoding: gzip,deflate "
  sendrc = SendCommand(Socket, Command)
  command="Content-Type: text/xml "
  sendrc = SendCommand(Socket, Command)
  command='SOAPAction: ""'
  sendrc = SendCommand(Socket, Command)
  command='User-Agent: REXXHTTP/1.0 lchmp901'
  sendrc = SendCommand(Socket, Command)
  command='Host: '||IPNAME||' '
  sendrc = SendCommand(Socket, Command)
  len2   = length(req2)
  command='Content-length: '||len2
  sendrc = SendCommand(Socket, Command)
  command=''
  sendrc = SendCommand(Socket, Command)
  command = req2
  sendrc = SendCommand(Socket, Command)
  r_c = '00'

RETURN 0

  /*------------------------------------------------------*/
SendCommand:
  /*------------------------------------------------------*/
  Parse Arg Socket, Command

  /*------------------------------------------------------*/
  /* append two pairs of CRLF to end the command string  */
  /*------------------------------------------------------*/
  Command = Command || crlf

  so_txt = Socket('write', sk_desc, Command)
  parse var so_txt s_rc s_results
  if s_rc <> 0 then,
    do
      call error 'E', 230, 'SOCKET(WRITE) rc='s_rc
    end
  else,
    Do
      s_data_len = s_results
    End
  r_c = '00'
  return so_txt

/*----------------------------------------------------------------*/
/* Hear what the server has to say                                */
/*----------------------------------------------------------------*/
Peek_at_socket:
  Returned_data = Socket('Recv', s_d, 8192, 'PEEK')
  parse var Returned_data s_rc s_type s_port s_ip s_results
  parse var Returned_data s_rc s_data_len s_data_text
  If s_rc <> 0 then,
  Do
    call error 'W', 250, 'SOCKET(Peek) rc='s_rc
  End
Return Returned_data

/*----------------------------------------------------------------*/
Read_from_socket:
/*----------------------------------------------------------------*/
parse var arg2  socket  '~'  sk_desc
s_d = sk_desc
Response = ''
Inbuffer = 0
Do Forever
  Returned_data = peek_at_socket()
  If s_rc <> 0 then,
  Do
    say 'I tried to peek but had a problem:'s_rc
    say '::'Returned_data'::'
    Leave
  End
  If s_data_len = 0 then,
  Do
    Leave
  End
  BytesRcvd = Socket('Recvfrom', s_d, s_data_len)
  Parse var bytesrcvd s_rc s_type s_port s_ipaddr s_real_len rcvdata
  If s_rc < 0 Then
  Do
    say s_rc '<= 0 so I am leaving read_from_socket' rcvdata
    Leave
  End
  If s_rc <> 0 then,
  Do
    call error 'I', 242, 'SOCKET(RecvFrom) rc='s_rc
  End
  Inbuffer = inbuffer + s_real_len
  Response = Response || rcvdata
End

  r_c = '00'||response
  Return 0

  /*------------------------------------------------------*/
  /* Syntax error routine                                 */
  /*------------------------------------------------------*/
syntax:
  xrc = rc
  say "xrc="xrc
  sigl_record = sigl
  MY_DATA=SOURCELINE(SIGL_RECORD)
  say sigl_record my_data
  call error 'E', rc, '==> REXX Error No.' xrc '@ line',
    sigl_record
  return

  /*------------------------------------------------------*/
  /* Halt   error routine                                 */
  /*------------------------------------------------------*/
halt:
  call error 'E', 220, '==> REXX Interrupted'
  return

  /*------------------------------------------------------*/
  /* Common error routine                                 */
  /*------------------------------------------------------*/
error:
  type = arg(1)
  retc = arg(2)
  text = arg(3)
  ecretc = right(retc,3,'0')
  ectype = translate(type)
  ecfull = 'URLCheck' || ecretc || ectype
  say '===> 'type":" ecfull text
  if type <> 'E' then return
  if (initialized = 0) then,
    do
      so_txt = Socket('SocketSetStatus')
      parse var so_txt s_rc s_severreason
      if (s_rc <> 'Connected') then,
        say 'The status of the socket set is' s_rc s_severreason
    end
  else,
    do
      so_txt = Socket('SocketSetStatus')
      parse var so_txt s_rc s_severreason
      if (s_rc <> 'Connected') then,
        say 'The status of the socket set is' s_rc s_severreason
    end
  so_txt = Socket('Terminate')
  r_c = '99'||'Sever error'
  say 'leaving lchmp901 severe error' r_c
  exit r_c

Terminate_TCPIP_Services:
  /*-------------------------------------------------------*/
  /* Terminate the socket and exit                         */
  /*-------------------------------------------------------*/
  so_txt = Socket('Terminate')
  Return

Connect:
  Parse Arg Server
  /* if the servername has a port address specified     */
  /* then use this one, otherwise use the default http  */
  /* port 80                                            */
  Parse Var Server Server ':' Port
  If Port = '' Then
    Port = 80
  if this_is_real  = 1 then,
    do
  /* resolve server name alias to dotted IP address     */
  so_txt = Socket('Gethostbyname', server)
  parse var so_txt s_rc s_results
  if s_rc <> 0 then,
    do
      call error 'I', 80, 'GetHostByName for',
        server 'failed' s_rc
     Return -1
    end
    end
 /*----------------------------------------------------------------*/
 /* Connect the socket                                             */
 /*----------------------------------------------------------------*/
  so_txt = Socket('Connect', s_d, 'AF_INET' port server)
  parse var so_txt s_rc s_results
  if s_rc <> 0 then,
    do
      call error 'W', 120, 'SOCKET(CONNECT) rc='s_rc
    end
  Return 0
  /*------------------------------------------------------*/
  /* Procedure: Close_Socket                              */
  /*------------------------------------------------------*/
Close_socket:
  parse var arg2  socket  '~'  s_d
  so_txt = Socket('Close', s_d)
  parse var so_txt s_rc s_results
  if s_rc <> 0 then,
    do
      call error 'W', 234, 'Close rc='s_rc
    end
  r_c = '00'
  Return
  /*------------------------------------------------------*/
  /* Procedure: Program initiation                        */
  /*------------------------------------------------------*/
Program_Initiation:
  CRLF = x2c('0D25')
  LF = x2c('25')
  rcvdata = ""
  Return

Initialize_TCPIP_Services:
 /*----------------------------------------------------------------*/
 /* Initialize the Socket                                          */
 /*----------------------------------------------------------------*/
  so_txt = Socket('Initialize', 'LCPKSP01', 2)
  parse var so_txt s_rc s_subtask s_maxdesc s_servicename
  socket_rc = s_rc
  if s_rc = 0 then,
    Do
      initialized = 1
      r_c = '00'||s_servicename
    End
  else,
    Do
      call error 'E', 40, 'Unable to initialize SOCKET URLCheck' s_rc
      r_c = '99'||'Unable to initialize SOCKET URLCheck'
    End
  Return
  /*------------------------------------------------------*/
  /* Procedure: Establish_A_Socket                        */
  /*------------------------------------------------------*/
Establish_A_Socket:
  URLLine = ""
  if env1 = 'LCAS' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'GA' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'HR' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'TRIC' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'CORP1' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if env1 = 'TEST' then
     URLLine = 'http://xxxserver/services/rexx?wsdl'
  if pos('SPECIALMOVE',env1) > 0 then
  Do
     parse var env1 . '~' movenumber
     movenumber=strip(movenumber)
     URLLine = ,
     ' http://xxxxx/xxxxxx/'||,
     'allApprovalsReceived.jsp?movenumber='||movenumber
  End
  Parse Var URLLine 'http://' Server '/' Document
  Document = '/' || Document
  socket_rc = -1
  so_txt = Socket('Socket', 'AF_INET', 'STREAM', 'TCP')
  parse var so_txt s_rc s_results
  if s_rc <> 0 then,
    do
      call error 'E', 60, 'SOCKET(SOCKET) rc='s_rc
    end
  else,
    Do
      s_d = s_results
      sk_desc = s_d
      socket_rc = 0
    End
 /*----------------------------------------------------------------*/
 /* Turn  on               EBCDIC-Ascii conversion                 */
 /*----------------------------------------------------------------*/
  so_txt = Socket('SetSockOpt',s_d,'SOL_SOCKET','SO_ASCII','On')
  parse var so_txt s_rc s_results
  if s_rc = 0 then nop
  else,
    call error 'W', 70, 'Unable to set SOCKET So_ASCii' s_rc
  so_txt = Socket('SetSockOpt',s_d,'SOL_SOCKET','SO_RCVTIMEO','30 0')
  parse var so_txt s_rc s_results
  if s_rc = 0 then nop
  else,
    call error 'W', 70, 'Unable to set SOCKET rcvtimeo' s_rc
  so_txt = Socket('SetSockOpt',s_d,'SOL_SOCKET','SO_SNDTIMEO','30 0')
  parse var so_txt s_rc s_results
  if s_rc = 0 then nop
  else,
    call error 'W', 70, 'Unable to set SOCKET sndtimeo' s_rc
  /*
  so_txt = Socket('GetSockOpt',s_d,'SOL_SOCKET','SO_ASCII')
  say so_txt
  so_txt = Socket('GetSockOpt',s_d,'SOL_SOCKET','SO_RCVTIMEO')
  say so_txt
  so_txt = Socket('GetSockOpt',s_d,'SOL_SOCKET','SO_SNDTIMEO')
  say so_txt
  */
  Socket = Connect(Server)
  If Socket = -1 Then
     r_c = '99'||socket||'~'||'bad socket connect'
  else
     r_c = '00'||socket||'~'||sk_desc
RETURN 0
Back to top
View user's profile Send private message
PeterHolland

Global Moderator


Joined: 27 Oct 2009
Posts: 2481
Location: Netherlands, Amstelveen

PostPosted: Wed Mar 06, 2013 1:44 pm
Reply with quote

How about using one 'READ' instead of 'PEEK'ing and 'RECFROM'?
Back to top
View user's profile Send private message
Josh Keller

New User


Joined: 08 Oct 2007
Posts: 36
Location: Columbia, SC

PostPosted: Thu Mar 07, 2013 10:47 pm
Reply with quote

I thought I'd share my results.


I use a driver REXX to allocate the panel,skeleton,execlibs ect needed for my application. The REXX application is compiled, so I'm calling it from our production EXECLIB. When testing with the above SOCKTEST, if I allocate the prod execlib, then the response time for the socket calls increases. When I remove the allocation, the response is normal. The execlib is the only library that affects the socket call as far as my issue is concerned. I assume it's taking longer to traverse the concatenated datasets to locate the SOCKET exec. ?

My fix was to drop/dealloc the production execlib once my application starts up. Then I allocated it as needed when I'm doing an external call. This one fix seemed to improve overall performance including VSAM reads.

Hope this helps someone else out in the future.
Back to top
View user's profile Send private message
PeterHolland

Global Moderator


Joined: 27 Oct 2009
Posts: 2481
Location: Netherlands, Amstelveen

PostPosted: Thu Mar 07, 2013 10:53 pm
Reply with quote

Nice. Thanks for sharing.
Back to top
View user's profile Send private message
View previous topic :: :: View next topic  
Post new topic   Reply to topic View Bookmarks
All times are GMT + 6 Hours
Forum Index -> CLIST & REXX

 


Similar Topics
Topic Forum Replies
No new posts Running REXX through JOB CLIST & REXX 13
No new posts Error to read log with rexx CLIST & REXX 11
No new posts isfline didnt work in rexx at z/OS ve... CLIST & REXX 7
No new posts run rexx code with jcl CLIST & REXX 15
No new posts Execute secondary panel of sdsf with ... CLIST & REXX 1
Search our Forums:

Back to Top