next up previous index
Next: Profiling Prolog Execution Up: Interprocess Communication Previous: Stream Connection Between Two   Index

Datagram Connection with Multiple Machines

This type of communication, which is the most general one offered by ECLiPSe, is similar to the datagram connection on a single machine with the exception that instead of the unix domain the internet domain is used and that any machine which is reachable over the network can participate in the communication.

Since ECLiPSe does not provide a link to the system call sendto(), the address where the packet should be sent to can be specified only using connect/2. If the next packet is to be sent to a different address, a new connect/2 call can be used. The socket can be disconnected by calling connect(s, 0/0).

The functionality of recvfrom() is not available, i.e. the sender has to identify itself explicitly in the message if it wants the receiver to know who the sender was.

Below is an example of a program that starts ECLiPSe on all available machines which are not highly loaded and accepts a hello message from them. Note the use of rsh to invoke the process on the remote machine and pass it the host name and port address.

% Invoke ECLiPSe on all available machines and accept a hello message
% from them.
connect_machines :-
    machine_list(List), % make a list of machines from ruptime
socket(internet, datagram, sigio(s)), % signal when data comes
bind(s, Address),
    set_interrupt_handler(io, io_handler/0),
    connect_machines(List, Address).

% As soon as a message arrives to the socket, the io signal will
% be sent and the handler reads the message.
io_handler :-
    set_flag(enable_interrupts, off),
    read_string(s, "\n", _, Message),
    writeln(Message),
    set_flag(enable_interrupts, on).

% Invoke eclipse on all machines with small load and let them execute
% the start/0 predicate
connect_machines([info(RHost, UpTime, Users, L1, _, _)|Rest], Host/Port) :-
    UpTime > 0, % it is not down
L1 < 0.5, % load not too high
Users < 3, % not too many users
!,
    concat_string(['rsh ', RHost, ' eclipse ', Host, ' ', Port,
        ' -b /home/lp/micha/sepia4/up.pl -e start'], Command),
    printf("sending to %s\n%b", RHost),
exec(Command, [], _),
    connect_machines(Rest, Host/Port).
connect_machines([_|Rest], Address) :-
    connect_machines(Rest, Address).
connect_machines([], _).

% ECLiPSe on remote hosts is invoked with
%          eclipse host port -b file.pl -e start
% It connects to the socket of the main process,
% sends it a hello message and exits.
start :-
    is_built_in(socket/3), % to ignore non-BSD machines
argv(1, SHost),
    argv(2, SPort),
    atom_string(Host, SHost),
    number_string(Port, SPort),
    get_flag(hostname, LHost),
    socket(internet, datagram, s), % create the socket
connect(s, Host/Port), % connect to the main process
printf(s, "hello from %s\n%b", LHost).

% Invoke ruptime(1) and parse its output to a list of accessible
% machines in the form 
%    info(Host, UpTime, Users, Load1, Load2, Load3).
machine_list(List) :-
 % exec/2 cannot be used as it could overflow
% the pipe and then block
    exec('ruptime -l', [null, S], P),
    parse_ruptime(S, List),
    close(S),
    wait(P, _),
    !.

% Parse the output of ruptime
parse_ruptime(S, [Info|List]) :-
    parse_uptime_record(S, Info),
    !,
    parse_ruptime(S, List).
parse_ruptime(_, []).

% parse one line of the ruptime output
parse_uptime_record(S, info(Host, Time, Users, Load1, Load2, Load3)) :-
    read_token(S, Host, _),
    Host \== end_of_file,
    read_token(S, Up, _),
    (Up == up ->
        read_time(S, Time),
        read_token(S, ',', _),
        read_token(S, Users, _),
        read_token(S, _, _),
        read_token(S, ',', _),
        read_token(S, load, _),
        read_token(S, Load1, _),
        read_token(S, ',', _),
        read_token(S, Load2, _),
        read_token(S, ',', _),
        read_token(S, Load3, _)
    ;
        read_time(S, _),
        Time = 0
    ).

% Parse the up/down time and if the machine is down, return 0
read_time(S, Time) :-
    read_token(S, T1, _),
    (read_token(S, +, _) ->
        Days = T1,
        read_token(S, Hours, _),
        read_token(S, :, _)
    ;
        Days = 0,
        Hours = T1
    ),
    read_token(S, Mins, _),
    Time is ((24 * Days) + Hours) * 60 + Mins.

and here is a script of the session:

[eclipse 1]: [up].
up.pl      compiled traceable 4772 bytes in 0.08 seconds

yes.
[eclipse 2]: connect_machines.
sending to mimas3
sending to mimas8
sending to acrab23
sending to europa1
sending to europa5
sending to regulus2
sending to miranda5
sending to mimas2
sending to triton6
sending to europa2
sending to acrab7
sending to europa3
sending to sirius
sending to miranda6
sending to charon6
sending to acrab13
sending to triton1
sending to acrab20
sending to triton4
sending to charon2
sending to triton5
sending to acrab24
sending to acrab21
sending to scorpio
sending to acrab14
sending to janus5
 
yes.
[eclipse 3]: hello from mimas3
eclipse: Command not found. % eclipse not installed here
hello from regulus2
hello from mimas8
hello from acrab20
hello from europa1
hello from mimas2
hello from miranda6
hello from miranda5
hello from europa3
hello from charon6
hello from charon2
hello from acrab24
hello from triton5
hello from acrab21
hello from janus5
hello from triton4
hello from triton6
hello from europa2
hello from europa5
hello from acrab23
hello from triton1
hello from acrab14
hello from acrab13
hello from acrab7

next up previous index
Next: Profiling Prolog Execution Up: Interprocess Communication Previous: Stream Connection Between Two   Index

1999-08-06