Class Models for Lua

# Socket Stream

## `loop.serial.SocketStream`

Subclass of `Serializer` that serializes values into a socket object like the ones provided by the LuaSocket library. It is also used to restore values serialized using the serialization mechanism provided by `Serializer` that are transmitted by a socket. This class is useful to implement communication infrastructures.

Instances of this class implement the `write` method required by `Serializer` in such way that the pieces of the serialized code are concatenated and sent directly through a socket.

## Behavior

### Fields

`socket` [required]
  Socket object where the serialied code shall be written. This socket is also used to receive the serialized code used to restore values. In this case, the transfered code may contain sequences of serialized values separated by a null character followed by a newline character (i.e. `"\0\n"`).

### Methods

`put(...)`
  Serializes the arguments and writes the results in the socket defined by field `socket`. The sequences of values serialized by this function are terminated by a null character followed by a newline character (i.e. `"\0\n"`).
`get()`
  Each time this method is called, it reads all the data until a null character followed by a newline character (i.e. `"\0\n"`) and then use this code to restore values. Therefore, each call of this method restores one of the set of values serialized and sent to the socket defined by field `socket`, in the same order they were originally serialized. All the set of values received through the socket defined by field `socket` must be separated by a null character followed by a newline character (i.e. `"\0\n"`).

## Remarks

- Methods `serialize` and `load` of the superclass `Serializer` should not be used because they break the serialization policy used by this class.

## Examples

### Naïve Object Request Broker

    --------------------------------------------------------------------------------
    -- Server Script ---------------------------------------------------------------

    -- exported object

    evaluator = {}

    function evaluator:repeats(count)
      self.results = {}
      self.count = count
    end

    function evaluator:execute(name, func, ...)
      local time = socket.gettime()
      for i=1, self.count do func(...) end
      self.results[name] = socket.gettime() - time
    end

    function evaluator:report()
      return self.count, self.results
    end

    -- server-side ORB

    local socket = require "socket"
    local Stream = require "loop.serial.SocketStream"

    local function dispatch(name, method, ...)
      local object = _G[name]
      if object then
        if type(object[method]) == "function" then
          return pcall(object[method], object, ...)
        else
          return false, "method '"..method.."' not provided"
        end
      else
        return false, "object '"..name.."' not found"
      end
    end

    local port = socket.bind("localhost", 2809)
    local channel, errmsg
    repeat
      channel, errmsg = port:accept()
      if channel then
        local stream = Stream{ socket = channel }
        stream:put(dispatch(stream:get()))
        channel:close()
      end
    until errmsg
    port:close()

    --------------------------------------------------------------------------------
    -- Client Script ---------------------------------------------------------------

    -- client-side ORB

    local socket = require "socket"
    local Stream = require "loop.serial.SocketStream"
    local oo     = require "loop.base"

    Proxy = oo.class()

    local function handleresults(success, ...)
      if not success then error(...) end
      return ...
    end

    function Proxy:__index(method)
      return function(proxy, ...)
        local stream = Stream{ socket = assert(socket.connect(proxy.host, proxy.port)) }
        stream:put(proxy.name, method, ...)
        return handleresults(stream:get())
      end
    end

    -- remote object access

    evaluator = Proxy{
      name = "evaluator",
      host = "localhost",
      port = 2809,
    }

    local function fat(n)
      local res = 1
      for i=1,n do
        res = res * i
      end
      return res
    end

    local function fatrec(n)
      if n == 0
        then return 1
        else return n*fatrec(n-1)
      end
    end

    evaluator:repeats(999)
    evaluator:execute("iteractive", fat, 999)
    evaluator:execute("recursive" , fatrec, 999)
    local n, results = evaluator:report()
    print(n.." repetitions:")
    for name, result in pairs(results) do print("", name, result) end

Copyright (C) 2004-2008 Tecgraf, PUC-Rio

This project is currently being maintained by Tecgraf at PUC-Rio.