配布されたMinervaプロセス間の通信

Minervaは、配布されたMinervaプログラム間の通信をサポートするための高レベルのインタフェースを提供します。

ソケットを介して、配布されたMinervaプロセス間での通信をサポートする述語があります。

この述語は、分散アプリケーションのクライアント/サーバ・アーキテクチャを実装するのに役立ちます。 クライアントとサーバ間のチャネルを作り、これらのチャネルを介して、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)]).


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

戻る 続く..