Lua - получение сокета с таймером для другого события

Я пытаюсь реализовать скрипт с серверным сокетом, который также будет периодически запрашивать данные с нескольких датчиков (т.е. на 59-й секунде каждой минуты). Я не хочу сериализовать данные на диск, а хранить их в таблице, на которую сокет ответит при опросе. Вот набросок кода, чтобы проиллюстрировать, что я пытаюсь сделать (я не включил клиентский код, который обращается к этому серверу, но эта часть в порядке)

#!/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

Я обеспокоен тем, что сервер может иногда блокироваться, и поэтому я пропущу 59-ю секунду.

Это хороший способ реализовать это или есть (более простой) лучший способ сделать это (скажем, с помощью сопрограмм)? Если сопрограммы были бы лучше, как мне реализовать их для моего сценария?


person Nepaluz    schedule 12.09.2015    source источник
comment
Не имеет отношения к вашему вопросу, но table.getn устарело.   -  person hjpotter92    schedule 13.09.2015
comment
@hjpotter92 - спасибо за комментарий, хотя я использовал его здесь только для иллюстрации и не собирался использовать его в своем производственном коде. Тем не менее, полезно знать.   -  person Nepaluz    schedule 13.09.2015


Ответы (2)


Для этого вам нужна своего рода многозадачность. Я бы использовал планировщик с поддержкой сети.

например cqueues будет выглядеть так:

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())
person daurnimator    schedule 14.09.2015
comment
Спасибо за ответ. Я еще не пробовал код, но ВАУ! выглядит идеально! - person Nepaluz; 14.09.2015

Я думаю, что периодический запуск некоторых приложений/кодов хорошо реализован с помощью библиотек cron на разных языках. Например, cron lib на lua можно скачать здесь.

person Vyacheslav    schedule 13.09.2015
comment
Я пытаюсь реализовать это во встроенной системе и хотел бы, чтобы ее объем памяти был как можно меньше, учитывая, что это займет много времени с точки зрения хранения данных. Если я смогу обойтись без добавления еще одной библиотеки, я уверен, что это будет дань уважения. - person Nepaluz; 13.09.2015
comment
Итак, попробуйте прочитать исходный код файла cron.lua. Это может помочь: github.com/kikito/cron.lua/blob/ master/cron.lua - person Vyacheslav; 13.09.2015
comment
Я прочитал этот код еще до публикации вопроса, но не поверил, что он предлагает что-то дополнительное. Если бы я что-то упустил (имея в виду мой пример кода), не могли бы вы указать на это? - person Nepaluz; 13.09.2015