Distributed programming: Difference between revisions

From Rosetta Code
Content added Content deleted
(add Spread)
m (Changed over to works with template)
Line 54: Line 54:


={{header|OCaml}}=
={{header|OCaml}}=
'''Compiler:''' JoCaml
{{works with|JoCaml}}
Minimalistic distributed logger with synchronous channels using the join calculus on top of OCaml.
Minimalistic distributed logger with synchronous channels using the join calculus on top of OCaml.


Line 107: Line 107:


={{header|Python}}=
={{header|Python}}=
{{works with|Python|2.4 and 2.6}}
==XML-RPC==
==XML-RPC==
'''Version:''' 2.4 and 2.6, code will work on both

'''Protocol:''' XML-RPC
'''Protocol:''' XML-RPC


Line 183: Line 182:


==HTTP==
==HTTP==
'''Version:''' 2.4 and 2.6, code will work on both

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


Line 241: Line 238:


==Socket, Plain Text==
==Socket, Plain Text==
'''Version:''' 2.4 and 2.6, code will work on both

'''Protocol:''' Plain Text
'''Protocol:''' Plain Text


Line 300: Line 295:


==Pyro==
==Pyro==
'''Version:''' 2.4 and 2.6, code will work on both

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


Line 356: Line 349:


== Spread ==
== Spread ==
'''Version:''' 2.4 and 2.6, code will work on both

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



Revision as of 14:13, 20 February 2008

Task
Distributed programming
You are encouraged to solve this task according to the task description, using any language you may know.

Given two computers on a network, send messages between them. The protocol used may be language-specific or not, and should be suitable for general distributed programming.

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`)
  }
}

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"

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, Plain Text

Protocol: Plain Text

Server

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

import SocketServer

HOST = "localhost"
PORT = 8000

# our instance that will upper whatever it gets and send back to client
class UpperCaseHandler(SocketServer.StreamRequestHandler):
    def handle(self):
        print '%s connected' % self.client_address[0]
        # get what client sends
        get = self.rfile.readline()
        # write back to client
        self.wfile.write(get.upper())

if __name__ == '__main__':
    tcpserver = SocketServer.TCPServer((HOST, PORT), UpperCaseHandler)
    try:
        tcpserver.serve_forever()
    except KeyboardInterrupt:
        print 'Exiting...'
        tcpserver.server_close()

Client

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

import socket

HOST = "localhost"
PORT = 8000

DATA = "my name is eren"

# connect to server and send data
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
sock.send("%s\n" % DATA)

# get
response = sock.recv(256)
sock.close()

print "We sent: %s" % DATA
print 'Server responded: %s' % response


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()