| Minervaは、配布されたMinervaプログラム間の通信をサポートするための高レベルのインタフェースを提供します。
ソケットを介して、配布されたMinervaプロセス間での通信をサポートする述語があります。
- server_start/4
- server_stop/1
- client_start/3
- client_stop/1
- listener_start/3
- listener_stop/1
- send/2
- receive/2
この述語は、分散アプリケーションのクライアント/サーバ・アーキテクチャを実装するのに役立ちます。 クライアントとサーバ間のチャネルを作り、これらのチャネルを介して、MINERVA項を送出し/受取ることができます。
Minervaによるクライアント/サーバ・アーキテクチャは、以下の構造を持ちます:
サーバ
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, ...)
.
同期通信によるクライアント
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, ...)
...
.
非同期通信によるクライアント
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, ...)
.
例題:
単純な黒板システムです。
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, than 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)]).
|