Prolog TCP socket communication (reading before writing)

Greetings all;
I am working with Prolog and Python socket communication using TCP protocol. I have made a Python server that gets request and message from the Prolog client and reverts with a message to the Prolog Client. The Python side is working as desired, however on the Prolog side (client); I want to first read the message received (on In stream) and depending on its value (server sends an array basically) I want to send a message back to the Python server (Out stream): The concerned code is as follows:

:- use_module(library(socket)).
:- use_module(library(streampool)).

create_client(Host, Port) :-                        
        setup_call_catcher_cleanup(tcp_socket(Socket),
                                   tcp_connect(Socket, Host:Port),
                                   exception(_),
                                   tcp_close_socket(Socket)),
        setup_call_cleanup(tcp_open_socket(Socket, Stream),
                           interact(Stream),
                           close_connection(Stream)).

interact(Stream) :-                          
                revert_to_server(Stream),    % this sends reply back to server
                read_string(Stream,L,X),                        
                split_string(X, ",", "", List),
                nth0(0, List, Ps0),
                nth0(7, List, Ps7),
                writeln(Ps0),
                writeln(Ps7).
                
                
interact(Stream) :-
        print_message(warning,'chat failed'),!.
               
revert_to_server(Stream):-
         format(Stream,'~q',Hi),
         flush_output(Stream).
                
                    
close_connection(Stream) :-
        close(Stream, [force(true)]).

The aforementioned code works, however, here first the message is sent to server (using revert_to_server) and then the message received from the server is read. I want the other way round. The issue is, when I move the ‘revert_to_server’ clause at the end of the ‘interact’ predicate (after ‘writeln(Ps7)’), then the predicate just doesn’t work. I searched a lot but couldn’t find any explanation or to do what I want. I somehow feel that flushing the stream in ‘revert_to_server’ destroys it and doesn’t allow it to be used further. In that case, I even tested it with two separate streams (In and Out) but that didn’t work as well. Please aid over the matter.

Thanking you in anticipation.

Searching this site for chat leads to a chat server implemented with Prolog : https://rosettacode.org/wiki/Chat_server#Prolog

HTH


Also to quote text as Prolog source code use ` and not '. See: Language highlighting

Thank you Eric. Will keep that in concern.

I think the problem is with read_string/3, which reads up to end-of-file. So, it may work if the server sends the string and immediately closes its output. Typically you want/need some message boundary, so you can read a message without checking for end-of-file. This can be a newline, a Prolog term (ending in . <white>), first sending a length indication and then the message (e.g., websockets), etc.

Using websockets might be something to look into. You can use them using the HTTP libraries, but also simply over the raw socket.

This seems a good insight to look into. Thanks Jan, will dive into it.

Hello Jan;
I tried following your advice of ‘not reading till the end of file’. I bounded the read_string’s length parameter to a small value so that it only reads a limited number of characters. It didn’t work that way. I tried looking for websockets in Prolog but I feel its only for server side. I couldn’t find it being used as in the client side. Is there a way I can use websockets in the client side?

That suggests the Python side does not flush the output.

No. For HTTP clients there is http_open_websocket/3. Of you want to use websockets over HTTP, that is your choice. You can also use the websocket protocol over any other stream using the low-level stream interface provided by ws_open/3. That acts as a filter on top of a normal stream (socket or anything else) and provides a message oriented API using ws_send/2 and ws_receive/2.

Still, I think proper flushing is your problem.

Thanks again. Will look into it.