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
Compiler: 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
XML-RPC
Version: 2.4 and 2.6, code will work on both
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
Version: 2.4 and 2.6, code will work on both
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
Version: 2.4 and 2.6, code will work on both
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
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.
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)