Search code examples
socketsopenedgeprogress-4gl

How to use OpenEdge.Net.ServerConnection.ClientSocket?


I was searching for object-oriented way to use Sockets in Progress and found the following document: https://documentation.progress.com/output/oehttpclient/117/index.html?OpenEdge.Net.ServerConnection.ClientSocket.html

I also found the following source code for the class: https://github.com/consultingwerk/ADE-Sourcecode/blob/master/src/netlib/OpenEdge/Net/ServerConnection/ClientSocket.cls

There doesn't seem to exist any kind of information or tutorials about it.

I tried to map out it's usage by looking at the source codes and came up with this:

USING OpenEdge.Net.ServerConnection.ClientSocket.
USING OpenEdge.Net.URI.
USING OpenEdge.Net.ServerConnection.ClientSocketConnectionParameters.

CLASS SocketTest:

    CONSTRUCTOR PUBLIC SocketTest():
        
        DEF VAR clientSocket AS ClientSocket NO-UNDO.
        DEF VAR data         AS LONGCHAR NO-UNDO.
        DEF VAR memptr       AS MEMPTR NO-UNDO.

        /* Create the socket object */
        clientSocket = NEW ClientSocket(
            NEW ClientSocketConnectionParameters(
                new URI("scheme???", "192.162.1.50", "9100")
            )
        ).

        /* Subscribe to 'DataReceived'-event??? */
        clientSocket:DataReceived:Subscribe(THIS-OBJECT, OnDataReceived).
        
        /* Connect */
        clientSocket:Connect().

        /* Send data */
        data = "Hello world!".
        COPY-LOB FROM data TO memptr.
        clientSocket:WriteData(memptr).

        /* Wait for response */
        clientSocket:WaitForResponse().
    )

    METHOD PUBLIC OnDataReceived(poSender AS ClientSocket, poEventArgs AS SocketReadEventArgs):

        DEF VAR longcharData AS LONGCHAR NO-UNDO.
        
        /* Convert the received data to longchar */
        COPY-LOB FROM poEventArgs:Data TO longcharData.
    END.
END.

I'm not sure if the above code can actually receive any data, or if the ClientSocket requires some additional configurations? It would be great to use this same piece of code to send and receive data.

I'd also like to know, could we change this from being a "client" into a "server", meaning the client would be the first one connecting to us, and we would then start sending messages to that client etc?


Solution

  • The ClientSocket class was written as part of the HttpClient implementation, and as you note, isn't really documented as an independent thing. That said, you have the approach right. I would just add an Unsubscribe once you're done - the AVM keeps "cross-references" for subscriptions and so the GC will not clean up the SocketTest or ClientSocket instances.

    A note on the event handler: the event args contains the number of bytes read in the Data MEMPTR - which is (by default) 8k in size. In this example it probably doesn't matter since the COPY-LOB statement will read the data until it hits the first null byte, and should stop there. You can see an example of this in https://github.com/consultingwerk/ADE-Sourcecode/blob/41f3bf2e90cea6537a4717a6b277a9cfcd8dd36e/src/netlib/OpenEdge/Net/HTTP/Lib/ABLSockets/ABLSocketLibrary.cls#L178 .

    The ClientSocketConnectionParameters class has information about the socket - the host, port, SSL options, timeouts etc. The ClientSocket will use that information in its Connect() method. There's an override to let you pass in a ClientSocketConnectionParameters object so you can re-use a ClientSocket object.

    The DataReceived, ReadTimeout and ReadTerminated events are how you consume the data that is returned - or response to other events - from the connected server.

    The ClientSocket is not intended, however, as a server socket. You would have to write your own implementation. AFAIK (as of OpenEdge 12.6) there is not one shipped as part of the OE product.

    Depending on your OE version, you can get newer API doc at https://documentation.progress.com/output/oehttpclient/ - this will redirect you to the latest version, and that page should have links to prior OE versions.

    NEW ClientSocketConnectionParameters( new URI("scheme???", "192.162.1.50", "9100") )

    The scheme here is typically "http" or "https". It's mainly used to define default port values (so 80 for http, and 443 for https). If you provide a port for the URI, then the scheme is just a string.

    The URI class in general is intended to represent URIs per http://tools.ietf.org/html/rfc3986