Consultor Eletrônico



Kbase 19882: How to program sockets for Server side with 4GL?
Autor   Progress Software Corporation - Progress
Acesso   Público
Publicação   07/02/2011
Status: Verified

GOAL:

How to program sockets for Server side with 4GL?

GOAL:

Sample 4GL Socket Programming Code for Server Side

FACT(s) (Environment):

All Supported Operating Systems
Progress 9.x
OpenEdge 10.x

FIX:

/* Sample 4GL Socket Programming Code for Server Side */ DEFINE VARIABLE hServer 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 a server socket */
/*--------------------------------------------------------*/
CREATE SERVER-SOCKET hServer./*--------------------------------------------------------*/
/* Server socket has been created so configure what */
/* internal procedure is called when a client connects to */
/* the server socket */
/*--------------------------------------------------------*/lRC = hServer:SET-CONNECT-PROCEDURE('ProcessClientConnect') NO-ERROR.IF lRC = FALSE OR ERROR-STATUS:GET-MESSAGE(1) <> '' THEN
DO:
DISPLAY 'Unable To Establish Connect Procedure'.
RETURN.
END./*--------------------------------------------------------*/
/* Enable the server socket to accept connections */
/*--------------------------------------------------------*/lRC = hServer:ENABLE-CONNECTIONS('-S 23456') NO-ERROR.IF lRC = FALSE OR ERROR-STATUS:GET-MESSAGE(1) <> '' THEN
DO:
DISPLAY 'Unable To Establish Listener'.
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./*--------------------------------------------------------*/
/* Server socket is now listening for connection requests */
/* from clients so we go into a repeat loop that listens */
/* for client connection requests and, implicitly, data */
/* that is received from existing client connections */
/*--------------------------------------------------------*/REPEAT ON STOP UNDO, LEAVE ON QUIT UNDO, LEAVE:
WAIT-FOR CONNECT OF hServer.
END./*--------------------------------------------------------*/
/* At this point, we have exited the repeat block above, */
/* so we disable the ability to accept any further client */
/* connections, cleanup the server socket, release any */
/* memory allocations and then exit the program &nbs.p; */
/* . */
/* Please note that all connected clients will get a */
/* packet sent to them and the clients DISCONNECTED() */
/* method will return TRUE */
/*--------------------------------------------------------*/hServer:DISABLE-CONNECTIONS().DELETE OBJECT hServer.SET-SIZE(mHeader) = 0.
SET-SIZE(mData) = 0.QUIT./*--------------------------------------------------------*/
/* Internal procedures for establishing connections and */
/* reading/responding to socket data are shown below */
/*--------------------------------------------------------*/PROCEDURE ProcessClientConnect:
DEFINE INPUT PARAMETER hSocket AS HANDLE NO-UNDO. /*----------------------------------------------------*/
/* All that is done during the connection process is */
/* to assign the internal procedure that will be used */
/* to handle the data sent by the client */
/* */
/* Please note that we do not need to keep track of */
/* the actual client socket handle as that is */
/* automatically handled for us by the wonderful 4GL */
/*----------------------------------------------------*/ lRC = hSocket:SET-READ-RESPONSE-PROCEDURE('SocketIO') NO-ERROR. IF lRC = FALSE OR ERROR-STATUS:GET-MESSAGE(1) <> '' THEN
DO:
DISPLAY 'Unable To Establish Read Response Procedure'.
RETURN.
END.
END PROCEDURE.PROCEDURE SocketIO:
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, then exit from this internal procedure */
/* */
/* Please note that this check is done because it is */
/* possible for a client to have become disconnecte.d */
/* by the time we receive this message. and if that is */
/* the case we don't want to do anything with this */
/* message */
/*----------------------------------------------------*/ 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 we 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.
&nb.sp; 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, data has been successfully read */
/* from the client (it doesn't matter what data was */
/* read) */
/*----------------------------------------------------*/ /*----------------------------------------------------*/
/* Now we reuse the mData memory pointer and send a */
/* new message back to the client that consists of */
/* the current time in HH:MM:SS format */
/*----------------------------------------------------*/ ASSIGN cTime = STRING(TIME,'HH:MM:SS'). /*----------------------------------------------------*/
/* 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(cTime) + 1.
PUT-STRING(mData,5) = cTime. 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..