LINUX.ORG.RU

lua ошибка при чтении pipe


0

1

Этот скрипт читатель читает из pipe (созданный mkfifo) поток строк, получив сигнал SIGUSR1 от скрипта который пишет (писатель) в pipe, анализирует полученные строки и сохраняет результаты в файл и продолжает читать pipe. таких скриптов запущенно одновременно несколько, у каждого свой pipe. Скрипт писатель по кругу выбирает в какой pipe писать данные и раз в 15 сек меняет получателя посылая SIGUSR1 текущему читателю перед его сменой. По сути ничего супер выдающегося. Но есть проблема

строка line = assert(read_file:read())
завершается ошибкой И каждый раз непредсказуемо, то на первом круге все схлопывается то на 4 ом.

#!/usr/bin/lua
local P = require 'posix'
for k,v in pairs(P) do _G[k] = v end -- без этой строчки не вызываются функции модуля posix
local pipe_in = arg[1]
local switch_interval = tonumber(arg[3])
local instance = arg[4]
root_dir = "/opt/ddos_pps_to_ip"
results_dir = root_dir .. "/results"
pids_dir = root_dir .. "/pids"
local strings = {} -- массив строк для анализа
local ddos_dstip = {} -- массив с количеством пакетов на dstip
maxpps = 100 -- порог PPS превышение которого обнаруживает скрипт
pid=P.getpid"pid"
print("INSTANCE: " .. instance  .. " " .. "PID: " .. pid)
fpid = io.open( pids_dir .. "/ddos" .. instance .. ".pid", "w")
io.output(fpid)
io.write(pid,"\n")
io.close(fpid)
read_file = io.open(pipe_in, "r") -- откроем pipe на чтение
fo = io.open(arg[2], "w") -- сохраним в файл считанные из pipe строки для отладки !!!!!!
io.output(fo)
function handler_sigusr1(signo)  -- обработчик сигнала  SIGUSR1
    fo:flush () -- сбросим буфер в файл
    print("PID:",pid,'handled',signo)
    as=#strings
    print("PID:",pid,"START CHECK DDOS",os.date"%T",time (),"Получено строк на обработку: ",as)
    for i = 1, as, 1 do   -- проанализируем все строки
        dstip = string.sub (strings[i], 71, 85)
        dstip = string.gsub (dstip," ","")
        numpack = string.sub (strings[i], 100, 103)
        numpack = string.gsub (numpack," ","")
        numpack = tonumber(numpack)
        num = ddos_dstip[dstip]
        if numpack ~= nil then
            if num ~= nil then -- первое появление IP адреса
                num = tonumber(num)
                ddos_dstip[dstip] = numpack + num
            else
                ddos_dstip[dstip] = numpack
            end
        end
    end
    rr = results_dir .. "/ddos" .. "_" .. time () .. "_" .. os.date"%T" .. ".result"
    local result_file = io.open( rr , "w")
    io.output(result_file)
    for k, v in pairs(ddos_dstip) do
        pps = math.floor(v/switch_interval)
        if pps >= maxpps then
            str = "dest_ip : " .. k .. " pps: " .. pps
            io.write(str,"\n")
        end
    end
    io.flush();
    result_file:close()
    ddos_dstip = {} -- очистим массив
    strings = {} -- очистим массив
    fo:flush ()
    print("PID:",pid,"STOP CHECK DDOS ",os.date"%T",time ())
end

signal(SIGUSR1,handler_sigusr1)

while true do
    line = assert(read_file:read()) -- assert вставлен для анализа
    if line == nil then
        print ("read PID:",pid,"Считал строку = nil")
        break
    end
    table.insert(strings, line)
    io.write(line,"\n")   -- вывод в файл - дублирование строк для отладки
end
print ("PID:",pid,"ЗАВЕРШАЕМ РАБОТУ")
fo:close() -- это необходимо вынести в обработчик сигналов INT TERM
read_file:close() -- это необходимо вынести в обработчик сигналов INT TERM

пробовал в if line == nil then переоткрывать pipe (вместо break), скрипты цепочки писатель - читатель не падают, но вопрос почему же падает читатель? Может что то я неправильно представляю и конструкция чтения строк из pipe «while true do» не для скриптов с прерываниями на обработку сигналов? Или переоткрывание pipe все таки правильно?

и еще вопрос. число строк записанных в pipe процессом писателем никогда не совпадает с числом строк полученных процессом читателем, это нормально для IPC c использованием pipe?

★★★

строка line = assert(read_file:read())
завершается ошибкой И каждый раз непредсказуемо, то на первом круге все схлопывается то на 4 ом.

local line, err = read_file:read(«*l») if line == nil then print («read PID:»,pid,«Считал строку = nil»," Ошибка:",err) break end

tnodir ()
Ответ на: комментарий от Vlad-76

Ошибка: Interrupted system call

Ага. read() читает себе, и если прям в данный момент поток получает сигнал, то сразу выполняется его обработчик, а вот read() вынужден вернуться с ошибкой «прервали». Поэтому надёжным вариантом, к которому тем не менее редко прибегают, является брать read() в цикл для повторения вызова в случае «прервали».

gag ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.