2015-09-12 32 views
2

我想实现一个脚本与服务器套接字,它也将周期性地轮询来自多个传感器(即在每分钟的第59秒)的数据。我不想将数据序列化到磁盘,而是将它保存在一个表中,该表将在轮询时响应。 下面是一些素描的代码来说明什么,我试图做(我还没有列入访问该服务器的客户端代码,但这部分是OK)Lua - 套接字与其他事件的定时器接收

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

我担心的是,服务器有时可能会(s)挡,因此我会错过第59秒。

这是一个很好的方法来实现这个或有一个(更简单)更好的方式来做到这一点(说使用协程)?如果协程更好,我如何为我的场景实现它们?

+1

与您的问题无关,但'table.getn'已弃用。 – hjpotter92

+0

@ hjpotter92 - 感谢您的评论,尽管我在此仅用于说明,并不打算在我的生产代码中使用它。不过,很高兴知道。 – Nepaluz

回答

4

要做到这一点,您需要某种多任务处理。 我会使用网络感知调度程序。

例如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()) 
+0

感谢您的回复。我还没有试过这个代码,但是WOW!看起来完美! – Nepaluz

0

我认为定期启动一些应用程序/代码很容易用不同语言的'cron'库实现。 例如,lua中的cron lib,你可以下载here

+0

我正试图在嵌入式系统上实现此功能,并且希望尽可能保持其内存占用尽可能小,因为它在存储数据方面会占用很多。如果我不必添加另一个库就可以离开,我肯定这是一个点头。 – Nepaluz

+0

因此,尝试阅读cron.lua文件的源代码。它可能有所帮助:https://github.com/kikito/cron.lua/blob/master/cron.lua – Vyacheslav

+0

即使在发布问题之前,我也阅读了该代码,但并不相信它提供了额外的东西。如果我确实错过了某些东西(记住我的骨架代码示例),你会不会指出? – Nepaluz