Lua的HTTP解析器

问题描述:

我想解析Lua中的http POST请求。我的实现工作,但吃了很多CPU负载。这是至关重要的,因此它在嵌入式平台上。Lua的HTTP解析器

我看过其他的实现,但它们不适合,因为我的图像很难适应内存,所以我不会使用另一个库。我推出了自己的解析器,但它使用了太多的系统资源。问题是我如何优化这个以降低CPU负载。

这是一个基于OpenWRT的系统,所以我只有Lua 5.1。这是查找边界的核心函数(在str变量中)。它逐块读取输入块,并寻找它。

另一种解决方案是使用LUCI库来完成繁重的工作,但我不希望我的代码被集成到LUCI中。

--look for a pattern (str) and copy input until it is found to the output. 
local function writeuntil(in_fp, str, out_fp) 

    local buff = "" 
    local ret = false 
    local bs = 4096 --Block size. The amount of data to read at once 

    local c = in_fp:read(bs) 
    local strStartPos = 1 

    while c do 
     local blockLen = string.len(c) --Not sure that a whole block is read, so get the size of the actual block. 
     local found = string.find(c, str, 1, true) --Try to locate str, so we don't have much work. 
     if (found ~= nil) then 
      if found > 2 then 
       out_fp:write(string.sub(c, 1, found - 1)) 
      end 
      ret = true 
      break --we are done 
     else --Try to mach str till the end of the block 
      local strPos = string.find(c, string.sub(str, strStartPos, strStartPos), 1, true) --try to locate the first character 
      if strPos then --There is a starting character in the block 
       if (strPos > 1) then 
         out_fp:write(string.sub(c, 1, strPos - 1)) 
       end 
       for i = strPos, blockLen do --iterate through the block 
        local ch = string.sub(c, i, i) 
        if ch == string.sub(str, strStartPos, strStartPos) then 
         buff = buff .. ch 
         if string.len(buff) == string.len(str) then 
          ret = true 
          break --We're done 
         end 
         strStartPos = strStartPos + 1 
        else --Lost track. Output. 
         if string.len(buff) > 0 then 
          out_fp:write(buff) 
          buff = "" 
         end 
         out_fp:write(ch) 
         strStartPos = 1 
        end 
       end 
      else 
       out_fp:write(c) 
      end 
     end 
     if ret then 
      break 
     end 
     c = in_fp:read(bs) --read next block 
    end 
    return ret 
end 
+0

您正在开始过早地搜索单个字符。改变你的第21行:'local strPos = string.find(c,string.sub(str,strStartPos,strStartPos),math.max(1,#c - #str + strStartPos + 1),true) - - 找到第一个字符' –

+0

我不明白它是否会有所帮助。 Str可以在缓冲区中的任何位置。 – Lev

+0

这将减少大量无用的搜索。去尝试一下。 –

叶戈尔,你是对的,但我结束了这个解决方案。它现在使用的CPU少得多。这并不完美,因此scp更快(尽管这是用C实现的)。

--look for a pattern (str) and copy input until it is found to the output. 
local function writeuntil(in_fp, str, out_fp) 

    local buff = "" 
    local ret = false 
    local bs = 4096 --Block size. The amount of data to read at once 

    local c = in_fp:read(bs) 
    local strStartPos = 1 
    local lastStrPos = 1 
    local needData = true 

    while c do 
     local blockLen = string.len(c) --Not sure that a whole block is read, so get the size of the actual block. 
     local found = string.find(c, str, 1, true) --Try to locate str, so we don't have much work. 
     if (found ~= nil) then 
      if found > 1 then 
       if #buff > 0 then 
        out_fp:write(buff) 
       end 
       out_fp:write(string.sub(c, 1, found - 1)) 
      end 
      ret = true 
      break --we are done 
     else --Try to mach str till the end of the block 
      local strPos = string.find(c, string.sub(str, strStartPos, strStartPos), lastStrPos, true) --try to locate the first character 
      if strPos then --There is a starting character in the block 
       out_fp:write(string.sub(c, lastStrPos, strPos - 1)) 
       for i = strPos, blockLen do --iterate through the block 
        local ch = string.sub(c, i, i) 
        if ch == string.sub(str, strStartPos, strStartPos) then 
         buff = buff .. ch 
         if string.len(buff) == string.len(str) then 
          ret = true 
          break --We're done 
         end 
         strStartPos = strStartPos + 1 
         lastStrPos = i + 1 
        else --Lost track. Output. 
         if string.len(buff) > 0 then 
          out_fp:write(buff) 
          buff = "" 
         end 
         out_fp:write(ch) 
         strStartPos = 1 
         if i == blockLen then 
          needData = true 
         else 
          lastStrPos = i + 1 
          needData = false 
         end 
         break 
        end 
       end 
      else 
       if ret == false then 
        if string.len(buff) > 0 then 
         out_fp:write(buff) 
         buff = "" 
        end 
        out_fp:write(string.sub(c, lastStrPos)) 
        lastStrPos = 1 
        needData = true 
       else 
        break 
       end 
      end 
     end 
     if ret then 
      break 
     end 
     if needData then 
      c = in_fp:read(bs) --read next block 
      lastStrPos = 1 
     end 
    end 
    return ret 
end