Kbase 19881: SOCKET. Sample 4GL Socket Programming Code for Client Side
Autor |
  Progress Software Corporation - Progress |
Acesso |
  Público |
Publicação |
  16/09/2010 |
|
Status: Verified
GOAL:
Sample 4GL Socket Programming Code for Client Side
GOAL:
How to program sockets for Client side with 4GL?
FACT(s) (Environment):
Progress 9.x
OpenEdge 10.x
FIX:
/* Sample 4GL Socket Programming Code for Client Side*/ DEFINE VARIABLE hSocket AS HANDLE NO-UNDO.
DEFINE VARIABLE lRC AS LOGICAL NO-UNDO.
DEFINE VARIABLE mHeader AS MEMPTR NO-UNDO.
DEFINE VARIABLE mData AS MEMPTR NO-UNDO.
DEFINE VARIABLE iDataSize AS INTEGER NO-UNDO.PAUSE 0 BEFORE-HIDE./*--------------------------------------------------------*/
/* Create socket and connect to server */
/*--------------------------------------------------------*/CREATE SOCKET hSocket.
hSocket:CONNECT('-H localhost -S 23456') NO-ERROR.IF hSocket:CONNECTED() = FALSE THEN
DO:
MESSAGE 'Unable to Connect' VIEW-AS ALERT-BOX.
RETURN.
END./*--------------------------------------------------------*/
/* Allocate 4 byte header block once (for performance) */
/* and specify the order of the bytes within the pointer */
/* which is needed to guarantee proper interpretation of */
/* the data between machines whose CPU's have different */
/* byte orders */
/*--------------------------------------------------------*/SET-SIZE(mHeader) = 4.SET-BYTE-ORDER(mHeader) = BIG-ENDIAN./*--------------------------------------------------------*/
/* Socket is connected, so configure what internal */
/* procedure the socket will invoke when data is sent */
/* from the server */
/*--------------------------------------------------------*/hSocket:SET-READ-RESPONSE-PROCEDURE('ProcessServerResponse')./*--------------------------------------------------------*/
/* Since the server isn't coded to send back a response */
/* if the connection process went well, run an internal */
/* procedure that sends an initial message to the server */
/* (which forces the server to respond and causes a loop */
/* to happen). During reading of a message from the */
/* server another message is automatically sent to the */
/* server asking for more information (for example, the */
/* current time). Basically, you are in a constant loop */
/* until you hit the escape key */
/*--------------------------------------------------------*/DIV>RUN KickStart./*--------------------------------------------------------*/
/* Now, you go into a loop waiting for data to be sent to */
/* the socket from the server */
/*--------------------------------------------------------*/REPEAT ON STOP UNDO, LEAVE ON QUIT UNDO, LEAVE:
IF hSocket:connected() THEN
WAIT-FOR READ-RESPONSE OF hSocket.
ELSE
LEAVE.
END./*--------------------------------------------------------*/
/* At this point, you have exited the repeat block above, */
/* so you disconnect the socket, clean up the socket */
/* handle, release any memory allocations and then exit */
/* the program */
/*--------------------------------------------------------*/hSocket:DISCONNECT() NO-ERROR.DELETE OBJECT hSocket.SET-SIZE(mHeader) = 0.
SET-SIZE(mData) = 0.QUIT./*--------------------------------------------------------*/
/* Internal procedures for reading the socket data and */
/* kick starting the whole process are shown below */
/*--------------------------------------------------------*/PROCEDURE ProcessServerResponse:
DEFINE VARIABLE cTime AS CHARACTER NO-UNDO.
DEFINE VARIABLE iMessageSize AS INTEGER NO-UNDO. /*----------------------------------------------------*/
/* Check to see if the socket is still connected, if */
/* not, exit from this internal procedure */
/* */
/* Please note that this check is done because it is */
/* normal for a client connection to get a message */
/* sent to it that indicates that the server has */
/* disconnected from the client */
/*----------------------------------------------------*/ IF SELF:CONNECTED() = FALSE THEN
RETURN. /*----------------------------------------------------*/
/* The following code reads the header block we are */
/* using on each packet of data being sent. We are */
/* prefixing each packet with a 4 byte integer that */
/* tells us how much "real" data to expect. This is */
/* done because w.e cannot be guaranteed that all of */
/* the data that was sent actually reached Progress */
/* at the same time. Since we are invoking a */
/* blocking read method, we want to be sure that we */
/* know how much data to read so that we don't sit */
/* around in the blocking read method forever waiting */
/* for data that will never arrive */
/*----------------------------------------------------*/ /*----------------------------------------------------*/
/* Read 4 byte header block */
/*----------------------------------------------------*/ lRC = SELF:READ(mHeader,1,4,2) NO-ERROR. IF lRC = FALSE OR ERROR-STATUS:GET-MESSAGE(1) <> '' THEN
DO:
DISPLAY 'Unable To Read Header Bytes'.
RETURN.
END. /*----------------------------------------------------*/
/* Now that the header block has been successfully */
/* read, we know how much real data to read, so we go */
/* do the read */
/*----------------------------------------------------*/ iMessageSize = GET-LONG(mHeader,1). IF iDataSize < iMessageSize THEN
DO:
SET-SIZE(mData) = 0.
SET-SIZE(mData) = iMessageSize.
iDataSize = iMessageSize.
SET-BYTE-ORDER(mData) = BIG-ENDIAN.
END. lRC = SELF:READ(mData,1,iMessageSize,2) NO-ERROR. IF lRC = FALSE OR ERROR-STATUS:GET-MESSAGE(1) <> '' THEN
DO:
DISPLAY 'Unable To Read Detail Bytes'.
RETURN.
END. /*----------------------------------------------------*/
/* At this point, we have successfully read the data */
/* from the server (8 bytes as the server should have */
/* sent a string containing the current time in the */
/* following format: HH:MM:SS), so pull the. data out */
/* of the memory pointer and display it on the */
/* screen */
/*----------------------------------------------------*/ cTime = GET-STRING(mData,1). DISPLAY cTime. PAUSE 1 NO-MESSAGE. /*----------------------------------------------------*/
/* Now we reuse the mData memory pointer and send a */
/* new message back to the server (it doesn't matter */
/* what we send because the server will ignore what */
/* is sent and just do a reply by sending ba.ck the */
/* current time) */
/*----------------------------------------------------*/ /*----------------------------------------------------*/
/* Make sure that the mData memory pointer is sized */
/* large enough for our purposes */
/*----------------------------------------------------*/ IF iDataSize < 13 THEN
DO:
SET-SIZE(mData) = 0.
SET-SIZE(mData) = 13.
iDataSize = 13.
SET-BYTE-ORDER(mData) = BIG-ENDIAN.
END. /*----------------------------------------------------*/
/* Fill the memory pointer with data (header + the */
/* real data) and write the data to the socket */
/*----------------------------------------------------*/ PUT-LONG(mData,1) = LENGTH('WhatEver') + 1.
PUT-STRING(mData,5) = 'WhatEver'. lRC = SELF:WRITE(mData,1,13) NO-ERROR. IF lRC = FALSE OR ERROR-STATUS:GET-MESSAGE(1) <> '' THEN
DO:
DISPLAY 'Unable To Write Detail Bytes'.
RETURN.
END.
END PROCEDURE.PROCEDURE KickStart:
/*----------------------------------------------------*/
/* Fill the memory pointer with data (header + the */
/* real data) and write the. data to the socket */
/*----------------------------------------------------*/ IF iDataSize < 13 THEN
DO:
SET-SIZE(mData) = 0.
SET-SIZE(mData) = 13.
iDataSize = 13.
SET-BYTE-ORDER(mData) = BIG-ENDIAN.
END. PUT-LONG(mData,1) = LENGTH('WhatEver') + 1.
PUT-STRING(mData,5) = 'WhatEver'. lRC = hSocket:WRITE(mData,1,13) NO-ERROR. IF lRC = FALSE OR ERROR-STATUS:GET-MESSAGE(1) <> '' THEN
DO:
DISPLAY 'Unable To Write Detail Bytes'.
RETURN.
END.
END PROCEDURE..