2

I am trying to implement a script with a server socket that will also periodically poll for data from several sensors (i.e on 59th second of every minute). I do not want to serialize the data to disk but rather keep it in a table which the socket will respond with when polled. Here's some sketch the code to illustrate what I am trying to do (I've not included the client code that accesses this server, but that part is OK)

#!/usr/bin/env lua

local socket = require("socket")
local server = assert(socket.bind("*", 0))
local ip, port = server:getsockname()

local data = {}
local count = 1
local function pollSensors()
  -- I do the sensor polling here and add to table e.g os.time()
  table.insert(data, os.time() .."\t" .. tostring(count))
  count = count + 1
end

while true do
  local client = server:accept()
  client:settimeout(2)
  local line, err = client:receive()
  -- I do process the received line to determine the response
  -- for illustration I'll just send the number of items in the table
  if not err then client:send("Records: " ..table.getn(data) .. "\n") end
  client:close()
  if os.time().sec == 59 then
     pollSensors()
  end
end

I am concerned that the server may on occasion(s) block and therefore I'll miss the 59th second.

Is this a good way to implement this or is there a (simpler) better way to do this (say using coroutines)? If coroutines would be better, how do I implement them for my scenario?

hjpotter92
  • 78,589
  • 36
  • 144
  • 183
Nepaluz
  • 669
  • 1
  • 12
  • 27
  • 1
    Unrelated to your question, but `table.getn` is deprecated. – hjpotter92 Sep 13 '15 at 09:21
  • @hjpotter92 - thanks for the comment though I used it here just for illustration and was not intending to use it in my production code. Still, good to know. – Nepaluz Sep 13 '15 at 12:33

2 Answers2

4

To accomplish this you need some sort of multitasking. I'd use a network aware scheduler.

e.g. cqueues would look like this:

local cqueues = require "cqueues"
local cs = require "cqueues.socket"

local data = {}
local count = 1
local function pollSensors()
    -- I do the sensor polling here and add to table e.g os.time()
    table.insert(data, os.time() .."\t" .. tostring(count))
    count = count + 1
end

local function handle_client(client)
    client:setmode("b", "bn") -- turn on binary mode for socket and turn off buffering
    -- ported code from question:
    client:settimeout(2) -- I'm not sure why you chose a 2 second timeout
    local line, err = client:read("*l") -- with cqueues, this read will not block the whole program, but just yield the current coroutine until data arrives.
    -- I do process the received line to determine the response
    -- for illustration I'll just send the number of items in the table
    if not err then
        assert(client:write(string.format("Records: %d\n", #data)))
    end
    client:close()
end

local cq = cqueues.new() -- create a new scheduler
-- create first coroutine that waits for incoming clients
cq:wrap(function()
    local server = cs.listen{host = "0.0.0.0"; port = "0"}
    local fam, ip, port = server:localname()
    print(string.format("Now listening on ip=%s port=%d", ip, port))
    for client in server:clients() do -- iterates over `accept`ed clients
        -- create a new coroutine for each client, passing the client in
        cqueues.running():wrap(handle_client, client)
    end
end)
-- create second coroutine that reads sensors
cq:wrap(function()
    while true do
        -- I assume you just wanted to read every 60 seconds; rather than actually *on* the 59th second of each minute.
        pollSensors()
        cqueues.sleep(60)
    end
end)
-- Run scheduler until all threads exit
assert(cq:loop())
daurnimator
  • 4,091
  • 18
  • 34
0

I think the periodically launching some apps/codes are good realized with 'cron' libraries in different languages. For instance, cron lib in lua you can download here.

Vyacheslav
  • 26,359
  • 19
  • 112
  • 194
  • I am trying to implement this on an embedded system and would like to keep its memory footprint as small as possible, given that it'll take up a lot in terms of storing data. If I can get away without having to add another lib, I am sure that'd be a nod to that. – Nepaluz Sep 13 '15 at 12:31
  • So, try to read the source code of cron.lua file. It might help: https://github.com/kikito/cron.lua/blob/master/cron.lua – Vyacheslav Sep 13 '15 at 15:17
  • I read that code, even before posting the question, but did not believe it offered anything extra. If I did miss something (bearing in mind my skeleton code sample), would you kindly point it out? – Nepaluz Sep 13 '15 at 15:30