Communication between distributed Minerva processes.

Minerva offers an high level interface to support the communication between distributed Minerva programs.

There exists a set of predicates to support the communication between distributed Minerva processes over sockets:

This predicates help you to implement a client/server architecture of your distributed application. You can create channels between clients and servers and send/receive MINERVA terms over these channels.
Client/server architectures with Minerva will have the following structure:

Server

main(..) :-
    ...
    server_start(Port, Backlog, connection_request(_, ...), Server).

connection_request(Socket, ...) :- ... open(Socket, read, Input, [socket,buffered,binary]), open(Socket, write, Output, [socket,buffered,binary]). listener_start(Input, handle_input(_,_,Output,...), Listener).

handle_input(Request, Listener, Output, ...) :- ... % optionally: send(Output, ...) .

Client with sychronous communication

main(..) :-
    ...
    client_start(Hostname, Port, Socket),
    communication_loop(Socket, ...),
    client_stop(Socket).

communication_loop(Socket, ...) :- open(Socket, read, Input, [socket,buffered,binary]), open(Socket, write, Output, [socket,buffered,binary]). repeat, ... send(Output, ...), ... receive(Input, ...) ... .

Client with asychronous communication

main(..) :-
    ...
    client_start(Hostname, Port, Socket),
    open(Socket, read, Input, [socket,buffered,binary]),
    open(Socket, write, Output, [socket,buffered,binary]).
    listener_start(Input, handle_input(_,_,Output,...), Listener).

% handle_output has to be a callback predicate called by some % thread (for example by some gui-request) handle_output(Output, ...) :- ... send(Output, ...).

handle_input(Request, Listener, Output, ...) :- ... % optionally: send(Output, ...) .

Examples:

A simple blackboard system.

main(['-server']) :- !, run_server(1254). main(['-client', Username]) :- !, run_client(localhost, 1254, Username).

% ***** SERVER *************************************************** % should be started with: minerva -daemon -l socktest -server % You have to start exactly one server. The server has to be active % before any client may be activated.

run_server(Port) :- % create a blackboard, which holds the names of the connected clients bb_create(login_names), println([ready]), % starts the server listening on port 'Port'. % if there is a connection request, the predicate user_login/1 % will be called server_start(Port, 3, user_login(_), _).

% handle a connection request from a client user_login(Socket) :- % open binary input and output streams to the client open_connection(Socket, Input, Output), % wait for input from the client. % If a client sends some term with send/2, then the % predicate user_io/3 will be called (the 1st argument will % be set to the transmitted term and the 2nd argument will % be set to the listener object). listener_start(Input, user_io(_,_,Output), _).

% handle a client request user_io(login(Username), Listener, _) :- !, % login request: register the client name println(['login: ', Username]), bb_put(login_names, Listener, Username). user_io(logout, Listener, Output) :- !, % logout request bb_get(login_names, Listener, Username), println(['logout: ', Username]), % unregister the client ... bb_remove(login_names, Output), % ... and close the connection. listener_stop(Listener). user_io(request(Goal), Listener, Output) :- % command request: bb_get(login_names, Listener, Username), println(['request from ', Username, ': ', quoted(Goal)]), % interpret the sended term as goal, execute it ... catch(Goal, _, fail), !, % ... and send the result back to the client. send(Output, Goal). user_io(request(_), _, Output) :- !, % command request: inform the client about the failed command execution send(Output, request_failed).

% ***** CLIENT *************************************************** % should be started with: minerva -l socktest -client % The server can handle more than one client at a time, therefore % you may start many clients. % % example: % minerva -l socktest -client john % ?- assertz(likes(john, anna)). % ... % minerva -l socktest -client anna % ?- likes(Who, anna). % : likes(john, anna) % ...

run_client(Hostname, Port, Username) :- % starts a connection to the server % (which has been started on host 'Hostname' and is listening % on port 'Port' for a connection). client_start(Hostname, Port, Socket), % open binary input and output streams to the server open_connection(Socket, Input, Output), % start the communication loop ... communicate(Input, Output, Username), % ... until the client want's to stop the communication client_stop(Socket).

open_connection(Socket, Input, Output) :- open(Socket, read, Input, [socket,buffered,binary]), open(Socket, write, Output, [socket,buffered,binary]).

communicate(Input,Output,Username) :- % send a login command, announcing the client name to the server send(Output, login(Username)), repeat, % read some goal from standard input write('?- '), flush_output, read(Request), % send the request to the server evaluate_request(Request, Input, Output), Request == end_of_file, !.

evaluate_request(end_of_file,_,Output) :- !, % send a logout command. send(Output, logout). evaluate_request(Request,Input,Output) :- !, % send a user command ... send(Output, request(Request)), % ... wait for the answer ... receive(Input, Answer), % ... and print it to standard output. println([': ', quoted(Answer)]).


client_start/3
client_stop/1
listener_start/3
listener_stop/3
receive/2
send/2
server_start/4
server_stop/1

Darueber read on...