Search code examples
c++socketstcpswi-prolog

Sockets in Swipl


So I'm currently in the starting phase of building a game and I'm using prolog as the server side of the game to do validation checks of plays in a board.

I'm having two issues at the moment.

One: Can't seem to close the server without aborting and thus leaving the socket open. Code is as follows

Server:

:- use_module(library(socket)).


create_server(Port) :-
        tcp_socket(Socket),
        tcp_bind(Socket, Port),
        tcp_listen(Socket, 5),
        tcp_open_socket(Socket, AcceptFd, _),
    dispatch(AcceptFd).

dispatch(AcceptFd) :-
        tcp_accept(AcceptFd, Socket, Peer),
        thread_create(process_client(Socket, Peer), _,
                      [ detached(true)
                      ]),
        dispatch(AcceptFd).

process_client(Socket, _Peer) :-
        setup_call_cleanup(tcp_open_socket(Socket, In, Out),
                           handle_service(In, Out),
                           close_connection(In, Out)).

close_connection(In, Out) :-
        close(In, [force(true)]),
        close(Out, [force(true)]).

handle_service(In, Out) :-
    read(In, Int),
    writeln(Int),
    (   Int == end_of_file
    ->  true
    ;   
        call_test(Int,Term),
        format(Out, 'seen(~q).~n', [Term]),
        flush_output(Out),
        handle_service(In, Out)
    ).

call_test(test,Term):-Term = 'really test'.
call_test(validate(teste),Term):-
    String = "validate(test)",
    string_to_list(String,List),
    read_from_chars(List,Stringf),
    writeln(Stringf), 
    Term = 'foo'.

Client:

:- 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, In, Out),
                           chat_to_server(In, Out),
                           close_connection(In, Out)).

chat_to_server(In, Out) :-
        read(Term),
    (   Term == end_of_file
    ->  true
    ;   format(Out, '~q .~n', [Term]),
        flush_output(Out),
        read(In, Reply),
        write(Reply),
        %format('Reply: ~q.~n', [Reply]),
        chat_to_server(In, Out)
    ).

close_connection(In, Out) :-
        close(In, [force(true)]),
        close(Out, [force(true)]).

I can close the client with no issues using ctrl+D (which is end_of_file), but my server doesn't close... It receives end_of_file, it prints end_of_file but it doesn't close. Not even when inserting it directly into the server. What am I doing wrong?

Two: I need to pass a string from C++ to Swipl that has the name of the predicate to use and the arguments. Can someone please tell me how to do this or at least point me in the right direction?

Thank you very much.


Solution

  • One: You can solve that in a simple way or a complicated way. The simple way is restarting not just your server, but also the Prolog interpreter. The complicated one is calling a predicate that cleanly exits the program when a "close" message is received.

    Two: The read/2 predicate, which takes as parameters an input stream (the read end of your socket, in this case) and a variable where the parsed input will be put, does just what you want: it reads a term from the input and converts it to the Prolog term it represents, as if you'd written it in a Prolog program. Note that after the term, the input must contain a dot to tell Prolog the term has ended (as the other answer shows).