Lua - 套接字接收其他事件的计时器
Lua - Socket receive with timer for other event
我正在尝试使用服务器套接字实现一个脚本,该套接字还将定期轮询来自多个传感器的数据(即每分钟的第 59 秒)。我不想将数据序列化到磁盘,而是将其保存在 table 中,套接字将在轮询时响应。
这里有一些代码草图来说明我正在尝试做什么(我没有包括访问此服务器的客户端代码,但那部分没问题)
#!/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 秒。
这是实现这个的好方法还是有(更简单)更好的方法(比如使用协程)?如果协程会更好,我该如何为我的场景实现它们?
我认为使用不同语言的 'cron' 库可以很好地实现定期启动一些 apps/codes。
例如lua中的cron lib你可以下载here.
要做到这一点,您需要进行某种多任务处理。
我会使用网络感知调度程序。
例如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())
我正在尝试使用服务器套接字实现一个脚本,该套接字还将定期轮询来自多个传感器的数据(即每分钟的第 59 秒)。我不想将数据序列化到磁盘,而是将其保存在 table 中,套接字将在轮询时响应。 这里有一些代码草图来说明我正在尝试做什么(我没有包括访问此服务器的客户端代码,但那部分没问题)
#!/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 秒。
这是实现这个的好方法还是有(更简单)更好的方法(比如使用协程)?如果协程会更好,我该如何为我的场景实现它们?
我认为使用不同语言的 'cron' 库可以很好地实现定期启动一些 apps/codes。 例如lua中的cron lib你可以下载here.
要做到这一点,您需要进行某种多任务处理。 我会使用网络感知调度程序。
例如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())