exiting from a WAIT-FOR CONNECT OF command

Hi All,

I have a very perplexing problem that can probably be solved rather easily, if I only knew how.

I have written a simple background process, that sits on the server and opens a Port (Server Socket). it then sits in a loop listening for any data to be sent through from the client machines. It then takes the data and runs a DLL procedure. Then sends back a message to the client machine, informing them of success or not. Anyway it all runs fine except for one little problem, and that is when you try to shut it down. If I close the connection I get an error because it is still running the WAIT-FOR CONNECTION OF statement. But if you press esc it exits without error (which I fully understand considering I have a On End-Key Leave type statement on the loop in the main block). I tried a trigger on a button that said:

Apply "ENDKEY"
or
Apply "ENDKEY" to C-Win.

I even tried
Apply "ENDKEY" to Main-Block, but as you would probably of guessed, that had a bit of a spit at me.

both failed.

Also when you exit via the esc key, you actually have to press it twice or you have rogue Progress tasks in the background. And we all know about Rogue Progress Tasks don't we :p
 

Chris Kelleher

Administrator
Staff member
Hi there,

I think you need to place your WAIT-FOR inside of a REPEAT ON STOP UNDO, LEAVE ON QUIT UNDO, LEAVE block. Here's some sample code.

Sockets, server side:
http://www.progress.com/services/support/cgi-bin/techweb-kbase.cgi/webkb.html?kbid=19882
Code:
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 zync') 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)    */
/*--------------------------------------------------------*/

SET-SIZE(mHeader) = 4.

/*--------------------------------------------------------*/
/* 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           */
/*                                                        */
/* 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 disconnected  */
    /* 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.
        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.
        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.
Sockets, client side:
http://www.progress.com/services/support/cgi-bin/techweb-kbase.cgi/webkb.html?kbid=19882
Code:
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 zync') 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)    */
/*--------------------------------------------------------*/

SET-SIZE(mHeader) = 4.

/*--------------------------------------------------------*/
/* 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                           */
/*--------------------------------------------------------*/

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:
    WAIT-FOR READ-RESPONSE OF hSocket.
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 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.
        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 back 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.
        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.
        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.

Hope this helps,
-Chris
 
Top