Distribution of 0 digits in factorial series: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added Sidef)
m (syntax highlighting fixup automation)
Line 1: Line 1:
{{task|Networking and Web Interaction}}
{{draft task|Mathematics}}


Write two programs (or one program with two modes) which run on networked computers, and send some messages between them.
Large Factorials and the Distribution of '0' in base 10 digits.


The protocol used may be language-specific or not, and should be '''suitable for general distributed programming'''; that is, the ''protocol'' should be generic (not designed just for the particular example application), readily capable of handling the independent communications of many different components of a single application, and the transferring of arbitrary data structures natural for the language.
; About the task:


This task is intended to demonstrate high-level communication facilities beyond just creating [[sockets]].
We can see that some features of factorial numbers (the series of numbers 1!, 2!, 3!, ...)
come about because such numbers are the product of a series of counting numbers, and so those
products have predictable factors. For example, all factorials above 1! are even numbers,
since they have 2 as a factor. Similarly, all factorials from 5! up end in a 0, because they
have 5 and 2 as factors, and thus have 10 as a factor. In fact, the factorial integers add
another 0 at the end of the factorial for every step of 5 upward: 5! = 120, 10! = 3628800,
15! = 1307674368000, 16! = 20922789888000 and so on.


=={{header|Ada}}==
Because factorial numbers, which quickly become quite large, continue to have another terminal 0
{{works with|GNAT GPL|2010}}
on the right hand side of the number for every factor of 5 added to the factorial product, one might
{{works with|PolyORB}}
think that the proportion of zeros in a base 10 factorial number might be close to 1/5. However,
though the factorial products add another terminating 0 every factor of 5 multiplied into the product,
as the numbers become quite large, the number of digits in the factorial product expands exponentially,
and so the number above the terminating zeros tends toward 10% of each digit from 0 to 1 as the factorial
becomes larger. Thus, as the factorials become larger, the proportion of 0 digits in the factorial products
shifts slowly from around 1/5 toward 1/10, since the number of terminating zeros in n! increases only in
proportion to n, whereas the number of digits of n! in base 10 increases exponentially.


Ada defines facilities for distributed systems in its standard (Annex E, also called DSA).
; The task:


This example works with PolyORB and the GNAT GPL 2010 compiler from AdaCore.
Create a function to calculate the mean of the proportions of 0 digits out of the total digits found in each factorial
product from 1! to N!. This proportion of 0 digits in base 10 should be calculated using the number as printed as a base 10 integer.


server.ads:
Example: for 1 to 6 we have 1!, 2!, 3!, 4!, 5!, 6!, or (1, 2, 6, 24, 120, 720), so we need the mean of
<syntaxhighlight lang="ada">package Server is
(0/1, 0/1, 0/1, 0/2, 1/3, 1/3) = (2/3) (totals of each proportion) / 6 (= N), or 0.1111111...
pragma Remote_Call_Interface;
procedure Foo;
function Bar return Natural;
end Server;</syntaxhighlight>


server.adb:
Example: for 1 to 25 the mean of the proportions of 0 digits in the factorial products series of N! with N from 1 to 25 is 0.26787.
<syntaxhighlight lang="ada">package body Server is
Count : Natural := 0;


procedure Foo is
Do this task for 1 to N where N is in (100, 1000, and 10000), so, compute the mean of the proportion of 0 digits for each product
begin
in the series of each of the factorials from 1 to 100, 1 to 1000, and 1 to 10000.
Count := Count + 1;
end Foo;


function Bar return Natural is
; Stretch task:
begin
return Count;
end Bar;
end Server;</syntaxhighlight>


client.adb:
Find the N in 10000 < N < 50000 where the mean of the proportions of 0 digits in the factorial products from 1 to N
<syntaxhighlight lang="ada">with Server;
permanently falls below 0.16. This task took many hours in the Python example, though I wonder if there is a faster
with Ada.Text_IO;
algorithm out there.


procedure Client is
=={{header|11l}}==
begin
{{trans|Python}}
Ada.Text_IO.Put_Line ("Calling Foo...");
Server.Foo;
Ada.Text_IO.Put_Line ("Calling Bar: " & Integer'Image (Server.Bar));
end Client;</syntaxhighlight>


required config (dsa.cfg):
<lang 11l>F facpropzeros(n, verbose = 1B)
<syntaxhighlight lang="ada">configuration DSA is
V proportions = [0.0] * n
pragma Starter (None);
V (fac, psum) = (BigInt(1), 0.0)
L(i) 0 .< n
fac *= i + 1
V d = String(fac)
psum += sum(d.map(x -> Int(x == ‘0’))) / Float(d.len)
proportions[i] = psum / (i + 1)


I verbose
-- Server
Server_Partition : Partition := (Server);
print(‘The mean proportion of 0 in factorials from 1 to #. is #..’.format(n, psum / n))
procedure Run_Server is in Server_Partition;


R proportions
-- Client
Client_Partition : Partition;
for Client_Partition'Termination use Local_Termination;
procedure Client;
for Client_Partition'Main use Client;
end DSA;</syntaxhighlight>


compilation:
L(n) [100, 1000, 10000]
<pre>$po_gnatdist dsa.cfg
facpropzeros(n)</lang>
[...]
------------------------------
---- Configuration report ----
------------------------------
Configuration :
Name : dsa
Main : run_server
Starter : none


Partition server_partition
{{out}}
Main : run_server
<pre>
Units :
The mean proportion of 0 in factorials from 1 to 100 is 0.246753186.
- server (rci)
The mean proportion of 0 in factorials from 1 to 1000 is 0.203544551.
- run_server (normal)
The mean proportion of 0 in factorials from 1 to 10000 is 0.173003848.
- polyorb.dsa_p.partitions (rci, from PCS)
</pre>


Environment variables :
=== Base 1000 version ===
- "POLYORB_DSA_NAME_SERVICE"
<lang 11l>F zinit()
V zc = [0] * 999
L(x) 1..9
zc[x - 1] = 2
zc[10 * x - 1] = 2
zc[100 * x - 1] = 2
L(y) (10.<100).step(10)
zc[y + x - 1] = 1
zc[10 * y + x - 1] = 1
zc[10 * (y + x) - 1] = 1


Partition client_partition
R zc
Main : client
Termination : local
Units :
- client (normal)


Environment variables :
F meanfactorialdigits()
- "POLYORB_DSA_NAME_SERVICE"
V zc = zinit()
V rfs = [1]
V (total, trail, first) = (0.0, 1, 0)
L(f) 2 .< 50000
V (carry, d999, zeroes) = (0, 0, (trail - 1) * 3)
V (j, l) = (trail, rfs.len)
L j <= l | carry != 0
I j <= l
carry = rfs[j - 1] * f + carry


-------------------------------
d999 = carry % 1000
[...]</pre>
I j <= l
rfs[j - 1] = d999
E
rfs.append(d999)


preparation (run PolyORB name service):
zeroes += I d999 == 0 {3} E zc[d999 - 1]
<pre>$ po_ioc_naming
carry I/= 1000
POLYORB_CORBA_NAME_SERVICE=IOR:010000002b00000049444[...]
j++
POLYORB_CORBA_NAME_SERVICE=corbaloc:iiop:1.2@10.200.[...]</pre>


You have to set the environment variable POLYORB_DSA_NAME_SERVICE to one of the two values given by po_ioc_naming for the server/client partitions.
L rfs[trail - 1] == 0
trail++


running server:
d999 = rfs.last
<pre>$ ./server_partition</pre>
d999 = I d999 >= 100 {0} E I d999 < 10 {2} E 1


running client:
zeroes -= d999
<pre>$ ./client_partition
V digits = rfs.len * 3 - d999
Calling Foo...
total += Float(zeroes) / digits
Calling Bar: 1
V ratio = total / f
$ ./client_partition
I f C [100, 1000, 10000]
Calling Foo...
print(‘The mean proportion of zero digits in factorials to #. is #.’.format(f, ratio))
Calling Bar: 2</pre>


=={{header|AutoHotkey}}==
I ratio >= 0.16
See [[Distributed program/AutoHotkey]].
first = 0
E I first == 0
first = f


=={{header|C}}==
print(‘The mean proportion dips permanently below 0.16 at ’first‘.’)
Using PVM [http://www.csm.ornl.gov/pvm/pvm_home.html]
This program is in a sense both a server and a client, depending on if its task is spawned with a command-line argument: if yes, it spawns another task of the same executible on the parallel virtual machine and waits for it to transmit data; if no, it transmits data and is done.
<syntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <pvm3.h>


int main(int c, char **v)
meanfactorialdigits()</lang>
{
int tids[10];
int parent, spawn;
int i_data, i2;
double f_data;


if (c > 1) {
{{out}}
spawn = pvm_spawn("/tmp/a.out", 0, PvmTaskDefault, 0, 1, tids);
<pre>
if (spawn <= 0) {
The mean proportion of zero digits in factorials to 100 is 0.246753186
printf("Can't spawn task\n");
The mean proportion of zero digits in factorials to 1000 is 0.203544551
return 1;
The mean proportion of zero digits in factorials to 10000 is 0.173003848
}
The mean proportion dips permanently below 0.16 at 47332.
</pre>


printf("Spawning successful\n");
=={{header|C++}}==
{{trans|Phix}}
<lang cpp>#include <array>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <vector>


/* pvm_recv(task_id, msgtag). msgtag identifies what kind of data it is,
auto init_zc() {
std::array<int, 1000> zc;
* for here: 1 = (int, double), 2 = (int, int)
* The receiving order is intentionally swapped, just to show.
zc.fill(0);
* task_id = -1 means "receive from any task"
zc[0] = 3;
*/
for (int x = 1; x <= 9; ++x) {
pvm_recv(-1, 2);
zc[x] = 2;
pvm_unpackf("%d %d", &i_data, &i2);
zc[10 * x] = 2;
printf("got msg type 2: %d %d\n", i_data, i2);
zc[100 * x] = 2;

for (int y = 10; y <= 90; y += 10) {
pvm_recv(-1, 1);
zc[y + x] = 1;
pvm_unpackf("%d %lf", &i_data, &f_data);
zc[10 * y + x] = 1;
printf("got msg type 1: %d %f\n", i_data, f_data);
zc[10 * (y + x)] = 1;
} else {
parent = pvm_parent();

pvm_initsend(PvmDataDefault);
i_data = rand();
f_data = (double)rand() / RAND_MAX;
pvm_packf("%d %lf", i_data, f_data);
pvm_send(parent, 1); /* send msg type 1 */

pvm_initsend(PvmDataDefault);
i2 = rand();
pvm_packf("%d %d", i_data, i2);
pvm_send(parent, 2); /* send msg type 2 */
}

pvm_exit();
return 0;
}</syntaxhighlight>{{out}}(running it on PVM console, exe is /tmp/a.out)<syntaxhighlight lang="text">pvm> spawn -> /tmp/a.out 1
spawn -> /tmp/a.out 1
[2]
1 successful
t40028
pvm> [2:t40029] EOF
[2:t40028] Spawning successful
[2:t40028] got msg type 2: 1804289383 1681692777
[2:t40028] got msg type 1: 1804289383 0.394383
[2:t40028] EOF
[2] finished</syntaxhighlight>

=={{header|C sharp|C#}}==
Start the program with "server" parameter to start the server, and "client" to start the client. The client will send data to the server and receive a response. The server will wait for data, display the data received, and send a response.

<syntaxhighlight lang="csharp">
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading.Tasks;

using static System.Console;

class DistributedProgramming
{
const int Port = 555;

async static Task RunClient()
{
WriteLine("Connecting");
var client = new TcpClient();
await client.ConnectAsync("localhost", Port);

using (var stream = client.GetStream())
{
WriteLine("Sending loot");
var data = Serialize(new SampleData());
await stream.WriteAsync(data, 0, data.Length);

WriteLine("Receiving thanks");
var buffer = new byte[80000];
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
var thanks = (string)Deserialize(buffer, bytesRead);
WriteLine(thanks);
}
}

client.Close();
}
}
return zc;
}


async static Task RunServer()
template <typename clock_type>
{
auto elapsed(const std::chrono::time_point<clock_type>& t0) {
auto t1 = clock_type::now();
WriteLine("Listening");
var listener = new TcpListener(IPAddress.Any, Port);
auto duration =
listener.Start();
std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
var client = await listener.AcceptTcpClientAsync();
return duration.count();
}


using (var stream = client.GetStream())
int main() {
auto zc = init_zc();
{
WriteLine("Receiving loot");
auto t0 = std::chrono::high_resolution_clock::now();
int trail = 1, first = 0;
var buffer = new byte[80000];
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
double total = 0;
var data = (SampleData)Deserialize(buffer, bytesRead);
std::vector<int> rfs{1};
WriteLine($"{data.Loot} at {data.Latitude}, {data.Longitude}");
std::cout << std::fixed << std::setprecision(10);

for (int f = 2; f <= 50000; ++f) {
WriteLine("Sending thanks");
int carry = 0, d999, zeroes = (trail - 1) * 3, len = rfs.size();
for (int j = trail - 1; j < len || carry != 0; ++j) {
var thanks = Serialize("Thanks!");
if (j < len)
await stream.WriteAsync(thanks, 0, thanks.Length);
carry += rfs[j] * f;
d999 = carry % 1000;
if (j < len)
rfs[j] = d999;
else
rfs.push_back(d999);
zeroes += zc[d999];
carry /= 1000;
}
}

while (rfs[trail - 1] == 0)
++trail;
client.Close();
d999 = rfs.back();
listener.Stop();
d999 = d999 < 100 ? (d999 < 10 ? 2 : 1) : 0;
Write("Press a key");
zeroes -= d999;
ReadKey();
}
int digits = rfs.size() * 3 - d999;

total += double(zeroes) / digits;
static byte[] Serialize(object data)
double ratio = total / f;
{
if (ratio >= 0.16)
first = 0;
using (var mem = new MemoryStream())
else if (first == 0)
{
first = f;
new BinaryFormatter().Serialize(mem, data);
if (f == 100 || f == 1000 || f == 10000) {
return mem.ToArray();
std::cout << "Mean proportion of zero digits in factorials to " << f
<< " is " << ratio << ". (" << elapsed(t0) << "ms)\n";
}
}
}
}
std::cout << "The mean proportion dips permanently below 0.16 at " << first
<< ". (" << elapsed(t0) << "ms)\n";
}</lang>


static object Deserialize(byte[] data, int length)
{{out}}
{
<pre>
using (var mem = new MemoryStream(data, 0, length))
Mean proportion of zero digits in factorials to 100 is 0.2467531862. (0ms)
{
Mean proportion of zero digits in factorials to 1000 is 0.2035445511. (1ms)
return new BinaryFormatter().Deserialize(mem);
Mean proportion of zero digits in factorials to 10000 is 0.1730038482. (152ms)
}
The mean proportion dips permanently below 0.16 at 47332. (4598ms)
}
</pre>

static void Main(string[] args)
{
if (args.Length == 0) return;

switch (args[0])
{
case "client": RunClient().Wait(); break;
case "server": RunServer().Wait(); break;
}
}
}

[Serializable]
class SampleData
{
public decimal Latitude = 44.33190m;
public decimal Longitude = 114.84129m;
public string Loot = "140 tonnes of jade";
}
</syntaxhighlight>

=={{header|D}}==
Uses the <b>rpc</b> library:
https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff/blob/master/rpc.d

This library is not standard, so this code (by Adam D. Ruppe) could and should be rewritten using more standard means.
<syntaxhighlight lang="d">import arsd.rpc;

struct S1 {
int number;
string name;
}

struct S2 {
string name;
int number;
}

interface ExampleNetworkFunctions {
string sayHello(string name);
int add(in int a, in int b) const pure nothrow;
S2 structTest(S1);
void die();
}

// The server must implement the interface.
class ExampleServer : ExampleNetworkFunctions {
override string sayHello(string name) {
return "Hello, " ~ name;
}

override int add(in int a, in int b) const pure nothrow {
return a + b;
}

override S2 structTest(S1 a) {
return S2(a.name, a.number);
}

override void die() {
throw new Exception("death requested");
}

mixin NetworkServer!ExampleNetworkFunctions;
}

class Client {
mixin NetworkClient!ExampleNetworkFunctions;
}

void main(in string[] args) {
import std.stdio;

if (args.length > 1) {
auto client = new Client("localhost", 5005);
// These work like the interface above, but instead of
// returning the value, they take callbacks for success (where
// the arg is the retval) and failure (the arg is the
// exception).
client.sayHello("whoa", (a) { writeln(a); }, null);
client.add(1,2, (a){ writeln(a); }, null);
client.add(10,20, (a){ writeln(a); }, null);
client.structTest(S1(20, "cool!"),
(a){ writeln(a.name, " -- ", a.number); },
null);
client.die(delegate(){ writeln("shouldn't happen"); },
delegate(a){ writeln(a); });
client.eventLoop;
} else {
auto server = new ExampleServer(5005);
server.eventLoop;
}
}</syntaxhighlight>

=={{header|E}}==
'''Protocol:''' Pluribus

This service cannot be used except by clients which know the URL designating it, messages are encrypted, and the client authenticates the server. However, it is vulnerable to denial-of-service by any client knowing the URL.

=== Server ===

(The protocol is symmetric; this program is the server only in that it is the one which is started first and exports an object.)

<syntaxhighlight lang="e">def storage := [].diverge()

def logService {
to log(line :String) {
storage.push([timer.now(), line])
}
to search(substring :String) {
var matches := []
for [time, line] ? (line.startOf(substring) != -1) in storage {
matches with= [time, line]
}
return matches
}
}

introducer.onTheAir()
def sturdyRef := makeSturdyRef.temp(logService)
println(<captp>.sturdyToURI(sturdyRef))
interp.blockAtTop()</syntaxhighlight>

This will print the URL of the service and run it until aborted.

=== Client ===

The URL provided by the server is given as the argument to this program.

<syntaxhighlight lang="e">def [uri] := interp.getArgs()
introducer.onTheAir()
def sturdyRef := <captp>.sturdyFromURI(uri)
def logService := sturdyRef.getRcvr()

logService <- log("foot")
logService <- log("shoe")

println("Searching...")
when (def result := logService <- search("foo")) -> {
for [time, line] in result {
println(`At $time: $line`)
}
}</syntaxhighlight>

=={{header|Erlang}}==
The protocol is erlang's own
=== Server ===
srv.erl

<syntaxhighlight lang="erlang">-module(srv).
-export([start/0, wait/0]).

start() ->
net_kernel:start([srv,shortnames]),
erlang:set_cookie(node(), rosetta),
Pid = spawn(srv,wait,[]),
register(srv,Pid),
io:fwrite("~p ready~n",[node(Pid)]),
ok.

wait() ->
receive
{echo, Pid, Any} ->
io:fwrite("-> ~p from ~p~n", [Any, node(Pid)]),
Pid ! {hello, Any},
wait();
Any -> io:fwrite("Error ~p~n", [Any])
end.</syntaxhighlight>

=== Client ===
client.erl

<syntaxhighlight lang="erlang">-module(client).
-export([start/0, wait/0]).

start() ->
net_kernel:start([client,shortnames]),
erlang:set_cookie(node(), rosetta),
{ok,[[Srv]]} = init:get_argument(server),
io:fwrite("connecting to ~p~n", [Srv]),
{srv, list_to_atom(Srv)} ! {echo,self(), hi},
wait(),
ok.

wait() ->
receive
{hello, Any} -> io:fwrite("Received ~p~n", [Any]);
Any -> io:fwrite("Error ~p~n", [Any])
end.</syntaxhighlight>

running it (*comes later)
|erlc srv.erl
|erl -run srv start -noshell
srv@agneyam ready
*-> hi from client@agneyam

|erlc client.erl
|erl -run client start -run init stop -noshell -server srv@agneyam
connecting to "srv@agneyam"
Received hi

=={{header|Factor}}==
The protocol is the one provided by Factor (concurrency.distributed, concurrency.messaging)

Example summary:

- A server node is listening for messages made of natural data types and structures, and simply prettyprint them.

- A client node is sending such data structure: an array of one string and one hashtable (with one key/value pair).

===Server===
<syntaxhighlight lang="factor">USING: concurrency.distributed concurrency.messaging threads io.sockets io.servers ;
QUALIFIED: concurrency.messaging
: prettyprint-message ( -- ) concurrency.messaging:receive . flush prettyprint-message ;
[ prettyprint-message ] "logger" spawn dup name>> register-remote-thread
"127.0.0.1" 9000 <inet4> <node-server> start-server</syntaxhighlight>

Note: we are using QUALIFIED: with the concurrency.messaging vocabulary because the "receive" word is defined in io.sockets vocabulary too. If someone have a cleaner way to handle this.

===Client===
<syntaxhighlight lang="factor">USING: concurrency.distributed io.sockets ;
QUALIFIED: concurrency.messaging
{ "Hello Remote Factor!" H{ { "key1" "value1" } } }
"127.0.0.1" 9000 <inet4> "logger" <remote-thread> concurrency.messaging:send</syntaxhighlight>

How to Run:

- Copy/Paste the server code in an instance of Factor Listener

- Copy/Paste the client code in another instance of Factor Listener.

The server node should prettyprint the data structure send by the client: { "Hello Remote Factor!" H{ { "key1" "value1" } } }


=={{header|Go}}==
=={{header|Go}}==
===Brute force===
===Standard library net/rpc===
Package net/rpc in the Go standard library serializes data with the Go-native "gob" type. The example here sends only a single floating point number, but the package will send any user-defined data type, including of course structs with multiple fields.
{{libheader|GMP(Go wrapper)}}

{{libheader|Go-rcu}}
'''Server:'''
Timings here are 2.8 seconds for the basic task and 182.5 seconds for the stretch goal.
<lang go>package main
<syntaxhighlight lang="go">package main

import (
"errors"
"log"
"net"
"net/http"
"net/rpc"
)

type TaxComputer float64

func (taxRate TaxComputer) Tax(x float64, r *float64) error {
if x < 0 {
return errors.New("Negative values not allowed")
}
*r = x * float64(taxRate)
return nil
}

func main() {
c := TaxComputer(.05)
rpc.Register(c)
rpc.HandleHTTP()
listener, err := net.Listen("tcp", ":1234")
if err != nil {
log.Fatal(err)
}
http.Serve(listener, nil)
}</syntaxhighlight>
'''Client:'''
<syntaxhighlight lang="go">package main


import (
import (
"fmt"
"fmt"
big "github.com/ncw/gmp"
"log"
"rcu"
"net/rpc"
)
)


func main() {
func main() {
fact := big.NewInt(1)
client, err := rpc.DialHTTP("tcp", "localhost:1234")
sum := 0.0
if err != nil {
first := int64(0)
fmt.Println(err)
firstRatio := 0.0
return
fmt.Println("The mean proportion of zero digits in factorials up to the following are:")
for n := int64(1); n <= 50000; n++ {
fact.Mul(fact, big.NewInt(n))
bytes := []byte(fact.String())
digits := len(bytes)
zeros := 0
for _, b := range bytes {
if b == '0' {
zeros++
}
}
sum += float64(zeros)/float64(digits)
ratio := sum / float64(n)
if n == 100 || n == 1000 || n == 10000 {
fmt.Printf("%6s = %12.10f\n", rcu.Commatize(int(n)), ratio)
}
if first > 0 && ratio >= 0.16 {
first = 0
firstRatio = 0.0
} else if first == 0 && ratio < 0.16 {
first = n
firstRatio = ratio
}
}
}
fmt.Printf("%6s = %12.10f", rcu.Commatize(int(first)), firstRatio)
fmt.Println(" (stays below 0.16 after this)")
fmt.Printf("%6s = %12.10f\n", "50,000", sum / 50000)
}</lang>


amount := 3.
{{out}}
var tax float64
err = client.Call("TaxComputer.Tax", amount, &tax)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Tax on %.2f: %.2f\n", amount, tax)
}</syntaxhighlight>
{{out | Client output}}
<pre>
<pre>
Tax on 3.00: 0.15
The mean proportion of zero digits in factorials up to the following are:
100 = 0.2467531862
1,000 = 0.2035445511
10,000 = 0.1730038482
47,332 = 0.1599999958 (stays below 0.16 after this)
50,000 = 0.1596200546
</pre>
</pre>
===gRPC===
<br>
See http://www.grpc.io/
==='String math' and base 1000===

{{trans|Phix}}
The default serialization for gRPC is "protocol buffers." gRPC uses a .proto file to define an interface for the client and server. The .proto has its own syntax, independent of client and server implementation languages. Server and client programs here are Go however.
Much quicker than before with 10,000 now being reached in 0.35 seconds and the stretch goal in about 5.5 seconds.

<lang go>package main
'''.proto:'''
<syntaxhighlight lang="proto">syntax = "proto3";

service TaxComputer {
rpc Tax(Amount) returns (Amount) {}
}

message Amount {
int32 cents = 1;
}</syntaxhighlight>
'''Server:'''
<syntaxhighlight lang="go">package main


import (
import (
"fmt"
"errors"
"rcu"
"net"

"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"

"taxcomputer"
)
)


type taxServer struct {
var rfs = []int{1} // reverse factorial(1) in base 1000
rate float64
var zc = make([]int, 999)
}


func (s *taxServer) Tax(ctx context.Context,
func init() {
amt *taxcomputer.Amount) (*taxcomputer.Amount, error) {
for x := 1; x <= 9; x++ {
if amt.Cents < 0 {
zc[x-1] = 2 // 00x
return nil, errors.New("Negative amounts not allowed")
zc[10*x-1] = 2 // 0x0
zc[100*x-1] = 2 // x00
var y = 10
for y <= 90 {
zc[y+x-1] = 1 // 0yx
zc[10*y+x-1] = 1 // y0x
zc[10*(y+x)-1] = 1 // yx0
y += 10
}
}
}
return &taxcomputer.Amount{int32(float64(amt.Cents)*s.rate + .5)}, nil
}
}


func main() {
func main() {
listener, err := net.Listen("tcp", ":1234")
total := 0.0
trail := 1
if err != nil {
grpclog.Fatalf(err.Error())
first := 0
firstRatio := 0.0
fmt.Println("The mean proportion of zero digits in factorials up to the following are:")
for f := 2; f <= 10000; f++ {
carry := 0
d999 := 0
zeros := (trail - 1) * 3
j := trail
l := len(rfs)
for j <= l || carry != 0 {
if j <= l {
carry = rfs[j-1]*f + carry
}
d999 = carry % 1000
if j <= l {
rfs[j-1] = d999
} else {
rfs = append(rfs, d999)
}
if d999 == 0 {
zeros += 3
} else {
zeros += zc[d999-1]
}
carry /= 1000
j++
}
for rfs[trail-1] == 0 {
trail++
}
// d999 = quick correction for length and zeros
d999 = rfs[len(rfs)-1]
if d999 < 100 {
if d999 < 10 {
d999 = 2
} else {
d999 = 1
}
} else {
d999 = 0
}
zeros -= d999
digits := len(rfs)*3 - d999
total += float64(zeros) / float64(digits)
ratio := total / float64(f)
if ratio >= 0.16 {
first = 0
firstRatio = 0.0
} else if first == 0 {
first = f
firstRatio = ratio
}
if f == 100 || f == 1000 || f == 10000 {
fmt.Printf("%6s = %12.10f\n", rcu.Commatize(f), ratio)
}
}
}
grpcServer := grpc.NewServer()
fmt.Printf("%6s = %12.10f", rcu.Commatize(first), firstRatio)
taxcomputer.RegisterTaxComputerServer(grpcServer, &taxServer{.05})
fmt.Println(" (stays below 0.16 after this)")
grpcServer.Serve(listener)
fmt.Printf("%6s = %12.10f\n", "50,000", total/50000)
}</lang>
}</syntaxhighlight>
'''Client:'''
<syntaxhighlight lang="go">package main


import (
{{out}}
"fmt"

"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"

"taxcomputer"
)

func main() {
conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
if err != nil {
grpclog.Fatalf(err.Error())
}
defer conn.Close()
client := taxcomputer.NewTaxComputerClient(conn)
amt := &taxcomputer.Amount{300}
tax, err := client.Tax(context.Background(), amt)
if err != nil {
grpclog.Fatalf(err.Error())
}
fmt.Println("Tax on", amt.Cents, "cents is", tax.Cents, "cents")
}</syntaxhighlight>
{{out | Client output}}
<pre>
<pre>
Tax on 300 cents is 15 cents
Same as 'brute force' version.
</pre>
</pre>


=={{header|jq}}==
===Apache Thrift===
See https://thrift.apache.org/
'''Works with jq'''


'''.thrift'''
The precision of jq's integer arithmetic is not up to this task, so in the following we borrow from the "BigInt" library and use a string representation of integers.


Like gRPC, Thrift requires a language independent interface definition file:
Unfortunately, although gojq (the Go implementation of jq) does support unbounded-precision integer arithmetic, it is unsuited for the task because of memory management issues.
<syntaxhighlight lang="thrift">service TaxService {
i32 tax(1: i32 amt)
}</syntaxhighlight>
'''Server:'''
<syntaxhighlight lang="go">package main


import (
'''From BigInt.jq'''
"errors"
<lang jq>
"log"
# multiply two decimal strings, which may be signed (+ or -)
def long_multiply(num1; num2):


"git.apache.org/thrift.git/lib/go/thrift"
def stripsign:
.[0:1] as $a
| if $a == "-" then [ -1, .[1:]]
elif $a == "+" then [ 1, .[1:]]
else [1, .]
end;


"gen-go/tax"
def adjustsign(sign):
)
if sign == 1 then . else "-" + . end;


type taxHandler float64
# mult/2 assumes neither argument has a sign
def mult(num1;num2):
(num1 | explode | map(.-48) | reverse) as $a1
| (num2 | explode | map(.-48) | reverse) as $a2
| reduce range(0; num1|length) as $i1
([]; # result
reduce range(0; num2|length) as $i2
(.;
($i1 + $i2) as $ix
| ( $a1[$i1] * $a2[$i2] + (if $ix >= length then 0 else .[$ix] end) ) as $r
| if $r > 9 # carrying
then
.[$ix + 1] = ($r / 10 | floor) + (if $ix + 1 >= length then 0 else .[$ix + 1] end )
| .[$ix] = $r - ( $r / 10 | floor ) * 10
else
.[$ix] = $r
end
)
)
| reverse | map(.+48) | implode;


func (r taxHandler) Tax(amt int32) (int32, error) {
(num1|stripsign) as $a1
if amt < 0 {
| (num2|stripsign) as $a2
return 0, errors.New("Negative amounts not allowed")
| if $a1[1] == "0" or $a2[1] == "0" then "0"
}
elif $a1[1] == "1" then $a2[1]|adjustsign( $a1[0] * $a2[0] )
return int32(float64(amt)*float64(r) + .5), nil
elif $a2[1] == "1" then $a1[1]|adjustsign( $a1[0] * $a2[0] )
}
else mult($a1[1]; $a2[1]) | adjustsign( $a1[0] * $a2[0] )
end;
</lang>
'''The task'''
<lang jq>
def count(s): reduce s as $x (0; .+1);


func main() {
def meanfactorialdigits:
transport, err := thrift.NewTServerSocket("localhost:3141")
def digits: tostring | explode;
if err != nil {
def nzeros: count( .[] | select(. == 48) ); # "0" is 48
log.Fatal(err)
. as $N
}
transFac := thrift.NewTTransportFactory()
| 0.16 as $goal
protoFac := thrift.NewTCompactProtocolFactory()
| label $out
proc := tax.NewTaxServiceProcessor(taxHandler(.05))
| reduce range( 1; 1+$N ) as $i ( {factorial: "1", proportionsum: 0.0, first: null };
s := thrift.NewTSimpleServer4(proc, transport, transFac, protoFac)
.factorial = long_multiply(.factorial; $i|tostring)
| (.factorial|digits) as $d
if err := s.Serve(); err != nil {
| .proportionsum += ($d | (nzeros / length))
log.Fatal(err)
}
| (.proportionsum / $i) as $propmean
}</syntaxhighlight>
| if .first
'''Client:'''
then if $propmean > $goal then .first = null else . end
<syntaxhighlight lang="go">package main
elif $propmean <= $goal then .first = $i
else .
end)
| "Mean proportion of zero digits in factorials to \($N) is \(.proportionsum/$N);" +
(if .first then " mean <= \($goal) from N=\(.first) on." else " goal (\($goal)) unmet." end);


import (
# The task:
"fmt"
100, 1000, 10000 | meanfactorialdigits</lang>
"log"
{{out}}

"git.apache.org/thrift.git/lib/go/thrift"

"gen-go/tax"
)

func main() {
transport, err := thrift.NewTSocket("localhost:3141")
if err != nil {
log.Fatal(err)
}
if err := transport.Open(); err != nil {
log.Fatal(err)
}
protoFac := thrift.NewTCompactProtocolFactory()
client := tax.NewTaxServiceClientFactory(transport, protoFac)
amt := int32(300)
t, err := client.Tax(amt)
if err != nil {
log.Print(err)
} else {
fmt.Println("tax on", amt, "is", t)
}
transport.Close()
}</syntaxhighlight>
{{out | Client output}}
<pre>
<pre>
tax on 300 is 15
Mean proportion of zero digits in factorials to 100 is 0.24675318616743216; goal (0.16) unmet.
Mean proportion of zero digits in factorials to 1000 is 0.20354455110316458; goal (0.16) unmet.
Mean proportion of zero digits in factorials to 10000 is 0.17300384824186707; goal (0.16) unmet.
</pre>
</pre>

=={{header|Haskell}}==
See:

* http://www.haskell.org/haskellwiki/HaXR#Server
* http://www.haskell.org/haskellwiki/HaXR#Client

Check license:
http://www.haskell.org/haskellwiki/HaskellWiki:Copyrights

=={{header|JavaScript}}==

{{works with|node.js}}

===Server===

<syntaxhighlight lang="javascript">var net = require('net')

var server = net.createServer(function (c){
c.write('hello\r\n')
c.pipe(c) // echo messages back
})

server.listen(3000, 'localhost')
</syntaxhighlight>

===Client===
<syntaxhighlight lang="javascript">var net = require('net')

conn = net.createConnection(3000, '192.168.1.x')

conn.on('connect', function(){
console.log('connected')
conn.write('test')
})

conn.on('data', function(msg){
console.log(msg.toString())
})</syntaxhighlight>


=={{header|Julia}}==
=={{header|Julia}}==
Julia was designed with distributed conmputing. in particular cluster computing, as a primary use target.
<lang julia>function meanfactorialdigits(N, goal = 0.0)
If a group of CPUs, including multiple cores on a single machine or a cluster running with paswordless ssh login, is used,
factoril, proportionsum = big"1", 0.0
the following can be set up as an example:
for i in 1:N
<syntaxhighlight lang="julia"># From Julia 1.0's online docs. File countheads.jl available to all machines:
factoril *= i

d = digits(factoril)
function count_heads(n)
zero_proportion_in_fac = count(x -> x == 0, d) / length(d)
c::Int = 0
proportionsum += zero_proportion_in_fac
propmean = proportionsum / i
for i = 1:n
if i > 15 && propmean <= goal
c += rand(Bool)
println("The mean proportion dips permanently below $goal at $i.")
break
end
if i == N
println("Mean proportion of zero digits in factorials to $N is ", propmean)
end
end
end
c
end
end</syntaxhighlight>
We then run the following on the primary client:
<syntaxhighlight lang="julia">
using Distributed
@everywhere include_string(Main, $(read("count_heads.jl", String)), "count_heads.jl")


a = @spawn count_heads(100000000) # runs on an available processor
@time foreach(meanfactorialdigits, [100, 1000, 10000])
b = @spawn count_heads(100000000) # runs on another available processor


println(fetch(a)+fetch(b)) # total heads of 200 million coin flips, half on each CPU
@time meanfactorialdigits(50000, 0.16)
</syntaxhighlight> {{output}} <pre>
</lang>{{out}}
100001564
<pre>
Mean proportion of zero digits in factorials to 100 is 0.24675318616743216
Mean proportion of zero digits in factorials to 1000 is 0.20354455110316458
Mean proportion of zero digits in factorials to 10000 is 0.17300384824186707
3.030182 seconds (297.84 k allocations: 1.669 GiB, 0.83% gc time, 0.28% compilation time)
The mean proportion dips permanently below 0.16 at 47332.
179.157788 seconds (3.65 M allocations: 59.696 GiB, 1.11% gc time)
</pre>
</pre>


=={{header|LFE}}==
=== Base 1000 version ===
{{trans|Pascal, Phix}}
<lang julia>function init_zc()
zc = zeros(Int, 999)
for x in 1:9
zc[x] = 2 # 00x
zc[10*x] = 2 # 0x0
zc[100*x] = 2 # x00
for y in 10:10:90
zc[y+x] = 1 # 0yx
zc[10*y+x] = 1 # y0x
zc[10*(y+x)] = 1 # yx0
end
end
return zc
end


The protocol used is the one native to Erlang (and thus native to LFE, Lisp Flavored Erlang).
function meanfactorialzeros(N = 50000, verbose = true)
zc = init_zc()
rfs = [1]


These examples are done completely in the LFE REPL.
total, trail, first, firstratio = 0.0, 1, 0, 0.0


===Server===
for f in 2:N
carry, d999, zeroes = 0, 0, (trail - 1) * 3
j, l = trail, length(rfs)
while j <= l || carry != 0
if j <= l
carry = (rfs[j]) * f + carry
end
d999 = carry % 1000
if j <= l
rfs[j] = d999
else
push!(rfs, d999)
end
zeroes += (d999 == 0) ? 3 : zc[d999]
carry ÷= 1000
j += 1
end
while rfs[trail] == 0
trail += 1
end
# d999 = quick correction for length and zeroes:
d999 = rfs[end]
d999 = d999 < 100 ? d999 < 10 ? 2 : 1 : 0
zeroes -= d999
digits = length(rfs) * 3 - d999
total += zeroes / digits
ratio = total / f
if ratio >= 0.16
first = 0
firstratio = 0.0
elseif first == 0
first = f
firstratio = ratio
end
if f in [100, 1000, 10000]
verbose && println("Mean proportion of zero digits in factorials to $f is $ratio")
end
end
verbose && println("The mean proportion dips permanently below 0.16 at $first.")
end


In one terminal window, start up the REPL
meanfactorialzeros(100, false)
@time meanfactorialzeros()
</lang>{{out}}
<pre>
Mean proportion of zero digits in factorials to 100 is 0.24675318616743216
Mean proportion of zero digits in factorials to 1000 is 0.20354455110316458
Mean proportion of zero digits in factorials to 10000 is 0.17300384824186707
The mean proportion dips permanently below 0.16 at 47332.
4.638323 seconds (50.08 k allocations: 7.352 MiB)
</pre>


<syntaxhighlight lang="bash">
=={{header|Mathematica}}/{{header|Wolfram Language}}==
$ ./bin/lfe
<lang Mathematica>ClearAll[ZeroDigitsFractionFactorial]
Erlang/OTP 17 [erts-6.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
ZeroDigitsFractionFactorial[n_Integer] := Module[{m},
m = IntegerDigits[n!];
Count[m, 0]/Length[m]
]
ZeroDigitsFractionFactorial /@ Range[6] // Mean // N
ZeroDigitsFractionFactorial /@ Range[25] // Mean // N
ZeroDigitsFractionFactorial /@ Range[100] // Mean // N
ZeroDigitsFractionFactorial /@ Range[1000] // Mean // N
ZeroDigitsFractionFactorial /@ Range[10000] // Mean // N


LFE Shell V6.2 (abort with ^G)
fracs = ParallelMap[ZeroDigitsFractionFactorial, Range[50000], Method -> ("ItemsPerEvaluation" -> 100)];
>
means = Accumulate[N@fracs]/Range[Length[fracs]];
</syntaxhighlight>
len = LengthWhile[Reverse@means, # < 0.16 &];

50000 - len + 1</lang>
And then enter the following code
{{out}}

<pre>0.111111
<syntaxhighlight lang="lisp">
0.267873
> (defun get-server-name ()
0.246753
(list_to_atom (++ "exampleserver@" (element 2 (inet:gethostname)))))
0.203545

0.173004
> (defun start ()
47332</pre>
(net_kernel:start `(,(get-server-name) shortnames))
(erlang:set_cookie (node) 'rosettaexample)
(let ((pid (spawn #'listen/0)))
(register 'serverref pid)
(io:format "~p ready~n" (list (node pid)))
'ok))

> (defun listen ()
(receive
(`#(echo ,pid ,data)
(io:format "Got ~p from ~p~n" (list data (node pid)))
(! pid `#(hello ,data))
(listen))
(x
(io:format "Unexpected pattern: ~p~n" `(,x)))))
</syntaxhighlight>

===Client===

In another terminal window, start up another LFE REPL and ender the following code:

<syntaxhighlight lang="lisp">
> (defun get-server-name ()
(list_to_atom (++ "exampleserver@" (element 2 (inet:gethostname)))))

> (defun send (data)
(net_kernel:start '(exampleclient shortnames))
(erlang:set_cookie (node) 'rosettaexample)
(io:format "connecting to ~p~n" `(,(get-server-name)))
(! `#(serverref ,(get-server-name)) `#(echo ,(self) ,data))
(receive
(`#(hello ,data)
(io:format "Received ~p~n" `(,data)))
(x
(io:format "Unexpected pattern: ~p~n" (list x))))
'ok)
</syntaxhighlight>

To use this code, simply start the server in the server terminal:

<syntaxhighlight lang="lisp">
> (start)
exampleserver@yourhostname ready
ok
(exampleserver@yourhostname)>
</syntaxhighlight>

Send some messages from the client terminal:

<syntaxhighlight lang="lisp">
> (send "hi there")
connecting to exampleserver@yourhostname
Received "hi there"
ok
(exampleclient@yourhostname)> (send 42)
connecting to exampleserver@yourhostname
Received 42
ok
(exampleclient@yourhostname)> (send #(key value))
connecting to exampleserver@yourhostname
Received {key,value}
ok
(exampleclient@yourhostname)>
</syntaxhighlight>

And check out the results back in the server terminal window:

<syntaxhighlight lang="lisp">
Got "hi there" from exampleclient@yourhostname
Got 42 from exampleclient@yourhostname
Got {key,value} from exampleclient@yourhostname
</syntaxhighlight>

=={{header|Mathematica}} / {{header|Wolfram Language}}==
The following sends a request for a random number to be generated on each of two nodes, these are then transmitted back to be assembled into an array with two elements. Omitting the first line, will cause the program to be run on all configured remote computers.
<syntaxhighlight lang="mathematica">LaunchKernels[2];
ParallelEvaluate[RandomReal[]]
</syntaxhighlight>


=={{header|Nim}}==
=={{header|Nim}}==
{{libheader|nanomsg}}
<syntaxhighlight lang="nim">import os, nanomsg


proc sendMsg(s: cint, msg: string) =
===Task===
echo "SENDING \"",msg,"\""
{{libheader|bignum}}
let bytes = s.send(msg.cstring, msg.len + 1, 0)
<lang Nim>import strutils, std/monotimes
assert bytes == msg.len + 1
import bignum


proc recvMsg(s: cint) =
let t0 = getMonoTime()
var buf: cstring
var sum = 0.0
let bytes = s.recv(addr buf, MSG, 0)
var f = newInt(1)
if bytes > 0:
var lim = 100
echo "RECEIVED \"",buf,"\""
for n in 1..10_000:
discard freemsg buf
f *= n
let str = $f
sum += str.count('0') / str.len
if n == lim:
echo n, ":\t", sum / float(n)
lim *= 10
echo()
echo getMonoTime() - t0</lang>


proc sendRecv(s: cint, msg: string) =
{{out}}
var to: cint = 100
<pre>100: 0.2467531861674322
discard s.setSockOpt(SOL_SOCKET, RCVTIMEO, addr to, sizeof to)
1000: 0.2035445511031646
while true:
10000: 0.1730038482418671
s.recvMsg
sleep 1000
s.sendMsg msg


proc node0(url: string) =
(seconds: 2, nanosecond: 857794404)</pre>
var s = socket(AF_SP, nanomsg.PAIR)
assert s >= 0
let res = s.bindd url
assert res >= 0
s.sendRecv "node0"
discard s.shutdown 0


proc node1(url: string) =
===Stretch task===
var s = socket(AF_SP, nanomsg.PAIR)
{{libheader|bignum}}
assert s >= 0
At each step, we eliminate the trailing zeroes to reduce the length of the number and save some time. But this is not much, about 8%.
let res = s.connect url
assert res >= 0
s.sendRecv "node1"
discard s.shutdown 0


if paramStr(1) == "node0":
<lang Nim>import strutils, std/monotimes
node0 paramStr(2)
import bignum
elif paramStr(1) == "node1":
node1 paramStr(2)</syntaxhighlight>
Usage:
<pre>./pair node0 tcp://127.0.0.1:25000
./pair node1 tcp://127.0.0.1:25000</pre>


=={{header|Objective-C}}==
let t0 = getMonoTime()
Distributed Objects are ''natural'' to Objective-C, and OpenStep and derivated framework offers an easy way of ''using'' remote objects as if it were local. The client must only know the protocol the remote object support. For the rest, calling a remote object's method or local object's method is transparent.
var sum = 0.0
var first = 0
var f = newInt(1)
var count0 = 0
for n in 1..<50_000:
f *= n
while f mod 10 == 0: # Reduce the length of "f".
f = f div 10
inc count0
let str = $f
sum += (str.count('0') + count0) / (str.len + count0)
if sum / float(n) < 0.16:
if first == 0: first = n
else:
first = 0


{{works with|GNUstep}}
echo "Permanently below 0.16 at n = ", first
===Server===
echo "Execution time: ", getMonoTime() - t0</lang>
The server ''vending'' the object with the name <tt>DistributedAction</tt>


<tt>ActionObjectProtocol.h</tt>
{{out}}
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h>
<pre>Permanently below 0.16 at n = 47332
// our protocol allows "sending" "strings", but we can implement
Execution time: (seconds: 190, nanosecond: 215845101)</pre>
// everything we could for a "local" object
@protocol ActionObjectProtocol
- (NSString *)sendMessage: (NSString *)msg;
@end</syntaxhighlight>


<tt>ActionObject.h</tt>
=={{header|Pascal}}==
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h>
Doing the calculation in Base 1,000,000,000 like in [[Primorial_numbers#alternative]].<BR>
#import "ActionObjectProtocol.h"
The most time consuming is converting to string and search for zeros.<BR>
Therefor I do not convert to string.I divide the base in sections of 3 digits with counting zeros in a lookup table.
<lang pascal>program Factorial;
{$IFDEF FPC} {$MODE DELPHI} {$Optimization ON,ALL} {$ENDIF}
uses
sysutils;
type
tMul = array of LongWord;
tpMul = pLongWord;
const
LongWordDec = 1000*1000*1000;
LIMIT = 50000;
var
CountOfZero : array[0..999] of byte;
SumOfRatio :array[0..LIMIT] of extended;


@interface ActionObject : NSObject <ActionObjectProtocol>
// we do not have much for this example!
@end</syntaxhighlight>


<tt>ActionObject.m</tt>
procedure OutMul(pMul:tpMul;Lmt :NativeInt);
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h>
// for testing
#import "ActionObject.h"
Begin
write(pMul[lmt]);
For lmt := lmt-1 downto 0 do
write(Format('%.9d',[pMul[lmt]]));
writeln;
end;


@implementation ActionObject
procedure InitCoZ;
-(NSString *)sendMessage: (NSString *)msg
//Init Lookup table for 3 digits
{
var
NSLog(@"client sending message %@", msg);
x,y : integer;
return @"server answers ...";
begin
}
fillchar(CountOfZero,SizeOf(CountOfZero),#0);
@end</syntaxhighlight>
CountOfZero[0] := 3; //000
For x := 1 to 9 do
Begin
CountOfZero[x] := 2; //00x
CountOfZero[10*x] := 2; //0x0
CountOfZero[100*x] := 2; //x00
y := 10;
repeat
CountOfZero[y+x] := 1; //0yx
CountOfZero[10*y+x] := 1; //y0x
CountOfZero[10*(y+x)] := 1; //yx0
inc(y,10)
until y > 100;
end;
end;


<tt>server.m</tt>
function getFactorialDecDigits(n:NativeInt):NativeInt;
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h>
var
#import "ActionObject.h"
res: extended;
Begin
result := -1;
IF (n > 0) AND (n <= 1000*1000) then
Begin
res := 0;
repeat res := res+ln(n); dec(n); until n < 2;
result := trunc(res/ln(10))+1;
end;
end;


int main (void)
function CntZero(pMul:tpMul;Lmt :NativeInt):NativeUint;
{
//count zeros in Base 1,000,000,000 number
@autoreleasepool {
var
q,r : LongWord;
ActionObject *action = [[ActionObject alloc] init];
i : NativeInt;
begin
result := 0;
For i := Lmt-1 downto 0 do
Begin
q := pMul[i];
r := q DIV 1000;
result +=CountOfZero[q-1000*r];//q-1000*r == q mod 1000
q := r;
r := q DIV 1000;
result +=CountOfZero[q-1000*r];
q := r;
r := q DIV 1000;
result +=CountOfZero[q-1000*r];
end;
//special case first digits no leading '0'
q := pMul[lmt];
while q >= 1000 do
begin
r := q DIV 1000;
result +=CountOfZero[q-1000*r];
q := r;
end;
while q > 0 do
begin
r := q DIV 10;
result += Ord( q-10*r= 0);
q := r;
end;
end;


NSSocketPort *port = (NSSocketPort *)[NSSocketPort port];
function GetCoD(pMul:tpMul;Lmt :NativeInt):NativeUint;
// initWithTCPPort: 1234 and other methods are not supported yet
//count of decimal digits
// by GNUstep
var
NSConnection *connect = [NSConnection
i : longWord;
connectionWithReceivePort: port
begin
sendPort: port]; // or sendPort: nil
result := 9*Lmt;
i := pMul[Lmt];
while i > 1000 do
begin
i := i DIV 1000;
inc(result,3);
end;
while i > 0 do
begin
i := i DIV 10;
inc(result);
end;
end;


[connect setRootObject: action];
procedure DoChecks(pMul:tpMul;Lmt,i :NativeInt);
//(extended(1.0)* makes TIO.RUN faster // only using FPU?
Begin
SumOfRatio[i] := SumOfRatio[i-1] + (extended(1.0)*CntZero(pMul,Lmt))/GetCoD(pMul,Lmt);
end;


/* "vend" the object ActionObject as DistributedAction; on GNUstep
function MulByI(pMul:tpMul;UL,i :NativeInt):NativeInt;
the Name Server that allows the resolution of the registered name
var
is bound to port 538 */
prod : Uint64;
if (![connect registerName:@"DistributedAction"
j : nativeInt;
withNameServer: [NSSocketPortNameServer sharedInstance] ])
carry : LongWord;
{
begin
NSLog(@"can't register the server DistributedAction");
result := UL;
exit(EXIT_FAILURE);
carry := 0;
}
For j := 0 to result do
Begin
NSLog(@"waiting for messages...");
prod := i*pMul[0]+Carry;
Carry := prod Div LongWordDec;
pMul[0] := Prod - LongWordDec*Carry;
inc(pMul);
end;


[[NSRunLoop currentRunLoop] run];
IF Carry <> 0 then
Begin
inc(result);
pMul[0]:= Carry;
End;
end;


}
procedure getFactorialExact(n:NativeInt);
return 0;
var
}</syntaxhighlight>
MulArr : tMul;
pMul : tpMul;
i,ul : NativeInt;
begin
i := getFactorialDecDigits(n) DIV 9 +10;
Setlength(MulArr,i);
pMul := @MulArr[0];
Ul := 0;
pMul[Ul]:= 1;
i := 1;
repeat
UL := MulByI(pMul,UL,i);
//Now do what you like to do with i!
DoChecks(pMul,UL,i);
inc(i);
until i> n;
end;


===Client===
procedure Out_(i: integer);
<tt>client.m</tt>
begin
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h>
if i > LIMIT then
#import "ActionObjectProtocol.h"
EXIT;
writeln(i:8,SumOfRatio[i]/i:18:15);
end;


int main(void)
var
{
i : integer;
@autoreleasepool {
Begin

InitCoZ;
id <ActionObjectProtocol> action = (id <ActionObjectProtocol>)
SumOfRatio[0]:= 0;
[NSConnection
getFactorialExact(LIMIT);
rootProxyForConnectionWithRegisteredName: @"DistributedAction"
Out_(100);
host: @"localhost"
Out_(1000);
usingNameServer: [NSSocketPortNameServer sharedInstance] ];
Out_(10000);

Out_(50000);
if (action == nil)
i := limit;
while i >0 do
{
NSLog(@"can't connect to the server");
Begin
exit(EXIT_FAILURE);
if SumOfRatio[i]/i >0.16 then
break;
}
dec(i);
NSArray *args = [[NSProcessInfo processInfo] arguments];
end;

inc(i);
if ([args count] == 1)
writeln('First ratio < 0.16 ', i:8,SumOfRatio[i]/i:20:17);
{
end.</lang>
NSLog(@"specify a message");
{{out}}
exit(EXIT_FAILURE);
<pre> 100 0.246753186167432
}
1000 0.203544551103165
10000 0.173003848241866
NSString *msg = args[1];
50000 0.159620054602269

First ratio < 0.16 47332 0.15999999579985665
// "send" (call the selector "sendMessage:" of the (remote) object
Real time: 4.898 s CPU share: 99.55 % // 2.67s on 2200G freepascal 3.2.2</pre>
// action) the first argument's text as msg, store the message "sent
// back" and then show it in the log
NSString *backmsg = [action sendMessage: msg];
NSLog("%@", backmsg);

}
return 0;
}</syntaxhighlight>

=={{header|OCaml}}==
{{works with|JoCaml}}

Minimalistic distributed logger with synchronous channels using the join calculus on top of OCaml.

=== Server ===
<syntaxhighlight lang="ocaml">open Printf
let create_logger () =
def log(text) & logs(l) =
printf "Logged: %s\n%!" text;
logs((text, Unix.gettimeofday ())::l) & reply to log

or search(text) & logs(l) =
logs(l) & reply List.filter (fun (line, _) -> line = text) l to search
in
spawn logs([]);
(log, search)

def wait() & finished() = reply to wait

let register name service = Join.Ns.register Join.Ns.here name service
let () =
let log, search = create_logger () in
register "log" log;
register "search" search;
Join.Site.listen (Unix.ADDR_INET (Join.Site.get_local_addr(), 12345));
wait ()</syntaxhighlight>

=== Client ===

<syntaxhighlight lang="ocaml">open Printf
let ns_there = Join.Ns.there (Unix.ADDR_INET (Join.Site.get_local_addr(), 12345))
let lookup name = Join.Ns.lookup ns_there name

let log : string -> unit = lookup "log"
let search : string -> (string * float) list = lookup "search"
let find txt =
printf "Looking for %s...\n" txt;
List.iter (fun (line, time) ->
printf "Found: '%s' at t = %f\n%!" (String.escaped line) time)
(search txt)
let () =
log "bar";
find "foo";
log "foo";
log "shoe";
find "foo"</syntaxhighlight>

=={{header|Oz}}==
We show a program that starts a server on a remote machine, exchanges two messages with that server and finally shuts it down.

<syntaxhighlight lang="oz">declare
functor ServerCode
export
port:Prt
define
Stream
Prt = {NewPort ?Stream}
thread
for Request#Reply in Stream do
case Request
of echo(Data) then Reply = Data
[] compute(Function) then Reply = {Function}
end
end
end
end

%% create the server on some machine
%% (just change "localhost" to some machine
%% that you can use with a passwordless rsh login
%% and that has the same Mozart version installed)
RM = {New Remote.manager init(host:localhost)}

%% execute the code encapsulated in the ServerCode functor
Server = {RM apply(ServerCode $)}

%% Shortcut: send a message to Server and receive a reply
fun {Send X}
{Port.sendRecv Server.port X}
end
in
%% echo
{System.showInfo "Echo reply: "#{Send echo(hello)}}

%% compute
{System.showInfo "Result of computation: "#
{Send compute(fun {$} 8 div 4 end)}}

%% shut down server
{RM close}</syntaxhighlight>


=={{header|Perl}}==
=={{header|Perl}}==
Using Data::Dumper and Safe to transmit arbitrary data structures as serialized text between hosts. Same code works as both sender and receiver.
{{libheader|ntheory}}
<lang perl>use strict;
<syntaxhighlight lang="perl">use Data::Dumper;
use warnings;
use IO::Socket::INET;
use Safe;
use ntheory qw/factorial/;


sub get_data {
for my $n (100, 1000, 10000) {
my $sock = new IO::Socket::INET
my($sum,$f) = 0;
LocalHost => "localhost",
$f = factorial $_ and $sum += ($f =~ tr/0//) / length $f for 1..$n;
LocalPort => "10000",
printf "%5d: %.5f\n", $n, $sum/$n;
Proto => "tcp",
}</lang>
Listen => 1,
{{out}}
Reuse => 1;
<pre> 100: 0.24675
unless ($sock) { die "Socket creation failure" }
1000: 0.20354
my $cli = $sock->accept();
10000: 0.17300</pre>

# of course someone may be tempted to send you 'system("rm -rf /")',
# to be safe(r), use Safe::
my $safe = new Safe;
my $x = $safe->reval(join("", <$cli>));
close $cli;
close $sock;
return $x;
}

sub send_data {
my $host = shift;
my $data = shift;
my $sock = new IO::Socket::INET
PeerAddr => "$host:10000",
Proto => "tcp",
Reuse => 1;

unless ($sock) { die "Socket creation failure" }

print $sock Data::Dumper->Dump([$data]);
close $sock;
}

if (@ARGV) {
my $x = get_data();
print "Got data\n", Data::Dumper->Dump([$x]);
} else {
send_data('some_host', { a=>100, b=>[1 .. 10] });
}</syntaxhighlight>


=={{header|Phix}}==
=={{header|Phix}}==
From/using [http://phix.x10.mx/pmwiki/pmwiki.php?n=Main.Libzmq the ZeroMQ wrapper from PCAN], a suitable simple publish/subscriber pair.
Using "string math" to create reversed factorials, for slightly easier skipping of "trailing" zeroes,
There is also a server/client/broker example.
but converted to base 1000 and with the zero counting idea from Pascal, which sped it up threefold.
Obviously you can trivially serialize() and deserialize() any Phix data to and from a string.
<!--<lang Phix>(phixonline)-->
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">rfs</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- reverse factorial(1) in base 1000</span>
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (zmq dll/so)</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"durapub:\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">init_zc</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">zmq</span><span style="color: #0000FF;">/</span><span style="color: #000000;">zmq</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">zc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">999</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- 00x</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">10</span><span style="color: #0000FF;">*</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- 0x0</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">100</span><span style="color: #0000FF;">*</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- x00</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">10</span> <span style="color: #008080;">to</span> <span style="color: #000000;">90</span> <span style="color: #008080;">by</span> <span style="color: #000000;">10</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- 0yx</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">10</span><span style="color: #0000FF;">*</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- y0x</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">10</span><span style="color: #0000FF;">*(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">)]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- yx0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">zc</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">zc</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">init_zc</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">(),</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">context</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">zmq_init</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">total</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">zmq_assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">context</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"zmq_init"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">trail</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">JS</span><span style="color: #0000FF;">?</span><span style="color: #000000;">10000</span><span style="color: #0000FF;">:</span><span style="color: #000000;">50000</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d999</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">trail</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">j</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">trail</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rfs</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">j</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">l</span> <span style="color: #008080;">or</span> <span style="color: #000000;">carry</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">j</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">l</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">rfs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">])*</span><span style="color: #000000;">f</span><span style="color: #0000FF;">+</span><span style="color: #000000;">carry</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">d999</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">j</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">l</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">rfs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">d999</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">rfs</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">d999</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">+=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d999</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #000000;">3</span><span style="color: #0000FF;">:</span><span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">d999</span><span style="color: #0000FF;">])</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">/</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">j</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">rfs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">trail</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">0</span> <span style="color: #008080;">do</span> <span style="color: #000000;">trail</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000080;font-style:italic;">-- d999 := quick correction for length and zeroes:</span>
<span style="color: #000000;">d999</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rfs</span><span style="color: #0000FF;">[$]</span>
<span style="color: #000000;">d999</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d999</span><span style="color: #0000FF;"><</span><span style="color: #000000;">100</span><span style="color: #0000FF;">?</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d999</span><span style="color: #0000FF;"><</span><span style="color: #000000;">10</span><span style="color: #0000FF;">?</span><span style="color: #000000;">2</span><span style="color: #0000FF;">:</span><span style="color: #000000;">1</span><span style="color: #0000FF;">):</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">d999</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">digits</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rfs</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">3</span><span style="color: #0000FF;">-</span><span style="color: #000000;">d999</span>
<span style="color: #000000;">total</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">zeroes</span><span style="color: #0000FF;">/</span><span style="color: #000000;">digits</span>
<span style="color: #000080;font-style:italic;">--// subscriber tells us when it's ready here</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">ratio</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">total</span><span style="color: #0000FF;">/</span><span style="color: #000000;">f</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">sync</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">zmq_socket</span><span style="color: #0000FF;">(</span><span style="color: #000000;">context</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ZMQ_PULL</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ratio</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">0.16</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">zmq_bind</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sync</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"tcp://*:5564"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">first</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">--// send update via this socket</span>
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">f</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">publisher</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">zmq_socket</span><span style="color: #0000FF;">(</span><span style="color: #000000;">context</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ZMQ_PUB</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">zmq_bind</span><span style="color: #0000FF;">(</span><span style="color: #000000;">publisher</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"tcp://*:5565"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">100</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10000</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">--// broadcast 10 updates, with pause</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Mean proportion of zero digits in factorials to %d is %.10f (%s)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ratio</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">update_nbr</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">10</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Update %d"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span> <span style="color: #000000;">update_nbr</span> <span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">zmq_s_send</span><span style="color: #0000FF;">(</span><span style="color: #000000;">publisher</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">sleep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"The mean proportion dips permanently below 0.16 at %d. (%s)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">first</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<!--</lang>-->
{{out}}
<pre>
Mean proportion of zero digits in factorials to 100 is 0.2467531862 (0s)
Mean proportion of zero digits in factorials to 1000 is 0.2035445511 (0.2s)
Mean proportion of zero digits in factorials to 10000 is 0.1730038482 (2.3s)
The mean proportion dips permanently below 0.16 at 47332. (1 minute and 2s)
</pre>
<small>(stretch goal removed under pwa/p2js since otherwise you'd get a blank screen for 2 or 3 minutes)</small>
=== trailing zeroes only ===
Should you only be interested in the ratio of trailing zeroes, you can do that much faster:
<!--<lang Phix>(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">(),</span>
<span style="color: #000000;">f10</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">log10</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">total</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">50000</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">f10</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">log10</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">digits</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">ceil</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f10</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">5</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">v</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">f</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">/</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">v</span> <span style="color: #0000FF;">*=</span> <span style="color: #000000;">5</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000000;">total</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">zeroes</span><span style="color: #0000FF;">/</span><span style="color: #000000;">digits</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">ratio</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">total</span><span style="color: #0000FF;">/</span><span style="color: #000000;">f</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ratio</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">0.07</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">first</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">f</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">100</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10000</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Mean proportion of trailing zeroes in factorials to %d is %f\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ratio</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"The mean proportion dips permanently below 0.07 at %d. (%s)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">first</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">zmq_s_send</span><span style="color: #0000FF;">(</span><span style="color: #000000;">publisher</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"END"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">sleep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<!--</lang>-->
{{out}}
<span style="color: #000000;">zmq_close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sync</span><span style="color: #0000FF;">)</span>
<pre>
<span style="color: #000000;">zmq_close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">publisher</span><span style="color: #0000FF;">)</span>
Mean proportion of trailing zeroes in factorials to 100 is 0.170338
<span style="color: #000000;">zmq_term</span><span style="color: #0000FF;">(</span><span style="color: #000000;">context</span><span style="color: #0000FF;">)</span>
Mean proportion of trailing zeroes in factorials to 1000 is 0.116334
<!--</syntaxhighlight>-->
Mean proportion of trailing zeroes in factorials to 10000 is 0.081267

The mean proportion dips permanently below 0.07 at 31549. (0.1s)
<!--<syntaxhighlight lang="phix">(notonline)-->
</pre>
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (zmq dll/so)</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"durasub:\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">zmq</span><span style="color: #0000FF;">/</span><span style="color: #000000;">zmq</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">context</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">zmq_init</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">zmq_assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">context</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"zmq_init"</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--// connect our subscriber socket</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">subscriber</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">zmq_socket</span><span style="color: #0000FF;">(</span><span style="color: #000000;">context</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ZMQ_SUB</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">id</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">allocate_string</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Hello"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">zmq_setsockopt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">subscriber</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ZMQ_IDENTITY</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">id</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">zmq_setsockopt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">subscriber</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ZMQ_SUBSCRIBE</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">zmq_connect</span><span style="color: #0000FF;">(</span><span style="color: #000000;">subscriber</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"tcp://localhost:5565"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">free</span><span style="color: #0000FF;">(</span><span style="color: #000000;">id</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--// synchronise with publisher</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">sync</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">zmq_socket</span><span style="color: #0000FF;">(</span><span style="color: #000000;">context</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ZMQ_PUSH</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">zmq_connect</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sync</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"tcp://localhost:5564"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">zmq_s_send</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sync</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">""</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--// get updates, Ctrl-C break</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">zmq_s_recv</span><span style="color: #0000FF;">(</span><span style="color: #000000;">subscriber</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"%s\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">==</span><span style="color: #008000;">"END"</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000000;">zmq_close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sync</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">zmq_close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">subscriber</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">zmq_term</span><span style="color: #0000FF;">(</span><span style="color: #000000;">context</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->

=={{header|PicoLisp}}==
===Server===
<syntaxhighlight lang="picolisp">(task (port 12321) # Background server task
(let? Sock (accept @)
(unless (fork) # Handle request in child process
(in Sock
(while (rd) # Handle requests
(out Sock
(pr (eval @)) ) ) ) # Evaluate and send reply
(bye) ) # Exit child process
(close Sock) ) ) # Close socket in parent process</syntaxhighlight>
===Client===
<syntaxhighlight lang="picolisp">(let? Sock (connect "localhost" 12321)
(out Sock (pr '*Pid)) # Query PID from server
(println 'PID (in Sock (rd))) # Receive and print reply
(out Sock (pr '(* 3 4))) # Request some calculation
(println 'Result (in Sock (rd))) # Print result
(close Sock) ) # Close connection to server</syntaxhighlight>
Output:
<pre>PID 18372
Result 12</pre>


=={{header|Python}}==
=={{header|Python}}==
{{works with|Python|2.4 and 2.6}}
<lang python>def facpropzeros(N, verbose = True):
proportions = [0.0] * N
fac, psum = 1, 0.0
for i in range(N):
fac *= i + 1
d = list(str(fac))
psum += sum(map(lambda x: x == '0', d)) / len(d)
proportions[i] = psum / (i + 1)


=== XML-RPC ===
if verbose:
'''Protocol:''' XML-RPC
print("The mean proportion of 0 in factorials from 1 to {} is {}.".format(N, psum / N))


==== Server ====
return proportions
<syntaxhighlight lang="python">#!/usr/bin/env python
# -*- coding: utf-8 -*-


import SimpleXMLRPCServer


class MyHandlerInstance:
for n in [100, 1000, 10000]:
facpropzeros(n)
def echo(self, data):
'''Method for returning data got from client'''
return 'Server responded: %s' % data


def div(self, num1, num2):
props = facpropzeros(47500, False)
'''Method for divide 2 numbers'''
n = (next(i for i in reversed(range(len(props))) if props[i] > 0.16))
return num1/num2


def foo_function():
print("The mean proportion dips permanently below 0.16 at {}.".format(n + 2))
'''A function (not an instance method)'''
</lang>{{out}}
return True
<pre>
The mean proportion of 0 in factorials from 1 to 100 is 0.24675318616743216.
The mean proportion of 0 in factorials from 1 to 1000 is 0.20354455110316458.
The mean proportion of 0 in factorials from 1 to 10000 is 0.17300384824186707.
The mean proportion dips permanently below 0.16 at 47332.
</pre>
The means can be plotted, showing a jump from 0 to over 0.25, followed by a slowly dropping curve:
<lang python>import matplotlib.pyplot as plt
plt.plot([i+1 for i in range(len(props))], props)
</lang>
=== Base 1000 version ===
{{trans|Go via Phix via Pascal}}
<lang python>def zinit():
zc = [0] * 999
for x in range(1, 10):
zc[x - 1] = 2 # 00x
zc[10 * x - 1] = 2 # 0x0
zc[100 * x - 1] = 2 # x00
for y in range(10, 100, 10):
zc[y + x - 1] = 1 # 0yx
zc[10 * y + x - 1] = 1 # y0x
zc[10 * (y + x) - 1] = 1 # yx0


HOST = "localhost"
return zc
PORT = 8000


server = SimpleXMLRPCServer.SimpleXMLRPCServer((HOST, PORT))
def meanfactorialdigits():
zc = zinit()
rfs = [1]
total, trail, first = 0.0, 1, 0
for f in range(2, 50000):
carry, d999, zeroes = 0, 0, (trail - 1) * 3
j, l = trail, len(rfs)
while j <= l or carry != 0:
if j <= l:
carry = rfs[j-1] * f + carry


# register built-in system.* functions.
d999 = carry % 1000
server.register_introspection_functions()
if j <= l:

rfs[j-1] = d999
# register our instance
server.register_instance(MyHandlerInstance())

# register our function as well
server.register_function(foo_function)

try:
# serve forever
server.serve_forever()
except KeyboardInterrupt:
print 'Exiting...'
server.server_close()</syntaxhighlight>

==== Client ====
<syntaxhighlight lang="python">#!/usr/bin/env python
# -*- coding: utf-8 -*-

import xmlrpclib

HOST = "localhost"
PORT = 8000

rpc = xmlrpclib.ServerProxy("http://%s:%d" % (HOST, PORT))

# print what functions does server support
print 'Server supports these functions:',
print ' '.join(rpc.system.listMethods())

# echo something
rpc.echo("We sent this data to server")

# div numbers
print 'Server says: 8 / 4 is: %d' % rpc.div(8, 4)

# control if foo_function returns True
if rpc.foo_function():
print 'Server says: foo_function returned True'</syntaxhighlight>

===HTTP===
'''Protocol:''' HTTP

==== Server ====
<syntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-

import BaseHTTPServer

HOST = "localhost"
PORT = 8000

# we just want to write own class, we replace do_GET method. This could be extended, I just added basics
# see; http://docs.python.org/lib/module-BaseHTTPServer.html
class MyHTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
# send 200 (OK) message
self.send_response(200)
# send header
self.send_header("Content-type", "text/html")
self.end_headers()

# send context
self.wfile.write("<html><head><title>Our Web Title</title></head>")
self.wfile.write("<body><p>This is our body. You wanted to visit <b>%s</b> page</p></body>" % self.path)
self.wfile.write("</html>")

if __name__ == '__main__':
server = BaseHTTPServer.HTTPServer((HOST, PORT), MyHTTPHandler)
try:
server.serve_forever()
except KeyboardInterrupt:
print 'Exiting...'
server.server_close()</syntaxhighlight>

==== Client ====
<syntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-

import httplib

HOST = "localhost"
PORT = 8000

conn = httplib.HTTPConnection(HOST, PORT)
conn.request("GET", "/somefile")

response = conn.getresponse()
print 'Server Status: %d' % response.status

print 'Server Message: %s' % response.read()</syntaxhighlight>

===Socket, Pickle format===

'''Protocol:''' raw socket / pickle format

This example builds a very basic RPC mechanism on top of sockets and the [http://docs.python.org/library/pickle.html#module-pickle pickle module]. Please note that the pickle module is not secure - a malicious client can build malformed data to execute arbitrary code on the server. If untrusted clients can access the server, the [http://docs.python.org/library/json.html json module] could be used as a substitute, but we lose the ability to transfer arbitrary Python objects that way.

==== Server ====
<syntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-
import SocketServer
import pickle
HOST = "localhost"
PORT = 8000

class RPCServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
# The object_to_proxy member should be set to the object we want
# methods called on. Unfortunately, we can't do this in the constructor
# because the constructor should not be overridden in TCPServer...

daemon_threads = True

class RPCHandler(SocketServer.StreamRequestHandler):
def handle(self):
in_channel = pickle.Unpickler(self.rfile)
out_channel = pickle.Pickler(self.wfile, protocol=2)
while True:
try:
name, args, kwargs = in_channel.load()
print 'got %s %s %s' % (name, args, kwargs)
except EOFError:
# EOF means we're done with this request.
# Catching this exception to detect EOF is a bit hackish,
# but will work for a quick demo like this
break
try:
method = getattr(self.server.object_to_proxy, name)
result = method(*args, **kwargs)
except Exception, e:
out_channel.dump(('Error',e))
else:
else:
rfs.append(d999)
out_channel.dump(('OK',result))


class MyHandlerInstance(object):
zeroes += 3 if d999 == 0 else zc[d999-1]
def echo(self, data):
carry //= 1000
j += 1
'''Method for returning data got from client'''
return 'Server responded: %s' % data
def div(self, dividend, divisor):
'''Method to divide 2 numbers'''
return dividend/divisor
def is_computer_on(self):
return True
if __name__ == '__main__':
rpcserver = RPCServer((HOST, PORT), RPCHandler)
rpcserver.object_to_proxy = MyHandlerInstance()
try:
rpcserver.serve_forever()
except KeyboardInterrupt:
print 'Exiting...'
rpcserver.server_close()
</syntaxhighlight>


==== Client ====
while rfs[trail-1] == 0:
<syntaxhighlight lang="python">#!/usr/bin/python
trail += 1
# -*- coding: utf-8 -*-
import socket
import pickle
HOST = "localhost"
PORT = 8000


class RPCClient(object):
# d999 is a quick correction for length and zeros
def __init__(self, host, port):
d999 = rfs[-1]
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
d999 = 0 if d999 >= 100 else 2 if d999 < 10 else 1
self.socket.connect((host, port))
self.rfile = self.socket.makefile('rb')
self.wfile = self.socket.makefile('wb')
self.in_channel = pickle.Unpickler(self.rfile)
self.out_channel = pickle.Pickler(self.wfile, protocol=2)


def _close(self):
zeroes -= d999
digits = len(rfs) * 3 - d999
self.socket.close()
total += zeroes / digits
self.rfile.close()
ratio = total / f
self.wfile.close()
if f in [100, 1000, 10000]:
print("The mean proportion of zero digits in factorials to {} is {}".format(f, ratio))
if ratio >= 0.16:
first = 0
elif first == 0:
first = f


# Make calling remote methods easy by overriding attribute access.
print("The mean proportion dips permanently below 0.16 at {}.".format(first))
# Accessing any attribute on our instances will give a proxy method that
# calls the method with the same name on the remote machine.
def __getattr__(self, name):
def proxy(*args, **kwargs):
self.out_channel.dump((name, args, kwargs))
self.wfile.flush() # to make sure the server won't wait forever
status, result = self.in_channel.load()
if status == 'OK':
return result
else:
raise result


return proxy
if __name__ == '__main__':
# connect to server and send data
rpcclient = RPCClient(HOST, PORT)


print 'Testing the echo() method:'
print rpcclient.echo('Hello world!')
print
print 'Calculating 42/2 on the remote machine:'
print rpcclient.div(42, 2)
print
print 'is_computer_on on the remote machine returns:'
print rpcclient.is_computer_on()
print
print 'Testing keyword args:'
print '42/2 is:', rpcclient.div(divisor=2, dividend=42)
rpcclient._close()
del rpcclient</syntaxhighlight>


===Pyro===
import time
'''Note:''' You should install Pyro (http://pyro.sourceforge.net) first and run '''pyro-ns''' binary to run code below.
TIME0 = time.perf_counter()
meanfactorialdigits()
print("\nTotal time:", time.perf_counter() - TIME0, "seconds.")
</lang>{{out}}
<pre>
The mean proportion of zero digits in factorials to 100 is 0.24675318616743216
The mean proportion of zero digits in factorials to 1000 is 0.20354455110316458
The mean proportion of zero digits in factorials to 10000 is 0.17300384824186707
The mean proportion dips permanently below 0.16 at 47332.


==== Server ====
Total time: 648.3583232999999 seconds.
<syntaxhighlight lang="python">#!/usr/bin/python
</pre>
# -*- coding: utf-8 -*-

import Pyro.core
import Pyro.naming

# create instance that will return upper case
class StringInstance(Pyro.core.ObjBase):
def makeUpper(self, data):
return data.upper()

class MathInstance(Pyro.core.ObjBase):
def div(self, num1, num2):
return num1/num2

if __name__ == '__main__':
server = Pyro.core.Daemon()
name_server = Pyro.naming.NameServerLocator().getNS()
server.useNameServer(name_server)
server.connect(StringInstance(), 'string')
server.connect(MathInstance(), 'math')
try:
server.requestLoop()
except KeyboardInterrupt:
print 'Exiting...'
server.shutdown()</syntaxhighlight>

==== Client ====
<syntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-

import Pyro.core

DATA = "my name is eren"
NUM1 = 10
NUM2 = 5

string = Pyro.core.getProxyForURI("PYRONAME://string")
math = Pyro.core.getProxyForURI("PYRONAME://math")

print 'We sent: %s' % DATA
print 'Server responded: %s\n' % string.makeUpper(DATA)

print 'We sent two numbers to divide: %d and %d' % (NUM1, NUM2)
print 'Server responded the result: %s' % math.div(NUM1, NUM2)</syntaxhighlight>

=== Spread ===
'''Note:''' You should install Spread (http://www.spread.org) and its python bindings (http://www.python.org/other/spread/)

==== Server ====
You don't need any code for server. You should start "spread" daemon by typing "spread -c /etc/spread.conf -n localhost". If you want more configuration, look at /etc/spread.conf.

After starting daemon, if you want to make sure that it is running, enter '''spuser -s 4803''' command where 4803 is your port set in spread.conf, you will see prompt, type '''j user''', you should see something like this message: ''Received REGULAR membership for group test with 3 members, where I am member 2''

==== Client (Listener) ====
<syntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-

import spread

PORT = '4803'

# connect spread daemon
conn = spread.connect(PORT)
# join the room
conn.join('test')

print 'Waiting for messages... If you want to stop this script, please stop spread daemon'
while True:
recv = conn.receive()
if hasattr(recv, 'sender') and hasattr(recv, 'message'):
print 'Sender: %s' % recv.sender
print 'Message: %s' % recv.message</syntaxhighlight>

==== Client (Sender) ====
<syntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-

import spread

PORT = '4803'

conn = spread.connect(PORT)
conn.join('test')

conn.multicast(spread.RELIABLE_MESS, 'test', 'hello, this is message sent from python')
conn.disconnect()</syntaxhighlight>

=={{header|Racket}}==
Server and client in the same piece of code, running a useless (fib 42) computation, four times, on four hosts (which all happen to be "localhost", but that can change, of course).

<syntaxhighlight lang="racket">
#lang racket/base
(require racket/place/distributed racket/place)

(define (fib n)
(if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2)))))

(provide work)
(define (work)
(place ch
(place-channel-put ch (fib (place-channel-get ch)))))

(module+ main
(define places
(for/list ([host '("localhost" "localhost" "localhost" "localhost")]
[port (in-naturals 12345)])
(define-values [node place]
(spawn-node-supervise-place-at host #:listen-port port #:thunk #t
(quote-module-path "..") 'work))
place))
(message-router
(after-seconds 1
(for ([p places]) (*channel-put p 42))
(printf "Results: ~s\n" (map *channel-get places))
(exit))))
</syntaxhighlight>


=={{header|Raku}}==
=={{header|Raku}}==
(formerly Perl 6)
Works, but depressingly slow for 10000.


Server listens for JSON encoded messages. It processes requests for set|get|dump. 'set' stores a message, 'get' returns message, 'dump' returns all stored messages. Optional parameters for ip address and port.
<lang perl6>sub postfix:<!> (Int $n) { ( constant factorial = 1, 1, |[\*] 2..* )[$n] }
sink 10000!; # prime the iterator to allow multithreading


Server.raku:
sub zs ($n) { ( constant zero-share = (^Inf).race(:32batch).map: { (.!.comb.Bag){'0'} / .!.chars } )[$n+1] }
<pre>./server.raku --usage
Usage:
server.p6 [--server=<Any>] [--port=<Any>]</pre>
<syntaxhighlight lang="raku" line>#!/usr/bin/env raku
use JSON::Fast ;
sub MAIN( :$server='0.0.0.0' , :$port=3333 ) {
my %db ;
react {
whenever IO::Socket::Async.listen( $server , $port ) -> $conn {
whenever $conn.Supply.lines -> $line {
my %response = 'status' => '' ;
my $msg = from-json $line ;
say $msg.raku;
given $msg{"function"} {
when 'set' {
%db{ $msg<topic> } = $msg<message> ;
%response<status> = 'ok' ;
}
when 'get' {
%response<topic> = $msg<topic> ;
%response<message> = %db{ $msg<topic> } ;
%response<status> = 'ok' ;
}
when 'dump' {
%response = %db ;
}
when 'delete' {
%db{ $msg<topic> }:delete;
%response<status> = 'ok' ;
}
}
$conn.print( to-json(%response, :!pretty) ~ "\n" ) ;
LAST { $conn.close ; }
QUIT { default { $conn.close ; say "oh no, $_";}}
CATCH { default { say .^name, ': ', .Str , " handled in $?LINE";}}
}
}
}
}</syntaxhighlight>
client.raku:
<pre>Usage:
client.raku [--server=<Any>] [--port=<Any>] [--json=<Any>] set <topic> [<message>]
client.raku [--server=<Any>] [--port=<Any>] get <topic>
client.raku [--server=<Any>] [--port=<Any>] dump</pre>
<syntaxhighlight lang="raku" line>#!/usr/bin/env raku
use JSON::Fast ;
multi MAIN('set', $topic, $message='', :$server='localhost', :$port='3333', :$json='') {
my %msg = function => 'set' , topic=> $topic , message=> $message ;
%msg{"message"} = from-json( $json ) if $json ;
sendmsg( %msg , $server, $port) ;
}
multi MAIN('get', $topic, :$server='localhost', :$port='3333') {
my %msg = function => 'get' , topic=> $topic ;
sendmsg( %msg , $server, $port) ;
}
multi MAIN('delete', $topic, :$server='localhost', :$port='3333') {
my %msg = function => 'delete' , topic=> $topic ;
sendmsg( %msg , $server, $port) ;
}
multi MAIN('dump', :$server='localhost', :$port='3333') {
my %msg = function => 'dump' ;
sendmsg( %msg , $server, $port) ;
}
sub sendmsg( %msg , $server, $port){
my $conn = await IO::Socket::Async.connect( $server , $port );
$conn.print: to-json( %msg,:!pretty)~"\n";
react {
whenever $conn.Supply -> $data {
print $data;
$conn.close;
}
}
}</syntaxhighlight>
examples:
<pre>echo '{"function":"set","topic":"push","message":["perl5","raku","rakudo"]}' | nc localhost 3333


./client.raku set version raku
.say for (
{"status": "ok"}
100
./client.raku get version
,1000
{"status": "ok","topic": "version","message": "raku"}
,10000
./client.raku --json='["one","two","three"]' set mylist
).map: -> \n { "{n}: {([+] (^n).map: *.&zs) / n}" }</lang>
{"status": "ok"}
{{out}}
./client.raku dump
<pre>100: 0.24675318616743216
{"push": ["perl5","raku","rakudo"],"version": "raku","mylist": ["one","two","three"]}
1000: 0.20354455110316458
./client.raku delete version
10000: 0.17300384824186605
{"status": "ok"}
</pre>


server output:
=={{header|REXX}}==
${:function("set"), :message($["perl5", "raku", "rakudo"]), :topic("push")}
<lang rexx>/*REXX program computes the mean of the proportion of "0" digits a series of factorials.*/
${:function("set"), :message("raku"), :topic("version")}
parse arg $ /*obtain optional arguments from the CL*/
${:function("get"), :topic("version")}
if $='' | $="," then $= 100 1000 10000 /*not specified? Then use the default.*/
${:function("set"), :message($["one", "two", "three"]), :topic("mylist")}
#= words($) /*the number of ranges to be used here.*/
${:function("dump")}
numeric digits 100 /*increase dec. digs, but only to 100. */
${:function("delete"), :topic("version")}</pre>
big= word($, #); != 1 /*obtain the largest number in ranges. */
do i=1 for big /*calculate biggest ! using 100 digs.*/
!= ! * i /*calculate the factorial of BIG. */
end /*i*/
if pos('E', !)>0 then do /*In exponential format? Then get EXP.*/
parse var ! 'E' x /*parse the exponent from the number. */
numeric digits x+1 /*set the decimal digits to X plus 1.*/
end /* [↑] the +1 is for the dec. point.*/


=={{header|Ruby}}==
title= ' mean proportion of zeros in the (decimal) factorial products for N'
Uses the distributed Ruby (dRuby) from the standard library. The "druby:" protocol uses TCP/IP sockets for communication.
say ' N │'center(title, 80) /*display the title for the output. */
say '───────────┼'center("" , 80, '─') /* " a sep " " " */


'''Server'''
do j=1 for #; n= word($, j) /*calculate some factorial ranges. */
<syntaxhighlight lang="ruby">require 'drb/drb'
say center( commas(n), 11)'│' left(0dist(n), 75)... /*show results for above range.*/
end /*j*/


# The URI for the server to connect to
say '───────────┴'center("" , 80, '─') /*display a foot sep for the output. */
URI="druby://localhost:8787"
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
commas: parse arg ?; do jc=length(?)-3 to 1 by -3; ?=insert(',', ?, jc); end; return ?
/*──────────────────────────────────────────────────────────────────────────────────────*/
0dist: procedure; parse arg z; != 1; y= 0
do k=1 for z; != ! * k; y= y + countstr(0, !) / length(!)
end /*k*/
return y/z</lang>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
N │ mean proportion of zeros in the (decimal) factorial products for N
───────────┼────────────────────────────────────────────────────────────────────────────────
100 │ 0.2467531861674322177784158871973526991129407033266153063813195937196095976...
1,000 │ 0.2035445511031646356400438031711455302985741167890402203486699704599684047...
10,000 │ 0.1730038482418660531800366428930706156810278809057883361518852958446868172...
───────────┴────────────────────────────────────────────────────────────────────────────────
</pre>


class TimeServer
=={{header|Rust}}==

{{trans|Phix}}
def get_current_time
<lang rust>fn init_zc() -> Vec<usize> {
return Time.now
let mut zc = vec![0; 1000];
end
zc[0] = 3;

for x in 1..=9 {
end
zc[x] = 2;

zc[10 * x] = 2;
# The object that handles requests on the server
zc[100 * x] = 2;
FRONT_OBJECT = TimeServer.new
let mut y = 10;

while y <= 90 {
$SAFE = 1 # disable eval() and friends
zc[y + x] = 1;

zc[10 * y + x] = 1;
DRb.start_service(URI, FRONT_OBJECT)
zc[10 * (y + x)] = 1;
# Wait for the drb server thread to finish before exiting.
y += 10;
DRb.thread.join</syntaxhighlight>

'''Client'''
<syntaxhighlight lang="ruby">require 'drb/drb'

# The URI to connect to
SERVER_URI = "druby://localhost:8787"

# Start a local DRbServer to handle callbacks.
#
# Not necessary for this small example, but will be required
# as soon as we pass a non-marshallable object as an argument
# to a dRuby call.
DRb.start_service

timeserver = DRbObject.new_with_uri(SERVER_URI)
puts timeserver.get_current_time</syntaxhighlight>

=={{header|Tcl}}==
A rudimentary IRC Server
<syntaxhighlight lang="tcl">proc main {} {
global connections
set connections [dict create]
socket -server handleConnection 12345
vwait dummyVar ;# enter the event loop
}

proc handleConnection {channel clientaddr clientport} {
global connections
dict set connections $channel address "$clientaddr:$clientport"
fconfigure $channel -buffering line
fileevent $channel readable [list handleMessage $channel]
}

proc handleMessage {channel} {
global connections
if {[gets $channel line] == -1} {
disconnect $channel
} else {
if {[string index [string trimleft $line] 0] eq "/"} {
set words [lassign [split [string trim $line]] command]
handleCommand $command $words $channel
} else {
echo $line $channel
}
}
}
}
zc
}
}


proc disconnect {channel} {
fn main() {
global connections
use std::time::Instant;
dict unset connections $channel
let zc = init_zc();
fileevent $channel readable ""
let t0 = Instant::now();
let mut trail = 1;
close $channel
}
let mut first = 0;
let mut total: f64 = 0.0;
let mut rfs = vec![1];


proc handleCommand {command words channel} {
for f in 2..=50000 {
global connections
let mut carry = 0;
switch -exact -- [string tolower $command] {
let mut d999: usize;
let mut zeroes = (trail - 1) * 3;
/nick {
dict set connections $channel nick [lindex $words 0]
let len = rfs.len();
let mut j = trail - 1;
while j < len || carry != 0 {
if j < len {
carry += rfs[j] * f;
}
d999 = carry % 1000;
if j < len {
rfs[j] = d999;
} else {
rfs.push(d999);
}
zeroes += zc[d999];
carry /= 1000;
j += 1;
}
}
while rfs[trail - 1] == 0 {
/quit {
trail += 1;
echo bye $channel
disconnect $channel
}
}
d999 = rfs[rfs.len() - 1];
default {
d999 = if d999 < 100 {
puts $channel "\"$command\" not implemented"
if d999 < 10 {
2
} else {
1
}
} else {
0
};
zeroes -= d999;
let digits = rfs.len() * 3 - d999;
total += (zeroes as f64) / (digits as f64);
let ratio = total / (f as f64);
if ratio >= 0.16 {
first = 0;
} else if first == 0 {
first = f;
}
}
}
if f == 100 || f == 1000 || f == 10000 {
}
let duration = t0.elapsed();

println!(
proc echo {message senderchannel} {
"Mean proportion of zero digits in factorials to {} is {:.10}. ({}ms)",
f,
global connections
foreach channel [dict keys $connections] {
ratio,
if {$channel ne $senderchannel} {
duration.as_millis()
set time [clock format [clock seconds] -format "%T"]
);
set nick [dict get $connections $channel nick]
puts $channel [format "\[%s\] %s: %s" $time $nick $message]
}
}
}
}
}
let duration = t0.elapsed();
println!(
"The mean proportion dips permanently below 0.16 at {}. ({}ms)",
first,
duration.as_millis()
);
}</lang>


main</syntaxhighlight>
{{out}}
Client
<pre>
<syntaxhighlight lang="tcl">proc main {} {
Mean proportion of zero digits in factorials to 100 is 0.2467531862. (0ms)
global argv argc
Mean proportion of zero digits in factorials to 1000 is 0.2035445511. (1ms)
if {$argc != 2} {
Mean proportion of zero digits in factorials to 10000 is 0.1730038482. (149ms)
error "usage: [info script] serveraddress serverport"
The mean proportion dips permanently below 0.16 at 47332. (4485ms)
}
</pre>
connect {*}$argv
vwait dummyVar
}


proc connect {addr port} {
=={{header|Sidef}}==
global sock
<lang ruby>func mean_factorial_digits(n, d = 0) {
set sock [socket $addr $port]

fconfigure $sock -buffering line
var v = 1
fileevent $sock readable getFromServer
var total = 0.float
fileevent stdin readable sendToServer
}


proc getFromServer {} {
for k in (1..n) {
v *= k
global sock
if {[gets $sock line] == -1} {
total += v.digits.count(d)/v.len
puts "disconnected..."
exit
} else {
puts $line
}
}
}


proc sendToServer {} {
total / n
global sock
set msg [string trim [gets stdin]]
if {[string length $msg] > 0} {
puts $sock $msg
}
}
}


main</syntaxhighlight>
say mean_factorial_digits(100)

say mean_factorial_digits(1000)
=={{header|UnixPipes}}==
say mean_factorial_digits(10000)</lang>
{{out}}
{{libheader|nc}}
Uses netcat and a buffer to cycle the server shell's stdout back to netcat's stdin.
<pre>

0.246753186167432217778415887197352699112940703327
===Server===
0.203544551103164635640043803171145530298574116789
{{alertbox|yellow|'''Security risk!''' Anything, able to reach 127.0.0.1 port 1234, can run shell commands as the user who runs the server. This allows other users to gain privileges.}}
0.173003848241866053180036642893070615681027880906

</pre>
<syntaxhighlight lang="bash">: >/tmp/buffer
tail -f /tmp/buffer | nc -l 127.0.0.1 1234 | sh >/tmp/buffer 2>&1</syntaxhighlight>

Limitations:

* The server can accept only one connection (but continues to run, not exit, after this connection dies).
* With some systems, <code>tail -f</code> might be slow to notice changes to /tmp/buffer.

===Client===
<syntaxhighlight lang="bash">nc 127.0.0.1 1234</syntaxhighlight>

Now you can enter commands in the client terminal and get the output back through the same connection.


=={{header|Wren}}==
=={{header|Wren}}==
{{trans|Go}}
===Brute force===
{{libheader|Wren-big}}
{{libheader|WrenGo}}
{{libheader|Wren-fmt}}
{{libheader|Wren-fmt}}
As Wren has no networking support at present, we use embedded programs for both the server and client with a Go host using the net/rpc package in its standard library.
Very slow indeed, 10.75 minutes to reach N = 10,000.
<lang ecmascript>import "/big" for BigInt
import "/fmt" for Fmt


Moreover, as Wren's VM is not re-entrant, we need to run two VMs from the server side, one to call Go from Wren and the other to call Wren from Go.
var fact = BigInt.one
var sum = 0
System.print("The mean proportion of zero digits in factorials up to the following are:")
for (n in 1..10000) {
fact = fact * n
var bytes = fact.toString.bytes
var digits = bytes.count
var zeros = bytes.count { |b| b == 48 }
sum = sum + zeros / digits
if (n == 100 || n == 1000 || n == 10000) {
Fmt.print("$,6d = $12.10f", n, sum / n)
}
}</lang>


'''Server:'''
{{out}}
<pre>
The mean proportion of zero digits in factorials up to the following are:
100 = 0.2467531862
1,000 = 0.2035445511
10,000 = 0.1730038482
</pre>
<br>
<br>
We need two Wren scripts one for each VM:
==='String math' and base 1000===
<syntaxhighlight lang="ecmascript">/* distributed_programming_server.wren */
{{trans|Phix}}
Around 60 times faster than before with 10,000 now being reached in about 10.5 seconds. Even the stretch goal is now viable and comes in at 5 minutes 41 seconds.
<lang ecmascript>import "/fmt" for Fmt


class Rpc {
var rfs = [1] // reverse factorial(1) in base 1000
foreign static register()


foreign static handleHTTP()
var init = Fn.new { |zc|
}
for (x in 1..9) {

zc[x-1] = 2 // 00x
foreign class Listener {
zc[10*x - 1] = 2 // 0x0
construct listen(network, address) {}
zc[100*x - 1] = 2 // x00
}
var y = 10

while (y <= 90) {
class HTTP {
zc[y + x - 1] = 1 // 0yx
foreign static serve(listener)
zc[10*y + x - 1] = 1 // y0x
}
zc[10*(y + x) - 1] = 1 // yx0

y = y + 10
Rpc.register()
}
Rpc.handleHTTP()
var listener = Listener.listen("tcp", ":1234")
HTTP.serve(listener)</syntaxhighlight>
<br>
<syntaxhighlight lang="ecmascript">/* distributed_programming_server2.wren */

class TaxComputer {
static tax(amount, rate) {
if (amount < 0) Fiber.abort("Negative values not allowed.")
return amount * rate
}
}
}</syntaxhighlight>
<br>
We now embed these scripts in the following Go program and run it on one terminal.
<syntaxhighlight lang="go">/* go run distributed_programming_server.go */

package main

import(
wren "github.com/crazyinfin8/WrenGo"
"log"
"net"
"net/http"
"net/rpc"
)

type any = interface{}

type TaxComputer float64

var vm2 *wren.VM

var fileName = "distributed_programming_server.wren"
var fileName2 = "distributed_programming_server2.wren"

func (taxRate TaxComputer) Tax(x float64, r *float64) error {
wrenVar, _ := vm2.GetVariable(fileName2, "TaxComputer")
wrenClass, _ := wrenVar.(*wren.Handle)
defer wrenClass.Free()
wrenMethod, _ := wrenClass.Func("tax(_,_)")
defer wrenMethod.Free()
ret, _ := wrenMethod.Call(x, float64(taxRate))
*r = ret.(float64)
return nil
}
}


func register(vm *wren.VM, parameters []any) (any, error) {
var zc = List.filled(999, 0)
c := TaxComputer(0.05) // 5% tax rate
init.call(zc)
rpc.Register(c)
var total = 0
return nil, nil
var trail = 1
}
var first = 0

var firstRatio = 0
func handleHTTP(vm *wren.VM, parameters []any) (any, error) {
System.print("The mean proportion of zero digits in factorials up to the following are:")
rpc.HandleHTTP()
for (f in 2..50000) {
var carry = 0
return nil, nil
}
var d999 = 0

var zeros = (trail-1) * 3
func serve(vm *wren.VM, parameters []any) (any, error) {
var j = trail
handle := parameters[1].(*wren.ForeignHandle)
var l = rfs.count
while (j <= l || carry != 0) {
ifc, _ := handle.Get()
listener := ifc.(*net.Listener)
if (j <= l) carry = rfs[j-1]*f + carry
http.Serve(*listener, nil)
d999 = carry % 1000
return nil, nil
if (j <= l) {
}
rfs[j-1] = d999

} else {
func listen(vm *wren.VM, parameters []any) (any, error) {
rfs.add(d999)
network := parameters[1].(string)
}
address := parameters[2].(string)
zeros = zeros + ((d999 == 0) ? 3 : zc[d999-1])
listener, err := net.Listen(network, address)
carry = (carry/1000).floor
j = j + 1
if err != nil {
log.Fatal(err)
}
}
return &listener, nil
while (rfs[trail-1] == 0) trail = trail + 1
}
// d999 = quick correction for length and zeros

d999 = rfs[-1]
func main() {
d999 = (d999 < 100) ? ((d999 < 10) ? 2 : 1) : 0
zeros = zeros - d999
vm := wren.NewVM()
var digits = rfs.count * 3 - d999
vm2 = wren.NewVM()
vm2.InterpretFile(fileName2)
total = total + zeros/digits

var ratio = total / f
if (ratio >= 0.16) {
rpcMethodMap := wren.MethodMap {
first = 0
"static register()": register,
firstRatio = 0
"static handleHTTP()": handleHTTP,
} else if (first == 0) {
first = f
firstRatio = ratio
}
}

if (f == 100 || f == 1000 || f == 10000) {
httpMethodMap := wren.MethodMap { "static serve(_)":serve }
Fmt.print("$,6d = $12.10f", f, ratio)

classMap := wren.ClassMap {
"Listener": wren.NewClass(listen, nil, nil),
"Rpc" : wren.NewClass(nil, nil, rpcMethodMap),
"HTTP" : wren.NewClass(nil, nil, httpMethodMap),
}
}

module := wren.NewModule(classMap)
vm.SetModule(fileName, module)
vm.InterpretFile(fileName)
vm.Free()
vm2.Free()
}</syntaxhighlight>
<br>
'''Client:'''
<br>
Just one Wren script needed here:
<syntaxhighlight lang="ecmascript">/* distributed_programming_client.wren */

import "./fmt" for Fmt

foreign class Client {
construct dialHTTP(network, address) {}

foreign call(serviceMethod, arg)
}
}

Fmt.write("$,6d = $12.10f", first, firstRatio)
var client = Client.dialHTTP("tcp", "localhost:1234")
System.print(" (stays below 0.16 after this)")
var amounts = [3, 5.6]
Fmt.print("$,6d = $12.10f", 50000, total/50000)</lang>
for (amount in amounts) {
var tax = client.call("TaxComputer.Tax", amount)
Fmt.print("Tax on $0.2f = $0.2f", amount, tax)
}</syntaxhighlight>
<br>
which we embed in the following Go program and run it on a different terminal.
<syntaxhighlight lang="go">/* go run distributed_programming_client.go */

package main

import(
wren "github.com/crazyinfin8/WrenGo"
"log"
"net/rpc"
"strings"
)

type any = interface{}

func dialHTTP(vm *wren.VM, parameters []any) (any, error) {
network := parameters[1].(string)
address := parameters[2].(string)
client, err := rpc.DialHTTP(network, address)
if err != nil {
log.Fatal(err)
}
return &client, nil
}

func call(vm *wren.VM, parameters []any) (any, error) {
handle := parameters[0].(*wren.ForeignHandle)
ifc, _ := handle.Get()
client := ifc.(**rpc.Client)
serviceMethod := parameters[1].(string)
amount := parameters[2].(float64)
var tax float64
err := (*client).Call(serviceMethod, amount, &tax)
if err != nil {
log.Fatal(err)
}
return tax, nil
}

func moduleFn(vm *wren.VM, name string) (string, bool) {
if name != "meta" && name != "random" && !strings.HasSuffix(name, ".wren") {
name += ".wren"
}
return wren.DefaultModuleLoader(vm, name)
}

func main() {
cfg := wren.NewConfig()
cfg.LoadModuleFn = moduleFn
vm := cfg.NewVM()
fileName := "distributed_programming_client.wren"
clientMethodMap := wren.MethodMap { "call(_,_)": call }
classMap := wren.ClassMap { "Client": wren.NewClass(dialHTTP, nil, clientMethodMap) }
module := wren.NewModule(classMap)
vm.SetModule(fileName, module)
vm.InterpretFile(fileName)
vm.Free()
}</syntaxhighlight>


{{out}}
{{out}}
Output on the client terminal:
<pre>
<pre>
Tax on 3.00 = 0.15
The mean proportion of zero digits in factorials up to the following are:
100 = 0.2467531862
Tax on 5.60 = 0.28
1,000 = 0.2035445511
10,000 = 0.1730038482
47,332 = 0.1599999958 (stays below 0.16 after this)
50,000 = 0.1596200546
</pre>
</pre>

{{omit from|Lotus 123 Macro Scripting}}
{{omit from|Maxima}}
{{omit from|PARI/GP}}
{{omit from|Retro}}

Revision as of 00:04, 27 August 2022

Task
Distribution of 0 digits in factorial series
You are encouraged to solve this task according to the task description, using any language you may know.

Write two programs (or one program with two modes) which run on networked computers, and send some messages between them.

The protocol used may be language-specific or not, and should be suitable for general distributed programming; that is, the protocol should be generic (not designed just for the particular example application), readily capable of handling the independent communications of many different components of a single application, and the transferring of arbitrary data structures natural for the language.

This task is intended to demonstrate high-level communication facilities beyond just creating sockets.

Ada

Works with: GNAT GPL version 2010
Works with: PolyORB

Ada defines facilities for distributed systems in its standard (Annex E, also called DSA).

This example works with PolyORB and the GNAT GPL 2010 compiler from AdaCore.

server.ads:

package Server is
   pragma Remote_Call_Interface;
   procedure Foo;
   function Bar return Natural;
end Server;

server.adb:

package body Server is
   Count : Natural := 0;

   procedure Foo is
   begin
      Count := Count + 1;
   end Foo;

   function Bar return Natural is
   begin
      return Count;
   end Bar;
end Server;

client.adb:

with Server;
with Ada.Text_IO;

procedure Client is
begin
   Ada.Text_IO.Put_Line ("Calling Foo...");
   Server.Foo;
   Ada.Text_IO.Put_Line ("Calling Bar: " & Integer'Image (Server.Bar));
end Client;

required config (dsa.cfg):

configuration DSA is
   pragma Starter (None);

   -- Server
   Server_Partition : Partition := (Server);
   procedure Run_Server is in Server_Partition;

   -- Client
   Client_Partition : Partition;
   for Client_Partition'Termination use Local_Termination;
   procedure Client;
   for Client_Partition'Main use Client;
end DSA;

compilation:

$po_gnatdist dsa.cfg
[...]
 ------------------------------
 ---- Configuration report ----
 ------------------------------
Configuration :
   Name        : dsa
   Main        : run_server
   Starter     : none

Partition server_partition
   Main        : run_server
   Units       :
             - server (rci)
             - run_server (normal)
             - polyorb.dsa_p.partitions (rci, from PCS)

   Environment variables :
             - "POLYORB_DSA_NAME_SERVICE"

Partition client_partition
   Main        : client
   Termination : local
   Units       :
             - client (normal)

   Environment variables :
             - "POLYORB_DSA_NAME_SERVICE"

 -------------------------------
[...]

preparation (run PolyORB name service):

$ po_ioc_naming
POLYORB_CORBA_NAME_SERVICE=IOR:010000002b00000049444[...]
POLYORB_CORBA_NAME_SERVICE=corbaloc:iiop:1.2@10.200.[...]

You have to set the environment variable POLYORB_DSA_NAME_SERVICE to one of the two values given by po_ioc_naming for the server/client partitions.

running server:

$ ./server_partition

running client:

$ ./client_partition
Calling Foo...
Calling Bar:  1
$ ./client_partition
Calling Foo...
Calling Bar:  2

AutoHotkey

See Distributed program/AutoHotkey.

C

Using PVM [1] This program is in a sense both a server and a client, depending on if its task is spawned with a command-line argument: if yes, it spawns another task of the same executible on the parallel virtual machine and waits for it to transmit data; if no, it transmits data and is done.

#include <stdio.h>
#include <stdlib.h>
#include <pvm3.h>

int main(int c, char **v)
{
	int tids[10];
	int parent, spawn;
	int i_data, i2;
	double f_data;

	if (c > 1) {
		spawn = pvm_spawn("/tmp/a.out", 0, PvmTaskDefault, 0, 1, tids);
		if (spawn <= 0) {
			printf("Can't spawn task\n");
			return 1;
		}

		printf("Spawning successful\n");

		/* pvm_recv(task_id, msgtag).  msgtag identifies what kind of data it is,
 		 * for here: 1 = (int, double), 2 = (int, int)
		 * The receiving order is intentionally swapped, just to show.
		 * task_id = -1 means "receive from any task"
		 */
		pvm_recv(-1, 2);
		pvm_unpackf("%d %d", &i_data, &i2);
		printf("got msg type 2: %d %d\n", i_data, i2);

		pvm_recv(-1, 1);
		pvm_unpackf("%d %lf", &i_data, &f_data);
		printf("got msg type 1: %d %f\n", i_data, f_data);
	} else {
		parent = pvm_parent();

		pvm_initsend(PvmDataDefault);
		i_data = rand();
		f_data = (double)rand() / RAND_MAX;
		pvm_packf("%d %lf", i_data, f_data);
		pvm_send(parent, 1);	/* send msg type 1 */

		pvm_initsend(PvmDataDefault);
		i2 = rand();
		pvm_packf("%d %d", i_data, i2);
		pvm_send(parent, 2);	/* send msg type 2 */
	}

	pvm_exit();
	return 0;
}
Output:

(running it on PVM console, exe is /tmp/a.out)

pvm> spawn -> /tmp/a.out 1
spawn -> /tmp/a.out 1
[2]
1 successful
t40028
pvm> [2:t40029] EOF
[2:t40028] Spawning successful
[2:t40028] got msg type 2: 1804289383 1681692777
[2:t40028] got msg type 1: 1804289383 0.394383
[2:t40028] EOF
[2] finished

C#

Start the program with "server" parameter to start the server, and "client" to start the client. The client will send data to the server and receive a response. The server will wait for data, display the data received, and send a response.

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading.Tasks;

using static System.Console;

class DistributedProgramming
{
    const int Port = 555;

    async static Task RunClient()
    {
        WriteLine("Connecting");
        var client = new TcpClient();
        await client.ConnectAsync("localhost", Port);

        using (var stream = client.GetStream())
        {
            WriteLine("Sending loot");
            var data = Serialize(new SampleData());
            await stream.WriteAsync(data, 0, data.Length);

            WriteLine("Receiving thanks");
            var buffer = new byte[80000];
            var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
            var thanks = (string)Deserialize(buffer, bytesRead);
            WriteLine(thanks);
        }

        client.Close();
    }

    async static Task RunServer()
    {
        WriteLine("Listening");
        var listener = new TcpListener(IPAddress.Any, Port);
        listener.Start();
        var client = await listener.AcceptTcpClientAsync();

        using (var stream = client.GetStream())
        {
            WriteLine("Receiving loot");
            var buffer = new byte[80000];
            var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
            var data = (SampleData)Deserialize(buffer, bytesRead);
            WriteLine($"{data.Loot} at {data.Latitude}, {data.Longitude}");

            WriteLine("Sending thanks");
            var thanks = Serialize("Thanks!");
            await stream.WriteAsync(thanks, 0, thanks.Length);
        }

        client.Close();
        listener.Stop();
        Write("Press a key");
        ReadKey();
    }

    static byte[] Serialize(object data)
    {
        using (var mem = new MemoryStream())
        {
            new BinaryFormatter().Serialize(mem, data);
            return mem.ToArray();
        }
    }

    static object Deserialize(byte[] data, int length)
    {
        using (var mem = new MemoryStream(data, 0, length))
        {
            return new BinaryFormatter().Deserialize(mem);
        }
    }

    static void Main(string[] args)
    {
        if (args.Length == 0) return;

        switch (args[0])
        {
            case "client": RunClient().Wait(); break;
            case "server": RunServer().Wait(); break;
        }
    }
}

[Serializable]
class SampleData
{
    public decimal Latitude = 44.33190m;
    public decimal Longitude = 114.84129m;
    public string Loot = "140 tonnes of jade";
}

D

Uses the rpc library: https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff/blob/master/rpc.d

This library is not standard, so this code (by Adam D. Ruppe) could and should be rewritten using more standard means.

import arsd.rpc;

struct S1 {
    int number;
    string name;
}

struct S2 {
    string name;
    int number;
}

interface ExampleNetworkFunctions {
    string sayHello(string name);
    int add(in int a, in int b) const pure nothrow;
    S2 structTest(S1);
    void die();
}

// The server must implement the interface.
class ExampleServer : ExampleNetworkFunctions {
    override string sayHello(string name) {
        return "Hello, " ~ name;
    }

    override int add(in int a, in int b) const pure nothrow {
        return a + b;
    }

    override S2 structTest(S1 a) {
        return S2(a.name, a.number);
    }

    override void die() {
        throw new Exception("death requested");
    }

    mixin NetworkServer!ExampleNetworkFunctions;
}

class Client {
    mixin NetworkClient!ExampleNetworkFunctions;
}

void main(in string[] args) {
    import std.stdio;

    if (args.length > 1) {
        auto client = new Client("localhost", 5005);
        // These work like the interface above, but instead of
        // returning the value, they take callbacks for success (where
        // the arg is the retval) and failure (the arg is the
        // exception).
        client.sayHello("whoa", (a) { writeln(a); }, null);
        client.add(1,2, (a){ writeln(a); }, null);
        client.add(10,20, (a){ writeln(a); }, null);
        client.structTest(S1(20, "cool!"),
                          (a){ writeln(a.name, " -- ", a.number); },
                          null);
        client.die(delegate(){ writeln("shouldn't happen"); },
                   delegate(a){ writeln(a); });
        client.eventLoop;
    } else {
        auto server = new ExampleServer(5005);
        server.eventLoop;
    }
}

E

Protocol: Pluribus

This service cannot be used except by clients which know the URL designating it, messages are encrypted, and the client authenticates the server. However, it is vulnerable to denial-of-service by any client knowing the URL.

Server

(The protocol is symmetric; this program is the server only in that it is the one which is started first and exports an object.)

def storage := [].diverge()

def logService {
  to log(line :String) {
    storage.push([timer.now(), line])
  }
  to search(substring :String) {
    var matches := []
    for [time, line] ? (line.startOf(substring) != -1) in storage {
      matches with= [time, line]
    }
    return matches
  }
}

introducer.onTheAir()
def sturdyRef := makeSturdyRef.temp(logService)
println(<captp>.sturdyToURI(sturdyRef))
interp.blockAtTop()

This will print the URL of the service and run it until aborted.

Client

The URL provided by the server is given as the argument to this program.

def [uri] := interp.getArgs()
introducer.onTheAir()
def sturdyRef := <captp>.sturdyFromURI(uri)
def logService := sturdyRef.getRcvr()

logService <- log("foot")
logService <- log("shoe")

println("Searching...")
when (def result := logService <- search("foo")) -> {
  for [time, line] in result {
    println(`At $time: $line`)
  }
}

Erlang

The protocol is erlang's own

Server

srv.erl

-module(srv).
-export([start/0, wait/0]).

start() ->
   net_kernel:start([srv,shortnames]),
   erlang:set_cookie(node(), rosetta),
   Pid = spawn(srv,wait,[]),
   register(srv,Pid),
   io:fwrite("~p ready~n",[node(Pid)]),
   ok.

wait() ->
   receive
       {echo, Pid, Any} ->
           io:fwrite("-> ~p from ~p~n", [Any, node(Pid)]),
           Pid ! {hello, Any},
           wait();
       Any -> io:fwrite("Error ~p~n", [Any])
   end.

Client

client.erl

-module(client).
-export([start/0, wait/0]).

start() ->
   net_kernel:start([client,shortnames]),
   erlang:set_cookie(node(), rosetta),
   {ok,[[Srv]]} = init:get_argument(server),
   io:fwrite("connecting to ~p~n", [Srv]),
   {srv, list_to_atom(Srv)} ! {echo,self(), hi},
   wait(),
   ok.

wait() ->
   receive
       {hello, Any} -> io:fwrite("Received ~p~n", [Any]);
       Any -> io:fwrite("Error ~p~n", [Any])
   end.

running it (*comes later)

|erlc srv.erl
|erl -run srv start -noshell
 srv@agneyam ready
*-> hi from client@agneyam
|erlc client.erl
|erl -run client start -run init stop -noshell -server srv@agneyam
 connecting to "srv@agneyam"
 Received hi

Factor

The protocol is the one provided by Factor (concurrency.distributed, concurrency.messaging)

Example summary:

- A server node is listening for messages made of natural data types and structures, and simply prettyprint them.

- A client node is sending such data structure: an array of one string and one hashtable (with one key/value pair).

Server

USING: concurrency.distributed concurrency.messaging threads io.sockets io.servers ;
QUALIFIED: concurrency.messaging
: prettyprint-message ( -- ) concurrency.messaging:receive . flush prettyprint-message ;
[ prettyprint-message ] "logger" spawn dup name>> register-remote-thread
"127.0.0.1" 9000 <inet4> <node-server> start-server

Note: we are using QUALIFIED: with the concurrency.messaging vocabulary because the "receive" word is defined in io.sockets vocabulary too. If someone have a cleaner way to handle this.

Client

USING: concurrency.distributed io.sockets ;
QUALIFIED: concurrency.messaging
{ "Hello Remote Factor!" H{ { "key1" "value1" } } } 
"127.0.0.1" 9000 <inet4> "logger" <remote-thread> concurrency.messaging:send

How to Run:

- Copy/Paste the server code in an instance of Factor Listener

- Copy/Paste the client code in another instance of Factor Listener.

The server node should prettyprint the data structure send by the client: { "Hello Remote Factor!" H{ { "key1" "value1" } } }

Go

Standard library net/rpc

Package net/rpc in the Go standard library serializes data with the Go-native "gob" type. The example here sends only a single floating point number, but the package will send any user-defined data type, including of course structs with multiple fields.

Server:

package main

import (
    "errors"
    "log"
    "net"
    "net/http"
    "net/rpc"
)

type TaxComputer float64

func (taxRate TaxComputer) Tax(x float64, r *float64) error {
    if x < 0 {
        return errors.New("Negative values not allowed")
    }
    *r = x * float64(taxRate)
    return nil
}

func main() {
    c := TaxComputer(.05)
    rpc.Register(c)
    rpc.HandleHTTP()
    listener, err := net.Listen("tcp", ":1234")
    if err != nil {
        log.Fatal(err)
    }
    http.Serve(listener, nil)
}

Client:

package main

import (
    "fmt"
    "log"
    "net/rpc"
)

func main() {
    client, err := rpc.DialHTTP("tcp", "localhost:1234")
    if err != nil {
        fmt.Println(err)
        return
    }

    amount := 3.
    var tax float64
    err = client.Call("TaxComputer.Tax", amount, &tax)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Tax on %.2f: %.2f\n", amount, tax)
}
Client output:
Tax on 3.00: 0.15

gRPC

See http://www.grpc.io/

The default serialization for gRPC is "protocol buffers." gRPC uses a .proto file to define an interface for the client and server. The .proto has its own syntax, independent of client and server implementation languages. Server and client programs here are Go however.

.proto:

syntax = "proto3";

service TaxComputer {
  rpc Tax(Amount) returns (Amount) {}
}

message Amount {
  int32 cents = 1;
}

Server:

package main

import (
    "errors"
    "net"

    "golang.org/x/net/context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/grpclog"

    "taxcomputer"
)

type taxServer struct {
    rate float64
}

func (s *taxServer) Tax(ctx context.Context,
    amt *taxcomputer.Amount) (*taxcomputer.Amount, error) {
    if amt.Cents < 0 {
        return nil, errors.New("Negative amounts not allowed")
    }
    return &taxcomputer.Amount{int32(float64(amt.Cents)*s.rate + .5)}, nil
}

func main() {
    listener, err := net.Listen("tcp", ":1234")
    if err != nil {
        grpclog.Fatalf(err.Error())
    }
    grpcServer := grpc.NewServer()
    taxcomputer.RegisterTaxComputerServer(grpcServer, &taxServer{.05})
    grpcServer.Serve(listener)
}

Client:

package main

import (
    "fmt"

    "golang.org/x/net/context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/grpclog"

    "taxcomputer"
)

func main() {
    conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
    if err != nil {
        grpclog.Fatalf(err.Error())
    }
    defer conn.Close()
    client := taxcomputer.NewTaxComputerClient(conn)
    amt := &taxcomputer.Amount{300}
    tax, err := client.Tax(context.Background(), amt)
    if err != nil {
        grpclog.Fatalf(err.Error())
    }
    fmt.Println("Tax on", amt.Cents, "cents is", tax.Cents, "cents")
}
Client output:
Tax on 300 cents is 15 cents

Apache Thrift

See https://thrift.apache.org/

.thrift

Like gRPC, Thrift requires a language independent interface definition file:

service TaxService {
   i32 tax(1: i32 amt)
}

Server:

package main

import (
    "errors"
    "log"

    "git.apache.org/thrift.git/lib/go/thrift"

    "gen-go/tax"
)

type taxHandler float64

func (r taxHandler) Tax(amt int32) (int32, error) {
    if amt < 0 {
        return 0, errors.New("Negative amounts not allowed")
    }
    return int32(float64(amt)*float64(r) + .5), nil
}

func main() {
    transport, err := thrift.NewTServerSocket("localhost:3141")
    if err != nil {
        log.Fatal(err)
    }
    transFac := thrift.NewTTransportFactory()
    protoFac := thrift.NewTCompactProtocolFactory()
    proc := tax.NewTaxServiceProcessor(taxHandler(.05))
    s := thrift.NewTSimpleServer4(proc, transport, transFac, protoFac)
    if err := s.Serve(); err != nil {
        log.Fatal(err)
    }
}

Client:

package main

import (
    "fmt"
    "log"

    "git.apache.org/thrift.git/lib/go/thrift"

    "gen-go/tax"
)

func main() {
    transport, err := thrift.NewTSocket("localhost:3141")
    if err != nil {
        log.Fatal(err)
    }
    if err := transport.Open(); err != nil {
        log.Fatal(err)
    }
    protoFac := thrift.NewTCompactProtocolFactory()
    client := tax.NewTaxServiceClientFactory(transport, protoFac)
    amt := int32(300)
    t, err := client.Tax(amt)
    if err != nil {
        log.Print(err)
    } else {
        fmt.Println("tax on", amt, "is", t)
    }
    transport.Close()
}
Client output:
tax on 300 is 15

Haskell

See:

Check license: http://www.haskell.org/haskellwiki/HaskellWiki:Copyrights

JavaScript

Works with: node.js

Server

var net = require('net')

var server = net.createServer(function (c){
  c.write('hello\r\n')
  c.pipe(c) // echo messages back
})

server.listen(3000, 'localhost')

Client

var net = require('net')

conn = net.createConnection(3000, '192.168.1.x')

conn.on('connect', function(){
	console.log('connected')
	conn.write('test')
})

conn.on('data', function(msg){
	console.log(msg.toString())
})

Julia

Julia was designed with distributed conmputing. in particular cluster computing, as a primary use target. If a group of CPUs, including multiple cores on a single machine or a cluster running with paswordless ssh login, is used, the following can be set up as an example:

# From Julia 1.0's online docs. File countheads.jl available to all machines:

function count_heads(n)
    c::Int = 0
    for i = 1:n
        c += rand(Bool)
    end
    c
end

We then run the following on the primary client:

using Distributed
@everywhere include_string(Main, $(read("count_heads.jl", String)), "count_heads.jl")

a = @spawn count_heads(100000000) # runs on an available processor
b = @spawn count_heads(100000000) # runs on another available processor

println(fetch(a)+fetch(b)) # total heads of 200 million coin flips, half on each CPU
Output:

100001564

LFE

The protocol used is the one native to Erlang (and thus native to LFE, Lisp Flavored Erlang).

These examples are done completely in the LFE REPL.

Server

In one terminal window, start up the REPL

$ ./bin/lfe
Erlang/OTP 17 [erts-6.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

LFE Shell V6.2 (abort with ^G)
>

And then enter the following code

> (defun get-server-name ()
    (list_to_atom (++ "exampleserver@" (element 2 (inet:gethostname)))))

> (defun start ()
    (net_kernel:start `(,(get-server-name) shortnames))
    (erlang:set_cookie (node) 'rosettaexample)
    (let ((pid (spawn #'listen/0)))
      (register 'serverref pid)
      (io:format "~p ready~n" (list (node pid)))
      'ok))

> (defun listen ()
    (receive
      (`#(echo ,pid ,data)
        (io:format "Got ~p from ~p~n" (list data (node pid)))
        (! pid `#(hello ,data))
        (listen))
      (x
        (io:format "Unexpected pattern: ~p~n" `(,x)))))

Client

In another terminal window, start up another LFE REPL and ender the following code:

> (defun get-server-name ()
    (list_to_atom (++ "exampleserver@" (element 2 (inet:gethostname)))))

> (defun send (data)
    (net_kernel:start '(exampleclient shortnames))
    (erlang:set_cookie (node) 'rosettaexample)
    (io:format "connecting to ~p~n" `(,(get-server-name)))
    (! `#(serverref ,(get-server-name)) `#(echo ,(self) ,data))
    (receive
      (`#(hello ,data)
        (io:format "Received ~p~n" `(,data)))
      (x
        (io:format "Unexpected pattern: ~p~n" (list x))))
    'ok)

To use this code, simply start the server in the server terminal:

> (start)
exampleserver@yourhostname ready
ok
(exampleserver@yourhostname)>

Send some messages from the client terminal:

> (send "hi there")                                        
connecting to exampleserver@yourhostname
Received "hi there"
ok
(exampleclient@yourhostname)> (send 42)          
connecting to exampleserver@yourhostname
Received 42
ok
(exampleclient@yourhostname)> (send #(key value))
connecting to exampleserver@yourhostname
Received {key,value}
ok
(exampleclient@yourhostname)>

And check out the results back in the server terminal window:

Got "hi there" from exampleclient@yourhostname
Got 42 from exampleclient@yourhostname
Got {key,value} from exampleclient@yourhostname

Mathematica / Wolfram Language

The following sends a request for a random number to be generated on each of two nodes, these are then transmitted back to be assembled into an array with two elements. Omitting the first line, will cause the program to be run on all configured remote computers.

LaunchKernels[2];
ParallelEvaluate[RandomReal[]]

Nim

Library: nanomsg
import os, nanomsg

proc sendMsg(s: cint, msg: string) =
  echo "SENDING \"",msg,"\""
  let bytes = s.send(msg.cstring, msg.len + 1, 0)
  assert bytes == msg.len + 1

proc recvMsg(s: cint) =
  var buf: cstring
  let bytes = s.recv(addr buf, MSG, 0)
  if bytes > 0:
    echo "RECEIVED \"",buf,"\""
    discard freemsg buf

proc sendRecv(s: cint, msg: string) =
  var to: cint = 100
  discard s.setSockOpt(SOL_SOCKET, RCVTIMEO, addr to, sizeof to)
  while true:
    s.recvMsg
    sleep 1000
    s.sendMsg msg

proc node0(url: string) =
  var s = socket(AF_SP, nanomsg.PAIR)
  assert s >= 0
  let res = s.bindd url
  assert res >= 0
  s.sendRecv "node0"
  discard s.shutdown 0

proc node1(url: string) =
  var s = socket(AF_SP, nanomsg.PAIR)
  assert s >= 0
  let res = s.connect url
  assert res >= 0
  s.sendRecv "node1"
  discard s.shutdown 0

if paramStr(1) == "node0":
  node0 paramStr(2)
elif paramStr(1) == "node1":
  node1 paramStr(2)

Usage:

./pair node0 tcp://127.0.0.1:25000
./pair node1 tcp://127.0.0.1:25000

Objective-C

Distributed Objects are natural to Objective-C, and OpenStep and derivated framework offers an easy way of using remote objects as if it were local. The client must only know the protocol the remote object support. For the rest, calling a remote object's method or local object's method is transparent.

Works with: GNUstep

Server

The server vending the object with the name DistributedAction

ActionObjectProtocol.h

#import <Foundation/Foundation.h>
// our protocol allows "sending" "strings", but we can implement
// everything we could for a "local" object
@protocol ActionObjectProtocol
- (NSString *)sendMessage: (NSString *)msg;
@end

ActionObject.h

#import <Foundation/Foundation.h>
#import "ActionObjectProtocol.h"

@interface ActionObject : NSObject <ActionObjectProtocol>
  // we do not have much for this example!
@end

ActionObject.m

#import <Foundation/Foundation.h>
#import "ActionObject.h"

@implementation ActionObject
-(NSString *)sendMessage: (NSString *)msg
{
  NSLog(@"client sending message %@", msg);
  return @"server answers ...";
}
@end

server.m

#import <Foundation/Foundation.h>
#import "ActionObject.h"

int main (void)
{
  @autoreleasepool {
  
    ActionObject *action = [[ActionObject alloc] init];

    NSSocketPort *port = (NSSocketPort *)[NSSocketPort port];
    // initWithTCPPort: 1234 and other methods are not supported yet
    // by GNUstep
    NSConnection *connect = [NSConnection 
  	      connectionWithReceivePort: port
  	      sendPort: port]; // or sendPort: nil

    [connect setRootObject: action];

    /* "vend" the object ActionObject as DistributedAction; on GNUstep
       the Name Server that allows the resolution of the registered name
       is bound to port 538 */
    if (![connect registerName:@"DistributedAction"
  	       withNameServer: [NSSocketPortNameServer sharedInstance] ]) 
    {
      NSLog(@"can't register the server DistributedAction");
      exit(EXIT_FAILURE);
    }
  
    NSLog(@"waiting for messages...");

    [[NSRunLoop currentRunLoop] run];

  }
  return 0;
}

Client

client.m

#import <Foundation/Foundation.h>
#import "ActionObjectProtocol.h"

int main(void)
{
  @autoreleasepool {

    id <ActionObjectProtocol> action = (id <ActionObjectProtocol>)
      [NSConnection
        rootProxyForConnectionWithRegisteredName: @"DistributedAction" 
        host: @"localhost"
        usingNameServer: [NSSocketPortNameServer sharedInstance] ];

    if (action == nil)
    {
      NSLog(@"can't connect to the server");
      exit(EXIT_FAILURE);
    }
  
    NSArray *args = [[NSProcessInfo processInfo] arguments];

    if ([args count] == 1)
    {
      NSLog(@"specify a message");
      exit(EXIT_FAILURE);
    }
  
    NSString *msg = args[1];

    // "send" (call the selector "sendMessage:" of the (remote) object
    // action) the first argument's text as msg, store the message "sent
    // back" and then show it in the log
    NSString *backmsg = [action sendMessage: msg];
    NSLog("%@", backmsg);

  }
  return 0;
}

OCaml

Works with: JoCaml

Minimalistic distributed logger with synchronous channels using the join calculus on top of OCaml.

Server

open Printf
 
let create_logger () =
  def log(text) & logs(l) =
      printf "Logged: %s\n%!" text;
      logs((text, Unix.gettimeofday ())::l) & reply to log

   or search(text) & logs(l) =
      logs(l) & reply List.filter (fun (line, _) -> line = text) l to search
  in
    spawn logs([]);
    (log, search)

def wait() & finished() = reply to wait

let register name service = Join.Ns.register Join.Ns.here name service
 
let () =
  let log, search = create_logger () in
    register "log" log;
    register "search" search;
    Join.Site.listen (Unix.ADDR_INET (Join.Site.get_local_addr(), 12345));
    wait ()

Client

open Printf
 
let ns_there = Join.Ns.there (Unix.ADDR_INET (Join.Site.get_local_addr(), 12345))
 
let lookup name = Join.Ns.lookup ns_there name

let log : string -> unit = lookup "log"
let search : string -> (string * float) list = lookup "search"
 
let find txt =
  printf "Looking for %s...\n" txt;
  List.iter (fun (line, time) ->
               printf "Found: '%s' at t = %f\n%!" (String.escaped line) time)
    (search txt)
 
let () =
  log "bar";
  find "foo";
  log "foo";
  log "shoe";
  find "foo"

Oz

We show a program that starts a server on a remote machine, exchanges two messages with that server and finally shuts it down.

declare
  functor ServerCode
  export
     port:Prt
  define
     Stream
     Prt = {NewPort ?Stream}
     thread
	for Request#Reply in Stream do
	   case Request
	   of echo(Data)        then Reply = Data
	   [] compute(Function) then Reply = {Function}
	   end
	end
     end
  end

  %% create the server on some machine
  %% (just change "localhost" to some machine
  %% that you can use with a passwordless rsh login
  %% and that has the same Mozart version installed)
  RM = {New Remote.manager init(host:localhost)}

  %% execute the code encapsulated in the ServerCode functor
  Server = {RM apply(ServerCode $)}

  %% Shortcut: send a message to Server and receive a reply
  fun {Send X}
     {Port.sendRecv Server.port X}
  end
in 
  %% echo
  {System.showInfo "Echo reply: "#{Send echo(hello)}}

  %% compute
  {System.showInfo "Result of computation: "#
   {Send compute(fun {$} 8 div 4 end)}}

  %% shut down server
  {RM close}

Perl

Using Data::Dumper and Safe to transmit arbitrary data structures as serialized text between hosts. Same code works as both sender and receiver.

use Data::Dumper;
use IO::Socket::INET;
use Safe;

sub get_data {
	my $sock = new IO::Socket::INET
		LocalHost =>	"localhost",
		LocalPort =>	"10000",
		Proto =>	"tcp",
		Listen =>	1,
		Reuse =>	1;
	unless ($sock) { die "Socket creation failure" }
	my $cli = $sock->accept();

	# of course someone may be tempted to send you 'system("rm -rf /")',
	# to be safe(r), use Safe::
	my $safe = new Safe;
	my $x = $safe->reval(join("", <$cli>));
	close $cli;
	close $sock;
	return $x;
}

sub send_data {
	my $host = shift;
	my $data = shift;
	my $sock = new IO::Socket::INET
		PeerAddr =>	"$host:10000",
		Proto =>	"tcp",
		Reuse =>	1;

	unless ($sock) { die "Socket creation failure" }

	print $sock Data::Dumper->Dump([$data]);
	close $sock;
}

if (@ARGV) {
	my $x = get_data();
	print "Got data\n", Data::Dumper->Dump([$x]);
} else {
	send_data('some_host', { a=>100, b=>[1 .. 10] });
}

Phix

From/using the ZeroMQ wrapper from PCAN, a suitable simple publish/subscriber pair. There is also a server/client/broker example. Obviously you can trivially serialize() and deserialize() any Phix data to and from a string.

without js -- (zmq dll/so)
puts(1, "durapub:\n")
include zmq/zmq.e

atom context = zmq_init(1)
zmq_assert(context, "zmq_init")

--// subscriber tells us when it's ready here
atom sync = zmq_socket(context, ZMQ_PULL)
zmq_bind(sync, "tcp://*:5564")

--// send update via this socket
atom publisher = zmq_socket(context, ZMQ_PUB)
zmq_bind(publisher, "tcp://*:5565")

--// broadcast 10 updates, with pause
for update_nbr = 1 to 10 do
    string s = sprintf("Update %d", { update_nbr })
    zmq_s_send(publisher, s)
    sleep(1)
end for

zmq_s_send(publisher, "END")
sleep(1)

zmq_close(sync)
zmq_close(publisher)
zmq_term(context)
without js -- (zmq dll/so)
puts(1, "durasub:\n")
include zmq/zmq.e

atom context = zmq_init(1)
zmq_assert(context, "zmq_init")

--// connect our subscriber socket
atom subscriber = zmq_socket(context, ZMQ_SUB)
atom id = allocate_string("Hello")
zmq_setsockopt(subscriber, ZMQ_IDENTITY, id, 5)
zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, 0, 0)
zmq_connect(subscriber, "tcp://localhost:5565")
free(id)

--// synchronise with publisher
atom sync = zmq_socket(context, ZMQ_PUSH)
zmq_connect(sync, "tcp://localhost:5564")
zmq_s_send(sync, "")

--// get updates, Ctrl-C break
while true do
    string s = zmq_s_recv(subscriber)
    printf(1, "%s\n", {s})
    if s=="END" then exit end if
end while

zmq_close(sync)
zmq_close(subscriber)
zmq_term(context)

PicoLisp

Server

(task (port 12321)                     # Background server task
   (let? Sock (accept @)
      (unless (fork)                   # Handle request in child process
         (in Sock
            (while (rd)                # Handle requests
               (out Sock
                  (pr (eval @)) ) ) )  # Evaluate and send reply
         (bye) )                       # Exit child process
      (close Sock) ) )                 # Close socket in parent process

Client

(let? Sock (connect "localhost" 12321)
   (out Sock (pr '*Pid))               # Query PID from server
   (println 'PID (in Sock (rd)))       # Receive and print reply
   (out Sock (pr '(* 3 4)))            # Request some calculation
   (println 'Result (in Sock (rd)))    # Print result
   (close Sock) )                      # Close connection to server

Output:

PID 18372
Result 12

Python

Works with: Python version 2.4 and 2.6

XML-RPC

Protocol: XML-RPC

Server

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import SimpleXMLRPCServer

class MyHandlerInstance:
    def echo(self, data):
        '''Method for returning data got from client'''
        return 'Server responded: %s' % data

    def div(self, num1, num2):
        '''Method for divide 2 numbers'''
        return num1/num2

def foo_function():
    '''A function (not an instance method)'''
    return True

HOST = "localhost"
PORT = 8000

server = SimpleXMLRPCServer.SimpleXMLRPCServer((HOST, PORT))

# register built-in system.* functions.
server.register_introspection_functions()

# register our instance
server.register_instance(MyHandlerInstance())

# register our function as well
server.register_function(foo_function)

try:
    # serve forever
    server.serve_forever()
except KeyboardInterrupt:
    print 'Exiting...'
    server.server_close()

Client

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import xmlrpclib

HOST = "localhost"
PORT = 8000

rpc = xmlrpclib.ServerProxy("http://%s:%d" % (HOST, PORT))

# print what functions does server support 
print 'Server supports these functions:',
print ' '.join(rpc.system.listMethods())

# echo something
rpc.echo("We sent this data to server")

# div numbers
print 'Server says: 8 / 4 is: %d' % rpc.div(8, 4)

# control if foo_function returns True
if rpc.foo_function():
    print 'Server says: foo_function returned True'

HTTP

Protocol: HTTP

Server

#!/usr/bin/python
# -*- coding: utf-8 -*-

import BaseHTTPServer

HOST = "localhost"
PORT = 8000

# we just want to write own class, we replace do_GET method. This could be extended, I just added basics
# see; http://docs.python.org/lib/module-BaseHTTPServer.html
class MyHTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_GET(self):
        # send 200 (OK) message
        self.send_response(200)
        # send header
        self.send_header("Content-type", "text/html")
        self.end_headers()

        # send context
        self.wfile.write("<html><head><title>Our Web Title</title></head>")
        self.wfile.write("<body><p>This is our body. You wanted to visit <b>%s</b> page</p></body>" % self.path)
        self.wfile.write("</html>")

if __name__ == '__main__':
    server = BaseHTTPServer.HTTPServer((HOST, PORT), MyHTTPHandler)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print 'Exiting...'
        server.server_close()

Client

#!/usr/bin/python
# -*- coding: utf-8 -*-

import httplib

HOST = "localhost"
PORT = 8000

conn = httplib.HTTPConnection(HOST, PORT)
conn.request("GET", "/somefile")

response = conn.getresponse()
print 'Server Status: %d' % response.status

print 'Server Message: %s' % response.read()

Socket, Pickle format

Protocol: raw socket / pickle format

This example builds a very basic RPC mechanism on top of sockets and the pickle module. Please note that the pickle module is not secure - a malicious client can build malformed data to execute arbitrary code on the server. If untrusted clients can access the server, the json module could be used as a substitute, but we lose the ability to transfer arbitrary Python objects that way.

Server

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import SocketServer
import pickle
 
HOST = "localhost"
PORT = 8000

class RPCServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    # The object_to_proxy member should be set to the object we want
    # methods called on. Unfortunately, we can't do this in the constructor
    # because the constructor should not be overridden in TCPServer...

    daemon_threads = True

class RPCHandler(SocketServer.StreamRequestHandler):
    def handle(self):
        in_channel = pickle.Unpickler(self.rfile)
        out_channel = pickle.Pickler(self.wfile, protocol=2)
        while True:
            try:
                name, args, kwargs = in_channel.load()
                print 'got %s %s %s' % (name, args, kwargs)
            except EOFError:
                # EOF means we're done with this request.
                # Catching this exception to detect EOF is a bit hackish,
                # but will work for a quick demo like this
                break
            try:
                method = getattr(self.server.object_to_proxy, name)
                result = method(*args, **kwargs)
            except Exception, e:
                out_channel.dump(('Error',e))
            else:
                out_channel.dump(('OK',result))

class MyHandlerInstance(object):
    def echo(self, data):
        '''Method for returning data got from client'''
        return 'Server responded: %s' % data
 
    def div(self, dividend, divisor):
        '''Method to divide 2 numbers'''
        return dividend/divisor
 
    def is_computer_on(self):
        return True
 
if __name__ == '__main__':
    rpcserver = RPCServer((HOST, PORT), RPCHandler)
    rpcserver.object_to_proxy = MyHandlerInstance()
    try:
        rpcserver.serve_forever()
    except KeyboardInterrupt:
        print 'Exiting...'
        rpcserver.server_close()

Client

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import socket
import pickle
 
HOST = "localhost"
PORT = 8000

class RPCClient(object):
    def __init__(self, host, port):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((host, port))
        self.rfile = self.socket.makefile('rb')
        self.wfile = self.socket.makefile('wb')
        self.in_channel = pickle.Unpickler(self.rfile)
        self.out_channel = pickle.Pickler(self.wfile, protocol=2)

    def _close(self):
        self.socket.close()
        self.rfile.close()
        self.wfile.close()

    # Make calling remote methods easy by overriding attribute access.
    # Accessing any attribute on our instances will give a proxy method that
    # calls the method with the same name on the remote machine.
    def __getattr__(self, name):
        def proxy(*args, **kwargs):
            self.out_channel.dump((name, args, kwargs))
            self.wfile.flush() # to make sure the server won't wait forever
            status, result = self.in_channel.load()
            if status == 'OK':
                return result
            else:
                raise result

        return proxy
 
if __name__ == '__main__':
    # connect to server and send data
    rpcclient = RPCClient(HOST, PORT)

    print 'Testing the echo() method:'
    print rpcclient.echo('Hello world!')
    print
    print 'Calculating 42/2 on the remote machine:'
    print rpcclient.div(42, 2)
    print
    print 'is_computer_on on the remote machine returns:'
    print rpcclient.is_computer_on()
    print
    print 'Testing keyword args:'
    print '42/2 is:', rpcclient.div(divisor=2, dividend=42)
    rpcclient._close()
    del rpcclient

Pyro

Note: You should install Pyro (http://pyro.sourceforge.net) first and run pyro-ns binary to run code below.

Server

#!/usr/bin/python
# -*- coding: utf-8 -*-

import Pyro.core
import Pyro.naming

# create instance that will return upper case
class StringInstance(Pyro.core.ObjBase):
    def makeUpper(self, data):
        return data.upper()

class MathInstance(Pyro.core.ObjBase):
    def div(self, num1, num2):
        return num1/num2

if __name__ == '__main__':
    server = Pyro.core.Daemon()
    name_server = Pyro.naming.NameServerLocator().getNS()
    server.useNameServer(name_server)
    server.connect(StringInstance(), 'string')
    server.connect(MathInstance(), 'math')
    try:
        server.requestLoop()
    except KeyboardInterrupt:
        print 'Exiting...'
        server.shutdown()

Client

#!/usr/bin/python
# -*- coding: utf-8 -*-

import Pyro.core

DATA = "my name is eren"
NUM1 = 10
NUM2 = 5

string = Pyro.core.getProxyForURI("PYRONAME://string")
math = Pyro.core.getProxyForURI("PYRONAME://math")

print 'We sent: %s' % DATA
print 'Server responded: %s\n' % string.makeUpper(DATA)

print 'We sent two numbers to divide: %d and %d' % (NUM1, NUM2)
print 'Server responded the result: %s' % math.div(NUM1, NUM2)

Spread

Note: You should install Spread (http://www.spread.org) and its python bindings (http://www.python.org/other/spread/)

Server

You don't need any code for server. You should start "spread" daemon by typing "spread -c /etc/spread.conf -n localhost". If you want more configuration, look at /etc/spread.conf.

After starting daemon, if you want to make sure that it is running, enter spuser -s 4803 command where 4803 is your port set in spread.conf, you will see prompt, type j user, you should see something like this message: Received REGULAR membership for group test with 3 members, where I am member 2

Client (Listener)

#!/usr/bin/python
# -*- coding: utf-8 -*-

import spread

PORT = '4803'

# connect spread daemon
conn = spread.connect(PORT)
# join the room
conn.join('test')

print 'Waiting for messages... If you want to stop this script, please stop spread daemon'
while True:
    recv = conn.receive()
    if hasattr(recv, 'sender') and hasattr(recv, 'message'):
        print 'Sender: %s' % recv.sender
        print 'Message: %s' % recv.message

Client (Sender)

#!/usr/bin/python
# -*- coding: utf-8 -*-

import spread

PORT = '4803'

conn = spread.connect(PORT)
conn.join('test')

conn.multicast(spread.RELIABLE_MESS, 'test', 'hello, this is message sent from python')
conn.disconnect()

Racket

Server and client in the same piece of code, running a useless (fib 42) computation, four times, on four hosts (which all happen to be "localhost", but that can change, of course).

#lang racket/base
(require racket/place/distributed racket/place)

(define (fib n)
  (if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2)))))

(provide work)
(define (work)
  (place ch
    (place-channel-put ch (fib (place-channel-get ch)))))

(module+ main
  (define places
    (for/list ([host '("localhost" "localhost" "localhost" "localhost")]
               [port (in-naturals 12345)])
      (define-values [node place]
        (spawn-node-supervise-place-at host #:listen-port port #:thunk #t
                                       (quote-module-path "..") 'work))
      place))
  (message-router
   (after-seconds 1
     (for ([p places]) (*channel-put p 42))
     (printf "Results: ~s\n" (map *channel-get places))
     (exit))))

Raku

(formerly Perl 6)

Server listens for JSON encoded messages. It processes requests for set|get|dump. 'set' stores a message, 'get' returns message, 'dump' returns all stored messages. Optional parameters for ip address and port.

Server.raku:

./server.raku --usage
Usage:
  server.p6 [--server=<Any>] [--port=<Any>]
#!/usr/bin/env raku
use JSON::Fast ;
sub MAIN( :$server='0.0.0.0' , :$port=3333 ) {
  my %db ;
  react {
    whenever IO::Socket::Async.listen( $server , $port ) -> $conn {
        whenever $conn.Supply.lines -> $line {
            my %response = 'status' => '' ;
            my $msg = from-json $line ;
            say $msg.raku;
            given $msg{"function"} {
                when 'set' {
                    %db{ $msg<topic> } = $msg<message> ;
                    %response<status> = 'ok' ;
                }
                when 'get' {
                    %response<topic> = $msg<topic> ;
                    %response<message> = %db{ $msg<topic> } ;
                    %response<status> = 'ok' ;
                }
                when 'dump' {
                    %response = %db ;
                }
                when 'delete' {
                    %db{ $msg<topic> }:delete;
                    %response<status> = 'ok' ;
                }
            }
            $conn.print( to-json(%response, :!pretty) ~ "\n" ) ;
            LAST { $conn.close ; }
            QUIT { default { $conn.close ; say "oh no, $_";}}
            CATCH { default { say .^name, ': ', .Str ,  " handled in $?LINE";}}
        }
    }
  }
}

client.raku:

Usage:
  client.raku [--server=<Any>] [--port=<Any>] [--json=<Any>] set <topic> [<message>]
  client.raku [--server=<Any>] [--port=<Any>] get <topic>
  client.raku [--server=<Any>] [--port=<Any>] dump
#!/usr/bin/env raku
use JSON::Fast ;
multi MAIN('set', $topic,  $message='', :$server='localhost', :$port='3333', :$json='') {
    my %msg = function => 'set' , topic=> $topic , message=> $message ;
    %msg{"message"} = from-json( $json ) if $json ;
    sendmsg( %msg , $server, $port) ;
}
multi MAIN('get', $topic, :$server='localhost', :$port='3333') {
    my %msg = function => 'get' , topic=> $topic ;
    sendmsg( %msg , $server, $port) ;
}
multi MAIN('delete', $topic, :$server='localhost', :$port='3333') {
    my %msg = function => 'delete' , topic=> $topic ;
    sendmsg( %msg , $server, $port) ;
}
multi MAIN('dump', :$server='localhost', :$port='3333') {
    my %msg = function => 'dump'  ;
    sendmsg( %msg , $server, $port) ;
}
sub sendmsg( %msg , $server, $port){
    my $conn = await IO::Socket::Async.connect( $server , $port );
    $conn.print: to-json( %msg,:!pretty)~"\n";
    react {
        whenever $conn.Supply -> $data {
            print $data;
            $conn.close;
        }
    }
}

examples:

echo '{"function":"set","topic":"push","message":["perl5","raku","rakudo"]}' | nc localhost 3333

./client.raku set version raku
{"status": "ok"}
./client.raku get version
{"status": "ok","topic": "version","message": "raku"}
./client.raku --json='["one","two","three"]' set mylist
{"status": "ok"}
./client.raku dump
{"push": ["perl5","raku","rakudo"],"version": "raku","mylist": ["one","two","three"]}
./client.raku delete version
{"status": "ok"}

server output:
${:function("set"), :message($["perl5", "raku", "rakudo"]), :topic("push")}
${:function("set"), :message("raku"), :topic("version")}
${:function("get"), :topic("version")}
${:function("set"), :message($["one", "two", "three"]), :topic("mylist")}
${:function("dump")}
${:function("delete"), :topic("version")}

Ruby

Uses the distributed Ruby (dRuby) from the standard library. The "druby:" protocol uses TCP/IP sockets for communication.

Server

require 'drb/drb'

# The URI for the server to connect to
URI="druby://localhost:8787"

class TimeServer

  def get_current_time
    return Time.now
  end

end

# The object that handles requests on the server
FRONT_OBJECT = TimeServer.new

$SAFE = 1   # disable eval() and friends

DRb.start_service(URI, FRONT_OBJECT)
# Wait for the drb server thread to finish before exiting.
DRb.thread.join

Client

require 'drb/drb'

# The URI to connect to
SERVER_URI = "druby://localhost:8787"

# Start a local DRbServer to handle callbacks.
#
# Not necessary for this small example, but will be required
# as soon as we pass a non-marshallable object as an argument
# to a dRuby call.
DRb.start_service

timeserver = DRbObject.new_with_uri(SERVER_URI)
puts timeserver.get_current_time

Tcl

A rudimentary IRC Server

proc main {} {
    global connections
    set connections [dict create]
    socket -server handleConnection 12345
    vwait dummyVar ;# enter the event loop
}

proc handleConnection {channel clientaddr clientport} {
    global connections
    dict set connections $channel address "$clientaddr:$clientport"
    fconfigure $channel -buffering line
    fileevent $channel readable [list handleMessage $channel]
}

proc handleMessage {channel} {
    global connections
    if {[gets $channel line] == -1} {
        disconnect $channel
    } else {
        if {[string index [string trimleft $line] 0] eq "/"} {
            set words [lassign [split [string trim $line]] command]
            handleCommand $command $words $channel
        } else {
            echo $line $channel
        }
    }
}

proc disconnect {channel} {
    global connections
    dict unset connections $channel
    fileevent $channel readable ""
    close $channel
}

proc handleCommand {command words channel} {
    global connections
    switch -exact -- [string tolower $command] {
        /nick {
            dict set connections $channel nick [lindex $words 0]
        }
        /quit {
            echo bye $channel
            disconnect $channel
        }
        default {
            puts $channel "\"$command\" not implemented"
        }
    }
}

proc echo {message senderchannel} {
    global connections
    foreach channel [dict keys $connections] {
        if {$channel ne $senderchannel} {
            set time [clock format [clock seconds] -format "%T"]
            set nick [dict get $connections $channel nick]
            puts $channel [format "\[%s\] %s: %s" $time $nick $message]
        }
    }
}

main

Client

proc main {} {
    global argv argc
    if {$argc != 2} {
        error "usage: [info script] serveraddress serverport"
    }
    connect {*}$argv
    vwait dummyVar
}

proc connect {addr port} {
    global sock
    set sock [socket $addr $port]
    fconfigure $sock -buffering line
    fileevent $sock readable getFromServer
    fileevent stdin readable sendToServer
}

proc getFromServer {} {
    global sock
    if {[gets $sock line] == -1} {
        puts "disconnected..."
        exit
    } else {
        puts $line
    }
}

proc sendToServer {} {
    global sock
    set msg [string trim [gets stdin]]
    if {[string length $msg] > 0} {
        puts $sock $msg
    }
}

main

UnixPipes

Library: nc

Uses netcat and a buffer to cycle the server shell's stdout back to netcat's stdin.

Server

Security risk! Anything, able to reach 127.0.0.1 port 1234, can run shell commands as the user who runs the server. This allows other users to gain privileges.
: >/tmp/buffer
tail -f /tmp/buffer | nc -l 127.0.0.1 1234 | sh >/tmp/buffer 2>&1

Limitations:

  • The server can accept only one connection (but continues to run, not exit, after this connection dies).
  • With some systems, tail -f might be slow to notice changes to /tmp/buffer.

Client

nc 127.0.0.1 1234

Now you can enter commands in the client terminal and get the output back through the same connection.

Wren

Translation of: Go
Library: WrenGo
Library: Wren-fmt

As Wren has no networking support at present, we use embedded programs for both the server and client with a Go host using the net/rpc package in its standard library.

Moreover, as Wren's VM is not re-entrant, we need to run two VMs from the server side, one to call Go from Wren and the other to call Wren from Go.

Server:
We need two Wren scripts one for each VM:

/* distributed_programming_server.wren */

class Rpc {
    foreign static register()

    foreign static handleHTTP()
}

foreign class Listener {
    construct listen(network, address) {}
}

class HTTP {
    foreign static serve(listener)
}

Rpc.register()
Rpc.handleHTTP()
var listener = Listener.listen("tcp", ":1234")
HTTP.serve(listener)


/* distributed_programming_server2.wren */

class TaxComputer {
    static tax(amount, rate) {
        if (amount < 0) Fiber.abort("Negative values not allowed.")
        return amount * rate
    }
}


We now embed these scripts in the following Go program and run it on one terminal.

/* go run distributed_programming_server.go */

package main

import(
    wren "github.com/crazyinfin8/WrenGo"
    "log"
    "net"
    "net/http"
    "net/rpc"
)

type any = interface{}

type TaxComputer float64

var vm2 *wren.VM

var fileName  = "distributed_programming_server.wren"
var fileName2 = "distributed_programming_server2.wren"

func (taxRate TaxComputer) Tax(x float64, r *float64) error {
    wrenVar, _ := vm2.GetVariable(fileName2, "TaxComputer")
    wrenClass, _ := wrenVar.(*wren.Handle)
    defer wrenClass.Free()
    wrenMethod, _ := wrenClass.Func("tax(_,_)")
    defer wrenMethod.Free()
    ret, _ := wrenMethod.Call(x, float64(taxRate))
    *r = ret.(float64)
    return nil
}

func register(vm *wren.VM, parameters []any) (any, error) {
    c := TaxComputer(0.05) // 5% tax rate
    rpc.Register(c)
    return nil, nil
}

func handleHTTP(vm *wren.VM, parameters []any) (any, error) {
    rpc.HandleHTTP()
    return nil, nil
}

func serve(vm *wren.VM, parameters []any) (any, error) {
    handle := parameters[1].(*wren.ForeignHandle)
    ifc, _ := handle.Get()
    listener := ifc.(*net.Listener)
    http.Serve(*listener, nil)
    return nil, nil
}

func listen(vm *wren.VM, parameters []any) (any, error) {
    network := parameters[1].(string)
    address := parameters[2].(string)
    listener, err := net.Listen(network, address)
    if err != nil {
        log.Fatal(err)
    }
    return &listener, nil
}

func main() {
    vm := wren.NewVM()
    vm2 = wren.NewVM()
    vm2.InterpretFile(fileName2)

    rpcMethodMap := wren.MethodMap {
        "static register()": register,
        "static handleHTTP()": handleHTTP,
    }

    httpMethodMap := wren.MethodMap { "static serve(_)":serve }

    classMap := wren.ClassMap {
        "Listener": wren.NewClass(listen, nil, nil),
        "Rpc"     : wren.NewClass(nil, nil, rpcMethodMap),
        "HTTP"    : wren.NewClass(nil, nil, httpMethodMap),
    }

    module := wren.NewModule(classMap)
    vm.SetModule(fileName, module)
    vm.InterpretFile(fileName)
    vm.Free()
    vm2.Free()
}


Client:
Just one Wren script needed here:

/* distributed_programming_client.wren */

import "./fmt" for Fmt

foreign class Client {
    construct dialHTTP(network, address) {}

    foreign call(serviceMethod, arg)
}

var client = Client.dialHTTP("tcp", "localhost:1234")
var amounts = [3, 5.6]
for (amount in amounts) {
    var tax = client.call("TaxComputer.Tax", amount)
    Fmt.print("Tax on $0.2f = $0.2f", amount, tax)
}


which we embed in the following Go program and run it on a different terminal.

/* go run distributed_programming_client.go */

package main

import(
    wren "github.com/crazyinfin8/WrenGo"
    "log"
    "net/rpc"
    "strings"
)

type any = interface{}

func dialHTTP(vm *wren.VM, parameters []any) (any, error) {
    network := parameters[1].(string)
    address := parameters[2].(string)
    client, err := rpc.DialHTTP(network, address)
    if err != nil {
        log.Fatal(err)
    }
    return &client, nil
}

func call(vm *wren.VM, parameters []any) (any, error) {
    handle := parameters[0].(*wren.ForeignHandle)
    ifc, _ := handle.Get()
    client := ifc.(**rpc.Client)
    serviceMethod := parameters[1].(string)
    amount := parameters[2].(float64)
    var tax float64
    err := (*client).Call(serviceMethod, amount, &tax)
    if err != nil {
        log.Fatal(err)
    }
    return tax, nil
}

func moduleFn(vm *wren.VM, name string) (string, bool) {
    if name != "meta" && name != "random" && !strings.HasSuffix(name, ".wren") {
        name += ".wren"
    }
    return wren.DefaultModuleLoader(vm, name)
}

func main() {
    cfg := wren.NewConfig()
    cfg.LoadModuleFn = moduleFn
    vm := cfg.NewVM()
    fileName := "distributed_programming_client.wren"
    clientMethodMap := wren.MethodMap { "call(_,_)": call }
    classMap := wren.ClassMap { "Client": wren.NewClass(dialHTTP, nil, clientMethodMap) }
    module := wren.NewModule(classMap)
    vm.SetModule(fileName, module)
    vm.InterpretFile(fileName)
    vm.Free()
}
Output:

Output on the client terminal:

Tax on 3.00 = 0.15
Tax on 5.60 = 0.28