hi,
A view days agoo i was dooing some testing with 4GL sockets in V91B.
I've made a (quite) simple Client/Server program which does the following:
A promon-alike server program keeps track of the users which connect to the client Socket program. When a users connects, the user name and hour of connections is sent to the promon-alike server program.
+The system consists of the next steps:
server.w:
* Get ip address for server, and connect server to serviceport
* Listen for connection of clients who send their logon name
and hour of connection (polling procedure) or disconnection.
*Put client logon + connection time in a list on the server screen.
client.w:
* Get ip address of server
* Write connect string to server when STARTUP client
* Write disconnect string to server when SHUTDOWN client.
*** PROBLEM ***
Everything seems to work fine, the server starts up, the client connects and disconnects, but when there are more then 1 client connected to the server, the disconnect is mentioned in the server-list, but the rest of the disconnections don't fire any more, so only the first disconnect of the client is mentioned in the server list.
Have a clue ????
Thanx for any response,
Emmanuel Nuyttens
Senior Programmer at C&C computers NV
OUDENAARDE _ BELGIUM
+The Code:
***************
*** SERVER.W ***
***************
/* main */
MAIN-BLOCK:
DO ON ERROR UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
RUN enable_UI.
ON 'tab':U OF fill-in-ip IN FRAME frame-ip
DO:
HIDE FRAME frame-ip.
ENABLE ALL WITH FRAME {&FRAME-NAME}.
END.
/* Get IP-adress of server */
cIP = ifunc_ip().
IF LENGTH(TRIM(cIp)) = 0 THEN
DO:
MESSAGE "IP address for server not found !"
SKIP "Please fill-in the IP-address" VIEW-AS ALERT-BOX.
VIEW FRAME frame-ip.
DISABLE ALL WITH FRAME {&FRAME-NAME}.
ENABLE ALL WITH FRAME frame-ip.
WAIT-FOR "tab":U OF fill-in-ip IN FRAME frame-ip.
ASSIGN
cIp = fill-in-ip:SCREEN-VALUE IN FRAME frame-ip.
END.
ASSIGN
fill-in-ip:SCREEN-VALUE IN FRAME {&FRAME-NAME} = "IP-
Adres : ":U + cIP + " ServicePoort : 3333":U.
cConnectString = "-H ":U + cIp + " -S 3333 -N tcp":U.
APPLY "choose":U TO button-start.
IF NOT THIS-PROCEDUREERSISTENT THEN
WAIT-FOR CLOSE OF THIS-PROCEDURE.
END.
/* Start the server - button-start */
DO:
/* Create Server Socket */
IF NOT VALID-HANDLE(hServerSocket) THEN
DO:
{&SELF-NAME}:LABEL = "&Stop Server".
CREATE SERVER-SOCKET hServerSocket.
fill-in-msg:SCREEN-VALUE IN FRAME {&FRAME-NAME}
= "Server STARTED".
/* Connection procedure */
hServerSocket:SET-CONNECT-PROCEDURE( "connProc":U).
aOk = hServerSocket:ENABLE-CONNECTIONS(cConnectString).
MESSAGE "Enabled connections:" aOk.
IF NOT aOk THEN
RETURN.
RUN adecomm/_statdsp.p (hstatus,1,"Waiting for
Connections ...").
END. ELSE
DO:
IF {&self-name}:LABEL = "&Stop Server" THEN
DO:
{&self-name}:LABEL = "&Start Server".
aOk = hServerSocketISABLE-CONNECTIONS().
MESSAGE "Disabled connections:" aOk.
IF NOT aOk THEN
RETURN.
ELSE
fill-in-msg:SCREEN-VALUE IN FRAME {&FRAME-NAME}
= "Server STOPPED".
RUN adecomm/_statdsp.p (hstatus,1,"Wait for connections
STOPPED...").
END. ELSE DO:
{&self-name}:LABEL = "&Stop Server".
aOk = hServerSocket:ENABLE-CONNECTIONS(cConnectString).
MESSAGE "Enabled connections:" aOk.
IF NOT aOk THEN
RETURN.
ELSE
fill-in-msg:SCREEN-VALUE IN FRAME {&FRAME-NAME}
= "Server STARTED".
RUN adecomm/_statdsp.p (hstatus,1,"Wait for connections
STARTED ...").
END.
END.
END.
/* Connection procedure */
/*------------------------------------------------------------------------------
Purpose: Get socket from connected client Client
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
/* Connection procedure for server socket */
DEFINE INPUT PARAMETER iphSocket AS HANDLE. /*Socket implicitly created*/
ASSIGN
hSocket = iphSocket.
END PROCEDURE.
/* Polling for Connected clients every 5 seconds
this procedure is executed by the OCX.tick Activex
distributed with Progress
*/
/*------------------------------------------------------------------------------
Purpose:
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
IF VALID-HANDLE(hSocket) THEN
DO:
IF hSocket:GET-BYTES-AVAILABLE() > 0 THEN
DO:
/* 64 bytes reserveren voor inkomende string */
SET-SIZE(mBuffer) = 64.
hSocket:READ (mBuffer,1,hSocket:GET-BYTES-AVAILABLE()).
cString = GET-STRING(mBuffer,1). /*Unmarshal data*/
BELL.
/* Put connected client in connection list */
SELECT-logon:ADD-LAST(cString) IN FRAME {&FRAME-NAME}.
END.
END.
END PROCEDURE.
**********
*CLIENT.W*
**********
/* Main */
MAIN-BLOCK:
DO ON ERROR UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
ON 'tab':U OF fill-in-logon IN FRAME frame-logon
DO:
HIDE FRAME frame-logon.
RUN connProc.
RETURN.
END.
RUN enable_UI.
DISABLE ALL WITH FRAME {&FRAME-NAME}.
VIEW FRAME frame-logon.
/* Insert adress server if not same machine */
cIP = ifunc_ip().
IF LENGTH(TRIM(cIp)) = 0 THEN
DO:
MESSAGE "IP adres server not found !" VIEW-AS ALERT-BOX.
APPLY "close":U TO THIS-PROCEDURE.
END.
ASSIGN
fill-in-ip:SCREEN-VALUE IN FRAME frame-logon = cIP.
ENABLE ALL WITH FRAME frame-logon.
IF NOT THIS-PROCEDUREERSISTENT THEN
WAIT-FOR CLOSE OF THIS-PROCEDURE.
END.
/* Connection Procedure */
/*------------------------------------------------------------------------------
Purpose:
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
/* Connect to service at server */
CREATE SOCKET hSocket.
hSocket:CONNECT (cConnectString).
IF hSocket:CONNECTED() THEN
DO:
ASSIGN
cTime = STRING(TIME,"hh:mm:ss") /* in var, voor zelfde tijd
doorsturen naar server */
fill-in-user:SCREEN-VALUE IN FRAME {&FRAME-NAME} = fill-in-
logon:SCREEN-VALUE IN FRAME frame-logon + " logged on
at " + cTime.
ENABLE ALL WITH FRAME {&FRAME-NAME}.
MESSAGE "Connected OK".
END.
ELSE DO:
MESSAGE "Could not connect".
APPLY "close":u TO THIS-PROCEDURE.
END.
RUN iproc_snd_msg(" logged on",cTime).
END PROCEDURE.
/* Shutdown client - on choose of close button */
RUN iproc_snd_msg(" logged off", STRING(TIME,"hh:mm:ss":U)).
hSocketISCONNECT().
APPLY "close":u TO THIS-PROCEDURE.
/* send connect message to server when STARTUP CLIENT */
/* send disconnect message to server when SHUTDOWN CLIENT */
/*------------------------------------------------------------------------------
Purpose: iproc_snd_msg
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
DEF INPUT PARAMETER ipcMsg AS CHAR NO-UNDO.
DEF INPUT PARAMETER ipcTime AS CHAR NO-UNDO.
SET-SIZE(mBuffer) = 64.
cString = fill-in-logon:SCREEN-VALUE IN FRAME frame-logon + " " + TRIM(ipcMsg) + " at " + ipcTime.
PUT-STRING(mBuffer,1) = cString.
hSocket:WRITE (mBuffer,1,LENGTH(cString)).
END PROCEDURE.
/* IFUNC_IP */
RETURNS CHARACTER
( /* parameter-definitions */ ) :
/*------------------------------------------------------------------------------
Purpose: Bepaal ip adres server
Notes:
------------------------------------------------------------------------------*/
DEF VAR cLijn AS CHAR NO-UNDO.
DEF VAR cIp AS CHAR NO-UNDO.
DEF VAR iIndex AS INT NO-UNDO.
OS-COMMAND SILENT md C:\TEMP.
OUTPUT TO "C:\TEMP\IPCONFIG.TXT":U.
OS-COMMAND SILENT ipconfig.
OUTPUT CLOSE.
INPUT FROM "C:\TEMP\IPCONFIG.TXT":U.
lus:
REPEAT:
IMPORT UNFORMATTED cLijn.
IF INDEX(cLijn,"IP Address":U) > 0 THEN
DO:
cIp = TRIM(cLijn).
LEAVE lus.
END.
END.
IF LENGTH(cIp) > 0 THEN
DO:
iIndex = INDEX(cIp,":":U).
IF iIndex > 0 THEN
cIp = SUBSTR(cIp,iIndex + 1 ,LENGTH(cIp) - iIndex).
END.
RETURN cIp. /* Function return value. */
END FUNCTION.
A view days agoo i was dooing some testing with 4GL sockets in V91B.
I've made a (quite) simple Client/Server program which does the following:
A promon-alike server program keeps track of the users which connect to the client Socket program. When a users connects, the user name and hour of connections is sent to the promon-alike server program.
+The system consists of the next steps:
server.w:
* Get ip address for server, and connect server to serviceport
* Listen for connection of clients who send their logon name
and hour of connection (polling procedure) or disconnection.
*Put client logon + connection time in a list on the server screen.
client.w:
* Get ip address of server
* Write connect string to server when STARTUP client
* Write disconnect string to server when SHUTDOWN client.
*** PROBLEM ***
Everything seems to work fine, the server starts up, the client connects and disconnects, but when there are more then 1 client connected to the server, the disconnect is mentioned in the server-list, but the rest of the disconnections don't fire any more, so only the first disconnect of the client is mentioned in the server list.
Have a clue ????
Thanx for any response,
Emmanuel Nuyttens
Senior Programmer at C&C computers NV
OUDENAARDE _ BELGIUM
+The Code:
***************
*** SERVER.W ***
***************
/* main */
MAIN-BLOCK:
DO ON ERROR UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
RUN enable_UI.
ON 'tab':U OF fill-in-ip IN FRAME frame-ip
DO:
HIDE FRAME frame-ip.
ENABLE ALL WITH FRAME {&FRAME-NAME}.
END.
/* Get IP-adress of server */
cIP = ifunc_ip().
IF LENGTH(TRIM(cIp)) = 0 THEN
DO:
MESSAGE "IP address for server not found !"
SKIP "Please fill-in the IP-address" VIEW-AS ALERT-BOX.
VIEW FRAME frame-ip.
DISABLE ALL WITH FRAME {&FRAME-NAME}.
ENABLE ALL WITH FRAME frame-ip.
WAIT-FOR "tab":U OF fill-in-ip IN FRAME frame-ip.
ASSIGN
cIp = fill-in-ip:SCREEN-VALUE IN FRAME frame-ip.
END.
ASSIGN
fill-in-ip:SCREEN-VALUE IN FRAME {&FRAME-NAME} = "IP-
Adres : ":U + cIP + " ServicePoort : 3333":U.
cConnectString = "-H ":U + cIp + " -S 3333 -N tcp":U.
APPLY "choose":U TO button-start.
IF NOT THIS-PROCEDUREERSISTENT THEN
WAIT-FOR CLOSE OF THIS-PROCEDURE.
END.
/* Start the server - button-start */
DO:
/* Create Server Socket */
IF NOT VALID-HANDLE(hServerSocket) THEN
DO:
{&SELF-NAME}:LABEL = "&Stop Server".
CREATE SERVER-SOCKET hServerSocket.
fill-in-msg:SCREEN-VALUE IN FRAME {&FRAME-NAME}
= "Server STARTED".
/* Connection procedure */
hServerSocket:SET-CONNECT-PROCEDURE( "connProc":U).
aOk = hServerSocket:ENABLE-CONNECTIONS(cConnectString).
MESSAGE "Enabled connections:" aOk.
IF NOT aOk THEN
RETURN.
RUN adecomm/_statdsp.p (hstatus,1,"Waiting for
Connections ...").
END. ELSE
DO:
IF {&self-name}:LABEL = "&Stop Server" THEN
DO:
{&self-name}:LABEL = "&Start Server".
aOk = hServerSocketISABLE-CONNECTIONS().
MESSAGE "Disabled connections:" aOk.
IF NOT aOk THEN
RETURN.
ELSE
fill-in-msg:SCREEN-VALUE IN FRAME {&FRAME-NAME}
= "Server STOPPED".
RUN adecomm/_statdsp.p (hstatus,1,"Wait for connections
STOPPED...").
END. ELSE DO:
{&self-name}:LABEL = "&Stop Server".
aOk = hServerSocket:ENABLE-CONNECTIONS(cConnectString).
MESSAGE "Enabled connections:" aOk.
IF NOT aOk THEN
RETURN.
ELSE
fill-in-msg:SCREEN-VALUE IN FRAME {&FRAME-NAME}
= "Server STARTED".
RUN adecomm/_statdsp.p (hstatus,1,"Wait for connections
STARTED ...").
END.
END.
END.
/* Connection procedure */
/*------------------------------------------------------------------------------
Purpose: Get socket from connected client Client
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
/* Connection procedure for server socket */
DEFINE INPUT PARAMETER iphSocket AS HANDLE. /*Socket implicitly created*/
ASSIGN
hSocket = iphSocket.
END PROCEDURE.
/* Polling for Connected clients every 5 seconds
this procedure is executed by the OCX.tick Activex
distributed with Progress
*/
/*------------------------------------------------------------------------------
Purpose:
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
IF VALID-HANDLE(hSocket) THEN
DO:
IF hSocket:GET-BYTES-AVAILABLE() > 0 THEN
DO:
/* 64 bytes reserveren voor inkomende string */
SET-SIZE(mBuffer) = 64.
hSocket:READ (mBuffer,1,hSocket:GET-BYTES-AVAILABLE()).
cString = GET-STRING(mBuffer,1). /*Unmarshal data*/
BELL.
/* Put connected client in connection list */
SELECT-logon:ADD-LAST(cString) IN FRAME {&FRAME-NAME}.
END.
END.
END PROCEDURE.
**********
*CLIENT.W*
**********
/* Main */
MAIN-BLOCK:
DO ON ERROR UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
ON 'tab':U OF fill-in-logon IN FRAME frame-logon
DO:
HIDE FRAME frame-logon.
RUN connProc.
RETURN.
END.
RUN enable_UI.
DISABLE ALL WITH FRAME {&FRAME-NAME}.
VIEW FRAME frame-logon.
/* Insert adress server if not same machine */
cIP = ifunc_ip().
IF LENGTH(TRIM(cIp)) = 0 THEN
DO:
MESSAGE "IP adres server not found !" VIEW-AS ALERT-BOX.
APPLY "close":U TO THIS-PROCEDURE.
END.
ASSIGN
fill-in-ip:SCREEN-VALUE IN FRAME frame-logon = cIP.
ENABLE ALL WITH FRAME frame-logon.
IF NOT THIS-PROCEDUREERSISTENT THEN
WAIT-FOR CLOSE OF THIS-PROCEDURE.
END.
/* Connection Procedure */
/*------------------------------------------------------------------------------
Purpose:
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
/* Connect to service at server */
CREATE SOCKET hSocket.
hSocket:CONNECT (cConnectString).
IF hSocket:CONNECTED() THEN
DO:
ASSIGN
cTime = STRING(TIME,"hh:mm:ss") /* in var, voor zelfde tijd
doorsturen naar server */
fill-in-user:SCREEN-VALUE IN FRAME {&FRAME-NAME} = fill-in-
logon:SCREEN-VALUE IN FRAME frame-logon + " logged on
at " + cTime.
ENABLE ALL WITH FRAME {&FRAME-NAME}.
MESSAGE "Connected OK".
END.
ELSE DO:
MESSAGE "Could not connect".
APPLY "close":u TO THIS-PROCEDURE.
END.
RUN iproc_snd_msg(" logged on",cTime).
END PROCEDURE.
/* Shutdown client - on choose of close button */
RUN iproc_snd_msg(" logged off", STRING(TIME,"hh:mm:ss":U)).
hSocketISCONNECT().
APPLY "close":u TO THIS-PROCEDURE.
/* send connect message to server when STARTUP CLIENT */
/* send disconnect message to server when SHUTDOWN CLIENT */
/*------------------------------------------------------------------------------
Purpose: iproc_snd_msg
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
DEF INPUT PARAMETER ipcMsg AS CHAR NO-UNDO.
DEF INPUT PARAMETER ipcTime AS CHAR NO-UNDO.
SET-SIZE(mBuffer) = 64.
cString = fill-in-logon:SCREEN-VALUE IN FRAME frame-logon + " " + TRIM(ipcMsg) + " at " + ipcTime.
PUT-STRING(mBuffer,1) = cString.
hSocket:WRITE (mBuffer,1,LENGTH(cString)).
END PROCEDURE.
/* IFUNC_IP */
RETURNS CHARACTER
( /* parameter-definitions */ ) :
/*------------------------------------------------------------------------------
Purpose: Bepaal ip adres server
Notes:
------------------------------------------------------------------------------*/
DEF VAR cLijn AS CHAR NO-UNDO.
DEF VAR cIp AS CHAR NO-UNDO.
DEF VAR iIndex AS INT NO-UNDO.
OS-COMMAND SILENT md C:\TEMP.
OUTPUT TO "C:\TEMP\IPCONFIG.TXT":U.
OS-COMMAND SILENT ipconfig.
OUTPUT CLOSE.
INPUT FROM "C:\TEMP\IPCONFIG.TXT":U.
lus:
REPEAT:
IMPORT UNFORMATTED cLijn.
IF INDEX(cLijn,"IP Address":U) > 0 THEN
DO:
cIp = TRIM(cLijn).
LEAVE lus.
END.
END.
IF LENGTH(cIp) > 0 THEN
DO:
iIndex = INDEX(cIp,":":U).
IF iIndex > 0 THEN
cIp = SUBSTR(cIp,iIndex + 1 ,LENGTH(cIp) - iIndex).
END.
RETURN cIp. /* Function return value. */
END FUNCTION.