Distributed programming: Difference between revisions

m
({{omit from|PARI/GP}})
m (→‎{{header|Wren}}: Minor tidy)
 
(65 intermediate revisions by 37 users not shown)
Line 1:
{{task|Networking and Web Interaction}}
 
GivenWrite two computersprograms (or one program with two modes) which run on anetworked networkcomputers, 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 not be generic (not designed just for thisthe particular example application but be generic and), readily capable of handling the communicationindependent communications of many different components of ana 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]].
=={{header|AutoHotkey}}==
See [[Distributed program/AutoHotkey]].
 
=={{header|CAda}}==
{{works with|GNAT GPL|2010}}
{{incorrect|C|The protocol used is not sufficiently general-purpose.}}
{{works with|Win32PolyORB}} (Visual C/C++ 6.0)
 
Ada defines facilities for distributed systems in its standard (Annex E, also called DSA).
The changes needed to work with Linux/Unix should be small.
The example server serves only one client at a time. The protocol has 3 messages. The
first character determines the server action.
:'0' - echo string reversed '1' - echo string '2' - shutdown the server.
===Server===
<lang c>#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
//#include <sys/socket.h>
//#include <inet.h>
#include <string.h>
//#include <time.h>
#include <windows.h>
#pragma comment(lib, "wsock32.lib")
 
This example works with PolyORB and the GNAT GPL 2010 compiler from AdaCore.
typedef struct sockaddr_in * InetSockAddr;
 
server.ads:
typedef int (*Handler)( InetSockAddr client, int socket );
<syntaxhighlight lang="ada">package Server is
pragma Remote_Call_Interface;
procedure Foo;
function Bar return Natural;
end Server;</syntaxhighlight>
 
server.adb:
typedef struct sServer {
<syntaxhighlight lang="ada">package body Server is
Handler handler;
Count int running: Natural := 0;
int sock;
struct sockaddr_in addr;
} *Server;
 
procedure Foo is
Server NewServer( short port, Handler handler)
begin
{
int sock Count := Count + 1;
end Foo;
struct sockaddr_in svrAddr;
Server srv= malloc(sizeof(struct sServer));
if (!srv) return srv;
srv->handler = handler;
srv->running = 1;
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock <0 ) {
printf("Couldn't open socket. -failed %d \n", sock);
exit(1);
}
srv->sock = sock;
 
function Bar return Natural is
memset(&svrAddr, 0, sizeof(struct sockaddr_in));
begin
svrAddr.sin_family = AF_INET;
return Count;
svrAddr.sin_addr.s_addr = htonl(INADDR_ANY); //any incoming addr ok
end Bar;
svrAddr.sin_port = htons(port);
end Server;</syntaxhighlight>
srv->addr = svrAddr;
 
client.adb:
if (bind(sock, (struct sockaddr *)&svrAddr, sizeof(svrAddr)) <0) {
<syntaxhighlight lang="ada">with Server;
printf("Bind to port %d failed\n", port);
with Ada.Text_IO;
exit(1);
}
return srv;
}
 
procedure Client is
#define MAXPENDING SOMAXCONN
begin
#define close(sock) closesocket(sock)
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):
int ServerServe( Server svr)
<syntaxhighlight lang="ada">configuration DSA is
{
pragma Starter (None);
struct sockaddr_in cli_addr;
int clen = sizeof(cli_addr);
if (listen(svr->sock, MAXPENDING) < 0) {
printf("listen() call failed.\n");
return -1;
}
while (svr->running) {
int sock = accept(svr->sock, (struct sockaddr *) &cli_addr, &clen);
if (sock < 0) {
printf("accept call failed in ServerServ.\n");
svr->running = 0;
}
else
svr->running = (*(svr->handler))( &cli_addr, sock );
}
}
 
-- Server
#define ServerDelete( svr ) \
Server_Partition : Partition := (Server);
{ if(svr->sock>0) close(svr->sock); \
procedure Run_Server is in Server_Partition;
free(svr); svr = NULL; }
 
-- Client
#define BUFR_SIZE 256
Client_Partition : Partition;
/* - return 0 on success, nonzero on done; */
for Client_Partition'Termination use Local_Termination;
int SimpleHandler( InetSockAddr cli_addr, int cli_sock )
procedure Client;
{
for Client_Partition'Main use Client;
char msgBufr[BUFR_SIZE];
end DSA;</syntaxhighlight>
int msgSize;
int rplySize;
const char *rplyMsg;
int mcode;
 
compilation:
do {
<pre>$po_gnatdist dsa.cfg
msgSize = recv(cli_sock, msgBufr, sizeof(msgBufr), 0) ;
[...]
if (msgSize < 0) {
------------------------------
printf("done receiving\n");
---- Configuration report ----
return 1;
------------------------------
}
Configuration :
mcode = msgBufr[0];
Name switch(mcode) { : dsa
Main default: run_server
Starter case '0': {none
char *p1 = msgBufr+1;
char *p2 = msgBufr+msgSize-2;
while (p2>p1) {
*p1 = *p1 + *p2; *p2 = *p1 - *p2; *p1 = *p1 - *p2;
p1++; p2--;
}
rplyMsg = msgBufr;
}
break;
case '1':
rplyMsg = msgBufr;
break;
case '2':
rplyMsg = "Server Quitting";
// server should quit
break;
}
rplySize = strlen(rplyMsg)+1;
if (rplySize > 0) {
int bytesSent = send(cli_sock, rplyMsg, rplySize, 0);
if (bytesSent < rplySize) {
printf("Not All bytes sent back from msg.");
msgSize = 0;
}
}
} while ((msgSize > 0) && (mcode !=2));
return (mcode == 2); // true if server should quit
}
 
Partition server_partition
int main( int argc, char *argv[])
Main : run_server
{
Units short port; :
Server - server; (rci)
- run_server (normal)
WORD sockVrsn;
- polyorb.dsa_p.partitions (rci, from PCS)
WSADATA wsaData;
 
Environment variables :
sockVrsn = MAKEWORD(1,1);
- "POLYORB_DSA_NAME_SERVICE"
 
Partition client_partition
if (argc < 2) {
Main : client
printf("Usage %s <port number>\n",argv[0]);
Termination : local
exit(1);
Units } :
- client (normal)
WSAStartup(sockVrsn, &wsaData);
port = (short)atoi(argv[1]);
server = NewServer( port, &SimpleHandler);
if (server){
ServerServe(server);
ServerDelete(server);
}
return 0;
}</lang>
===Client===
<lang c>#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
//#include <sys/socket.h>
//#include <inet.h>
#include <string.h>
//#include <time.h>
#include <windows.h>
#pragma comment(lib, "wsock32.lib")
 
Environment variables :
typedef struct sockaddr_in * InetSockAddr;
- "POLYORB_DSA_NAME_SERVICE"
 
-------------------------------
typedef struct sClient {
[...]</pre>
int sock;
struct sockaddr_in addr;
} *Client;
 
preparation (run PolyORB name service):
Client NewClient( const char *ipAddr, short port )
<pre>$ po_ioc_naming
{
POLYORB_CORBA_NAME_SERVICE=IOR:010000002b00000049444[...]
int sock;
POLYORB_CORBA_NAME_SERVICE=corbaloc:iiop:1.2@10.200.[...]</pre>
struct sockaddr_in svrAddr;
Client clint= malloc(sizeof(struct sClient));
if (!clint) return clint;
 
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.
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock <0 ) {
printf("Couldn't open socket. -failed %d \n", sock);
exit(1);
}
clint->sock = sock;
 
running server:
memset(&svrAddr, 0, sizeof(struct sockaddr_in));
<pre>$ ./server_partition</pre>
svrAddr.sin_family = AF_INET;
svrAddr.sin_addr.s_addr = inet_addr(ipAddr);
printf("IP addr: %x", inet_addr(ipAddr));
svrAddr.sin_port = htons(port);
clint->addr = svrAddr;
 
running client:
if (connect(sock, (struct sockaddr *)&svrAddr, sizeof(svrAddr)) <0) {
<pre>$ ./client_partition
perror("connect failed");
Calling Foo...
printf("Connect to Server %s:%d failed\n", ipAddr,port);
Calling Bar: 1
exit(1);
$ ./client_partition
}
Calling Foo...
return clint;
Calling Bar: 2</pre>
}
 
=={{header|AutoHotkey}}==
#define close(sock) closesocket(sock)
See [[Distributed program/AutoHotkey]].
 
=={{header|C}}==
#define BUFR_SIZE 128
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 ClientDoProcsmain(int Client clintc, const char *mlist[]*v)
{
int tids[10];
char rcvBufr[BUFR_SIZE];
int parent, spawn;
const char **msg;
int i_data, i2;
int v;
double f_data;
 
if (c > 1) {
for (msg = mlist; *msg; msg++) {
spawn = pvm_spawn("/tmp/a.out", 0, PvmTaskDefault, 0, 1, tids);
int mlen = strlen(*msg)+1;
if (spawn <= 0) {
printf("Send: %s\n", *msg);
printf("Can't spawn task\n");
v = send(clint->sock, *msg, mlen, 0);
return 1;
if (v != mlen ) {
}
printf("MessageSend error: %d %d\n", v,mlen);
}
else {
int bytesRcvd = 0;
bytesRcvd = recv( clint->sock, rcvBufr, BUFR_SIZE-1, 0);
if (bytesRcvd < 0) {
printf("Error Rcvg Bytes\n");
break;
}
printf("Recvd: %s\n", rcvBufr);
}
}
return 0;
}
 
printf("Spawning successful\n");
#define ClientDelete( cli ) \
{ if(cli->sock>0) close(cli->sock); \
free(cli); cli = NULL; }
 
/* pvm_recv(task_id, msgtag). msgtag identifies what kind of data it is,
const char *msglist[] = {
* for here: 1 = (int, double), 2 = (int, int)
"0Hello World!!!",
* The receiving order is intentionally swapped, just to show.
"1Hello Teacher!",
* task_id = -1 means "receive from any task"
"1This should echo back same",
*/
"0This should echo back reversed",
pvm_recv(-1, 2);
"2 ByeBye",
pvm_unpackf("%d %d", &i_data, &i2);
NULL };
printf("got msg type 2: %d %d\n", i_data, i2);
 
pvm_recv(-1, 1);
int main( int argc, char *argv[])
pvm_unpackf("%d %lf", &i_data, &f_data);
{
printf("got msg type 1: %d %f\n", i_data, f_data);
short port;
} else {
Client clint;
parent = pvm_parent();
WORD sockVrsn;
WSADATA wsaData;
 
pvm_initsend(PvmDataDefault);
sockVrsn = MAKEWORD(1,1);
i_data = rand();
WSAStartup(sockVrsn, &wsaData);
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);
if (argc < 3) {
i2 = rand();
printf("Usage %s <serverIP> <port number>\n",argv[0]);
pvm_packf("%d %d", i_data, i2);
exit(1);
pvm_send(parent, 2); /* send msg type 2 */
}
}
 
pvm_exit();
port = (short)atoi(argv[2]);
return 0;
// argv[1]="127.0.0.1";
}</syntaxhighlight>{{out}}(running it on PVM console, exe is /tmp/a.out)<syntaxhighlight lang="text">pvm> spawn -> /tmp/a.out 1
clint = NewClient( argv[1], port );
spawn -> /tmp/a.out 1
if (clint) {
[2]
ClientDoProcs(clint, msglist);
1 successful
ClientDelete(clint);
t40028
}
pvm> [2:t40029] EOF
Sleep(10);
[2:t40028] Spawning successful
return 0;
[2:t40028] got msg type 2: 1804289383 1681692777
}</lang>
[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.
{{incorrect|C sharp|The protocol used is not sufficiently general-purpose.}}
The example server can handle one client at any one time. It will read what the client writes, and respond with "Hello World!". The client will write "Hello World!" and read the response from the server.
 
<syntaxhighlight lang="csharp">
===Server===
using System;
<lang csharp>
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 Program
 
class DistributedProgramming
{
const int Port = 555;
static void Main(string[] args)
{
TcpListener server = new TcpListener(8000);
server.Start();
 
async static Task RunClient()
Console.WriteLine("Listening, port 8000");
{
WriteLine("Connecting");
var client = new TcpClient();
await client.ConnectAsync("localhost", Port);
 
using (var stream = client.GetStream())
TcpClient client;
{
do
WriteLine("Sending loot");
{
var data = Serialize(new SampleData());
// Accept client
await stream.WriteAsync(data, 0, data.Length);
client = server.AcceptTcpClient();
Console.WriteLine("Recieved client: " + client.Client.AddressFamily.ToString());
 
WriteLine("Receiving thanks");
// Recieve
var buffer = new byte[80000];
string tRecieve = "";
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
char t;
var thanks = (string)Deserialize(buffer, bytesRead);
do
WriteLine(thanks);
{
}
if (client.Available > 0)
{
t = (char)client.GetStream().ReadByte();
 
client.Close();
if (t == 0)
}
break;
 
async static Task RunServer()
tRecieve += t;
{
}
WriteLine("Listening");
} while (true);
var listener = new TcpListener(IPAddress.Any, Port);
listener.Start();
var client = await listener.AcceptTcpClientAsync();
 
using (var stream = client.GetStream())
Console.WriteLine("Recieved: " + tRecieve);
{
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");
// Send
var thanks = Serialize("Thanks!");
byte[] tSend = Encoding.ASCII.GetBytes("Hello World!");
client.GetStream() await stream.WriteWriteAsync(tSendthanks, 0, tSendthanks.Length);
}
client.GetStream().WriteByte(0);
 
client.Close();
Console.WriteLine("Sent: " + Encoding.ASCII.GetString(tSend));
listener.Stop();
Write("Press a key");
ReadKey();
}
 
static byte[] Serialize(object data)
// Close
{
client.Close();
using (var mem = new MemoryStream())
} while (true);
{
new BinaryFormatter().Serialize(mem, data);
return mem.ToArray();
}
}
 
static object Deserialize(byte[] data, int length)
}
{
}
using (var mem = new MemoryStream(data, 0, length))
</lang>
{
return new BinaryFormatter().Deserialize(mem);
}
}
 
static void Main(string[] args)
===Client===
{
<lang csharp>
if (args.Length == 0) return;
using System.Net.Sockets;
 
switch (args[0])
{
case "client": RunClient().Wait(); break;
case "server": RunServer().Wait(); break;
}
}
}
 
[Serializable]
class Program
class SampleData
{
public decimal Latitude = 44.33190m;
static void Main(string[] args)
public decimal Longitude = 114.84129m;
{
public string Loot = "140 tonnes of jade";
TcpClient client;
}
</syntaxhighlight>
 
=={{header|D}}==
// Connect
Uses the <b>rpc</b> library:
do
https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff/blob/master/rpc.d
{
client = new TcpClient();
client.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 8000));
 
This library is not standard, so this code (by Adam D. Ruppe) could and should be rewritten using more standard means.
Console.WriteLine("Connected");
<syntaxhighlight lang="d">import arsd.rpc;
 
struct S1 {
// Send
int number;
byte[] tSend = Encoding.ASCII.GetBytes("Hello World!");
string name;
client.GetStream().Write(tSend, 0, tSend.Length);
}
client.GetStream().WriteByte(0);
 
struct S2 {
Console.WriteLine("Sent: " + Encoding.ASCII.GetString(tSend));
string name;
int number;
}
 
interface ExampleNetworkFunctions {
// Read
string sayHello(string name);
string tRecieve = "";
int add(in int a, in int b) const pure nothrow;
char t;
S2 structTest(S1);
do
void die();
{
}
if (client.Available > 0)
{
t = (char)client.GetStream().ReadByte();
 
// The server must implement the interface.
if (t == 0)
class ExampleServer : ExampleNetworkFunctions {
break;
override string sayHello(string name) {
return "Hello, " ~ name;
}
 
override int add(in int a, in int b) const pure nothrow {
tRecieve += t;
return a + b;
}
}
} while (true);
 
override S2 structTest(S1 a) {
Console.WriteLine("Recieved: " + tRecieve);
return S2(a.name, a.number);
}
 
override void die() {
client.Close();
throw new Exception("death requested");
}
 
mixin NetworkServer!ExampleNetworkFunctions;
Console.Read();
} while (true);
}
}
</lang>
 
class Client {
=={{header|D}}==
mixin NetworkClient!ExampleNetworkFunctions;
{{incorrect|D|The protocol used is not sufficiently general-purpose.}}
}
 
void main(in string[] args) {
{{works with|Tango}}
import std.stdio;
=== Server ===
<lang D>module distributedserver ;
import tango.net.ServerSocket, tango.text.convert.Integer,
tango.text.Util, tango.io.Stdout ;
 
void main() {
auto Ip = new InternetAddress("localhost", 12345) ;
auto server = new ServerSocket(Ip) ;
auto socket = server.accept ;
auto buffer = new char[socket.bufferSize] ;
 
if (args.length > 1) {
bool quit = false ;
auto client = new Client("localhost", 5005);
// These work like the interface above, but instead of
while(!quit) {
// returning the value, they take callbacks for success (where
bool error = false ;
// the arg is the retval) and failure (the arg is the
// exception).
try {
client.sayHello("whoa", (a) { writeln(a); }, null);
auto len = socket.input.read(buffer) ;
client.add(1,2, (a){ writeln(a); }, null);
auto cmd = (len > 0) ? delimit(buffer[0..len], " ") : [""] ;
client.add(10,20, (a){ writeln(a); }, null);
Stdout(cmd).newline.flush ;
client.structTest(S1(20, "cool!"),
switch (cmd[0]) {
(a){ writeln(a.name, " -- ", a.number); },
case "square":
null);
socket.output.write(toString(toInt(cmd[1]) * toInt(cmd[1]))) ; break ;
client.die(delegate(){ writeln("shouldn't happen"); },
case"add":
delegate(a){ writeln(a); });
socket.output.write(toString(toInt(cmd[1]) + toInt(cmd[2]))) ; break ;
case "quit": client.eventLoop;
} else {
socket.output.write("Server Shut down") ;
auto quitserver = true ; breaknew ExampleServer(5005);
default: error = true server.eventLoop;
}
}</syntaxhighlight>
} catch (Exception e)
error = true ;
if(error) socket.output.write("<Error>") ;
if(socket) socket.close ;
if(!quit) socket = server.accept ;
}
 
if(socket) socket.close ;
}</lang>
=== Client ===
<lang D>module distributedclient ;
import tango.net.SocketConduit, tango.net.InternetAddress,
tango.text.Util, tango.io.Stdout ;
 
void main(char[][] args) {
 
if(args.length> 1) {
try {
auto Ip = new InternetAddress("localhost", 12345) ;
auto socket = new SocketConduit ;
socket.connect(Ip) ;
auto buffer = new char[socket.bufferSize] ;
socket.output.write(join(args[1..$]," ")) ;
auto len = socket.input.read(buffer) ;
if(len > 0) Stdout(buffer[0..len]).newline ;
if(socket) socket.close ;
} catch(Exception e)
Stdout(e.msg).newline ;
} else
Stdout("usage: supply argument as,\n\tquit\n"
"\tsquare <number>\n\tadd <number> <number>").newline ;
}</lang>
 
=={{header|E}}==
Line 464 ⟶ 366:
(The protocol is symmetric; this program is the server only in that it is the one which is started first and exports an object.)
 
<langsyntaxhighlight Elang="e">def storage := [].diverge()
 
def logService {
Line 482 ⟶ 384:
def sturdyRef := makeSturdyRef.temp(logService)
println(<captp>.sturdyToURI(sturdyRef))
interp.blockAtTop()</langsyntaxhighlight>
 
This will print the URL of the service and run it until aborted.
Line 490 ⟶ 392:
The URL provided by the server is given as the argument to this program.
 
<langsyntaxhighlight Elang="e">def [uri] := interp.getArgs()
introducer.onTheAir()
def sturdyRef := <captp>.sturdyFromURI(uri)
Line 503 ⟶ 405:
println(`At $time: $line`)
}
}</langsyntaxhighlight>
 
=={{header|Erlang}}==
Line 510 ⟶ 412:
srv.erl
 
<langsyntaxhighlight lang="erlang">-module(srv).
-export([start/0, wait/0]).
 
Line 528 ⟶ 430:
wait();
Any -> io:fwrite("Error ~p~n", [Any])
end.</langsyntaxhighlight>
 
=== Client ===
client.erl
 
<langsyntaxhighlight lang="erlang">-module(client).
-export([start/0, wait/0]).
 
Line 540 ⟶ 442:
erlang:set_cookie(node(), rosetta),
{ok,[[Srv]]} = init:get_argument(server),
io:fwrite("conenctingconnecting to ~p~n", [Srv]),
{srv, list_to_atom(Srv)} ! {echo,self(), hi},
wait(),
Line 549 ⟶ 451:
{hello, Any} -> io:fwrite("Received ~p~n", [Any]);
Any -> io:fwrite("Error ~p~n", [Any])
end.</langsyntaxhighlight>
 
running it (*comes later)
Line 559 ⟶ 461:
|erlc client.erl
|erl -run client start -run init stop -noshell -server srv@agneyam
conenctingconnecting 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}}==
===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:'''
<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 (
"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)
}</syntaxhighlight>
{{out | Client output}}
<pre>
Tax on 3.00: 0.15
</pre>
===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:'''
<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 (
"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)
}</syntaxhighlight>
'''Client:'''
<syntaxhighlight lang="go">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")
}</syntaxhighlight>
{{out | Client output}}
<pre>
Tax on 300 cents is 15 cents
</pre>
 
===Apache Thrift===
See https://thrift.apache.org/
 
'''.thrift'''
 
Like gRPC, Thrift requires a language independent interface definition file:
<syntaxhighlight lang="thrift">service TaxService {
i32 tax(1: i32 amt)
}</syntaxhighlight>
'''Server:'''
<syntaxhighlight lang="go">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)
}
}</syntaxhighlight>
'''Client:'''
<syntaxhighlight lang="go">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()
}</syntaxhighlight>
{{out | Client output}}
<pre>
tax on 300 is 15
</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}}==
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:
<syntaxhighlight lang="julia"># 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</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
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
</syntaxhighlight> {{output}} <pre>
100001564
</pre>
 
=={{header|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
 
<syntaxhighlight lang="bash">
$ ./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)
>
</syntaxhighlight>
 
And then enter the following code
 
<syntaxhighlight lang="lisp">
> (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)))))
</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}}==
{{libheader|nanomsg}}
<syntaxhighlight lang="nim">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)</syntaxhighlight>
Usage:
<pre>./pair node0 tcp://127.0.0.1:25000
./pair node1 tcp://127.0.0.1:25000</pre>
 
=={{header|Objective-C}}==
Line 571 ⟶ 945:
 
<tt>ActionObjectProtocol.h</tt>
<langsyntaxhighlight lang="objc">#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</langsyntaxhighlight>
 
<tt>ActionObject.h</tt>
<langsyntaxhighlight lang="objc">#import <Foundation/Foundation.h>
#import "ActionObjectProtocol.h"
 
@interface ActionObject : NSObject <ActionObjectProtocol>
// we do not have much for this example!
@end</langsyntaxhighlight>
 
<tt>ActionObject.m</tt>
<langsyntaxhighlight lang="objc">#import <Foundation/Foundation.h>
#import "ActionObject.h"
 
Line 596 ⟶ 970:
return @"server answers ...";
}
@end</langsyntaxhighlight>
 
<tt>server.m</tt>
<langsyntaxhighlight lang="objc">#import <Foundation/Foundation.h>
#import "ActionObject.h"
 
int main (void)
{
@autoreleasepool {
NSAutoreleasePool *pool;
ActionObject *action;
NSConnection *connect;
NSSocketPort *port;
pool ActionObject *action = [[NSAutoreleasePoolActionObject alloc] init];
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] ] == NO)
{
NSLog(@"can't register the server DistributedAction");
exit(EXIT_FAILURE);
}
NSLog(@"waiting for messages...");
 
[[NSRunLoop currentRunLoop] run];
 
}
[pool release];
return 0;
}</langsyntaxhighlight>
 
===Client===
<tt>client.m</tt>
<langsyntaxhighlight lang="objc">#import <Foundation/Foundation.h>
#import "ActionObjectProtocol.h"
 
int main(void)
{
@autoreleasepool {
NSAutoreleasePool *pool;
NSArray *args;
id <ActionObjectProtocol> action;
NSString *msg, *backmsg;
 
id <ActionObjectProtocol> action = (id <ActionObjectProtocol>)
pool = [[NSAutoreleasePool alloc] init];
[NSConnection
rootProxyForConnectionWithRegisteredName: @"DistributedAction"
host: @"localhost"
usingNameServer: [NSSocketPortNameServer sharedInstance] ];
 
if (action == nil)
action = (id <ActionObjectProtocol>)
[NSConnection{
NSLog(@"can't connect to the server");
rootProxyForConnectionWithRegisteredName: @"DistributedAction"
host: @"localhost"exit(EXIT_FAILURE);
}
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 objectAtIndex: [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);
 
}
[pool release];
return 0;
}</langsyntaxhighlight>
 
=={{header|OCaml}}==
Line 692 ⟶ 1,056:
 
=== Server ===
<langsyntaxhighlight lang="ocaml">open Printf
let create_logger () =
Line 714 ⟶ 1,078:
register "search" search;
Join.Site.listen (Unix.ADDR_INET (Join.Site.get_local_addr(), 12345));
wait ()</langsyntaxhighlight>
 
=== Client ===
 
<langsyntaxhighlight lang="ocaml">open Printf
let ns_there = Join.Ns.there (Unix.ADDR_INET (Join.Site.get_local_addr(), 12345))
Line 738 ⟶ 1,102:
log "foo";
log "shoe";
find "foo"</langsyntaxhighlight>
 
=={{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.
 
<langsyntaxhighlight lang="oz">declare
functor ServerCode
export
Line 782 ⟶ 1,146:
 
%% shut down server
{RM close}</langsyntaxhighlight>
 
=={{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.
<syntaxhighlight lang="perl">use strict;
use warnings;
use Data::Dumper;
use IO::Socket::INET;
use Safe;
 
sub get_data {
my $sock = IO::Socket::INET->new(
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 = Safe->new;
my $x = $safe->reval(join("", <$cli>));
close $cli;
close $sock;
return $x;
}
 
sub send_data {
my $host = shift;
my $data = shift;
my $sock = IO::Socket::INET->new(
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}}==
From/using [http://phix.x10.mx/pmwiki/pmwiki.php?n=Main.Libzmq 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.
<!--<syntaxhighlight lang="phix">(notonline)-->
<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;">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;">--// subscriber tells us when it's ready here</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: #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: #000080;font-style:italic;">--// send update via this socket</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: #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: #000080;font-style:italic;">--// broadcast 10 updates, with pause</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: #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: #7060A8;">sleep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</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: #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>
<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;">publisher</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>-->
 
<!--<syntaxhighlight lang="phix">(notonline)-->
<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===
<langsyntaxhighlight PicoLisplang="picolisp">(task (port 12321) # Background server task
(let? Sock (accept @)
(unless (fork) # Handle request in child process
Line 794 ⟶ 1,274:
(pr (eval @)) ) ) ) # Evaluate and send reply
(bye) ) # Exit child process
(close Sock) ) ) # Close socket in parent process</langsyntaxhighlight>
===Client===
<langsyntaxhighlight PicoLisplang="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</langsyntaxhighlight>
Output:
<pre>PID 18372
Line 813 ⟶ 1,293:
 
==== Server ====
<langsyntaxhighlight lang="python">#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
Line 850 ⟶ 1,330:
except KeyboardInterrupt:
print 'Exiting...'
server.server_close()</langsyntaxhighlight>
 
==== Client ====
<langsyntaxhighlight lang="python">#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
Line 875 ⟶ 1,355:
# control if foo_function returns True
if rpc.foo_function():
print 'Server says: foo_function returned True'</langsyntaxhighlight>
 
===HTTP===
Line 881 ⟶ 1,361:
 
==== Server ====
<langsyntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-
 
Line 910 ⟶ 1,390:
except KeyboardInterrupt:
print 'Exiting...'
server.server_close()</langsyntaxhighlight>
 
==== Client ====
<langsyntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-
 
Line 927 ⟶ 1,407:
print 'Server Status: %d' % response.status
 
print 'Server Message: %s' % response.read()</langsyntaxhighlight>
 
===Socket, PlainPickle Textformat===
 
{{incorrect|Python|The protocol used is not sufficiently general-purpose.}}
'''Protocol:''' Plainraw Textsocket / 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 ====
<langsyntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import SocketServer
import pickle
 
HOST = "localhost"
PORT = 8000
 
class RPCServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
# our instance that will upper whatever it gets and send back to client
# The object_to_proxy member should be set to the object we want
class UpperCaseHandler(SocketServer.StreamRequestHandler):
# 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)
print '%s connected' % self.client_address[0]
out_channel = pickle.Pickler(self.wfile, protocol=2)
# get what client sends
getwhile = self.rfile.readline()True:
# write back to clienttry:
name, args, kwargs = in_channel.load()
self.wfile.write(get.upper())
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__':
tcpserverrpcserver = SocketServer.TCPServerRPCServer((HOST, PORT), UpperCaseHandlerRPCHandler)
rpcserver.object_to_proxy = MyHandlerInstance()
try:
tcpserverrpcserver.serve_forever()
except KeyboardInterrupt:
print 'Exiting...'
tcpserverrpcserver.server_close()</lang>
</syntaxhighlight>
 
==== Client ====
<langsyntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import socket
import pickle
 
HOST = "localhost"
PORT = 8000
 
class RPCClient(object):
DATA = "my name is eren"
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):
# connect to server and send data
self.socket.close()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.rfile.close()
sock.connect((HOST, PORT))
self.wfile.close()
sock.send("%s\n" % DATA)
 
# Make calling remote methods easy by overriding attribute access.
# get
# Accessing any attribute on our instances will give a proxy method that
response = sock.recv(256)
# calls the method with the same name on the remote machine.
sock.close()
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 "We sent: %s" % DATA
print rpcclient.echo('Hello world!')
print 'Server responded: %s' % response</lang>
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===
Line 986 ⟶ 1,536:
 
==== Server ====
<langsyntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-
 
Line 1,011 ⟶ 1,561:
except KeyboardInterrupt:
print 'Exiting...'
server.shutdown()</langsyntaxhighlight>
 
==== Client ====
<langsyntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-
 
Line 1,030 ⟶ 1,580:
 
print 'We sent two numbers to divide: %d and %d' % (NUM1, NUM2)
print 'Server responded the result: %s' % math.div(NUM1, NUM2)</langsyntaxhighlight>
 
=== Spread ===
Line 1,041 ⟶ 1,591:
 
==== Client (Listener) ====
<langsyntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-
 
Line 1,058 ⟶ 1,608:
if hasattr(recv, 'sender') and hasattr(recv, 'message'):
print 'Sender: %s' % recv.sender
print 'Message: %s' % recv.message</langsyntaxhighlight>
 
==== Client (Sender) ====
<langsyntaxhighlight lang="python">#!/usr/bin/python
# -*- coding: utf-8 -*-
 
Line 1,072 ⟶ 1,622:
 
conn.multicast(spread.RELIABLE_MESS, 'test', 'hello, this is message sent from python')
conn.disconnect()</langsyntaxhighlight>
 
=={{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}}==
(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:
<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
{"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")}</pre>
 
=={{header|Ruby}}==
Uses the distributed Ruby (dRuby) from the standard library. The "druby:" protocol uses TCP/IP sockets for communication.
Uses {{libheader|dRuby}}
The "druby:" protocol uses TCP/IP sockets for communication.
 
'''Server'''
<langsyntaxhighlight lang="ruby">require 'drb/drb'
 
# The URI for the server to connect to
Line 1,099 ⟶ 1,779:
DRb.start_service(URI, FRONT_OBJECT)
# Wait for the drb server thread to finish before exiting.
DRb.thread.join</langsyntaxhighlight>
 
'''Client'''
<langsyntaxhighlight lang="ruby">require 'drb/drb'
 
# The URI to connect to
Line 1,115 ⟶ 1,795:
 
timeserver = DRbObject.new_with_uri(SERVER_URI)
puts timeserver.get_current_time</langsyntaxhighlight>
 
=={{header|Tcl}}==
A rudimentary IRC Server
<langsyntaxhighlight lang="tcl">proc main {} {
global connections
set connections [dict create]
Line 1,181 ⟶ 1,861:
}
 
main</langsyntaxhighlight>
Client
<langsyntaxhighlight lang="tcl">proc main {} {
global argv argc
if {$argc != 2} {
Line 1,218 ⟶ 1,898:
}
 
main</langsyntaxhighlight>
 
=={{header|UnixPipes}}==
{{libheader|nc}}
{{incorrect|UnixPipes|The protocol used is not sufficiently general-purpose.}}
Uses netcat and a buffer to cycle the server shell's stdout back to netcat's stdin.
Uses netcat
 
===Server===
{{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.}}
 
<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}}==
{{trans|Go}}
{{libheader|WrenGo}}
{{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.
 
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:'''
<br>
We need two Wren scripts one for each VM:
<syntaxhighlight lang="wren">/* 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)</syntaxhighlight>
<br>
<syntaxhighlight lang="wren">/* Distributed_programming_server_2.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_server_2.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()
}</syntaxhighlight>
<br>
'''Client:'''
<br>
Just one Wren script needed here:
<syntaxhighlight lang="wren">/* 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)
}</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() {
server
cfg := wren.NewConfig()
<lang bash>(echo 1; echo 2; echo 3) | nc -l 1024</lang>
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}}
client
Output on the client terminal:
<lang bash>nc 192.168.0.1 1024 | wc -l</lang>
<pre>
Tax on 3.00 = 0.15
Tax on 5.60 = 0.28
</pre>
 
{{omit from|Lotus 123 Macro Scripting}}
{{omit from|Maxima}}
{{omit from|PARI/GP}}
{{omit from|Retro}}
9,482

edits