2017-09-11 80 views
0

我想解析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

這將減少大量無用的搜索。去嘗試一下。 –

回答

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