具有自动更新功能的 NodeMCU 超小型 Web 服务器内存不足
NodeMCU super tiny web server with autoupdate runs out of memory
我正在测试具有自动更新功能的小型 Lua 网络服务器。 HTML 代码每秒重定向到 Web 服务器本身。所以客户端的网络浏览器总是从服务器获取新数据而不是
使用浏览器的缓存。
如果一段时间后我只连接一个客户端(我的 PC 或智能手机),NodeMCU 板会崩溃并显示此消息:
PANIC: unprotected error in call to Lua API (SO-WebSrv-Test.lua:27: out of memory)
我使用了 Marcel Stoer 的代码,他回答了类似的 "running out of memory" 。
我修改了 Marcel 的 Lua 代码,但随着时间的推移这段代码仍然会占用所有堆内存。
我稍微缩小了问题范围:如果 HTML 代码的刷新频率低于 30 秒,代码会占用堆内存。
那么我该如何修改这段代码来实现恒定的堆内存使用?
此致。
斯蒂芬
tmr.alarm(0, 1000, 1, function()
if wifi.sta.getip() == nil then
print("trying to connect to AccessPoint...")
else
own_ip, netmask, gateway=wifi.sta.getip()
print("connected to AccessPoint:")
print("IP Info: \nIP Address of this device: ",own_ip)
print("Netmask: ",netmask)
print("Gateway Addr: ",gateway,"\n")
print("type IP-Address "..own_ip.." into your browser to display SHT-31-website")
tmr.stop(0)
end
end)
counter = 0
srv = net.createServer(net.TCP, 28800)
print("Server created... \n")
srv:listen(80, function(conn)
conn:on("receive", function(sck, request)
local message = {}
counter = counter + 1
message[#message + 1] = "<head> <meta http-equiv=refresh content=1; URL=http://"..own_ip.."> </head>"
message[#message + 1] = "<h1> ESP8266 SHT-31 Web Server Ver 003</h1>"
message[#message + 1] = "<h2>some more text blabla blub"..counter.."</h2>"
local function send(sk)
if #message > 0 then
sk:send(table.remove(message, 1))
else
sk:close()
message = nil
print("Heap Available:" .. node.heap())
end
end
sck:on("sent", send)
send(sck)
end)
end)
您没有告诉我们您使用的固件版本。我在 Chromium 浏览器中测试了最新版本,没有发现任何内存问题。我在 700 多个重新加载周期后中止了测试,堆消耗绝对稳定。
今年早些时候我们不得不 reduce the TCP TIME_WAIT
parameter value 因为太多处于 time-wait 状态的废弃套接字正在耗尽内存。说明:
TIME-WAIT
(either server or client) represents waiting for enough time
to pass to be sure the remote TCP received the acknowledgment of its
connection termination request. [According to RFC 793 a connection can
stay in TIME-WAIT for a maximum of four minutes known as two MSL
(maximum segment lifetime).]
来源:https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Protocol_operation
更多详情:https://www.rfc-editor.org/rfc/rfc7230#section-6.6
但是:
- 您似乎打算通过 HTTP 将 HTML 发送回您的客户端,但不要告诉它,它可能不喜欢那样
- 如果您的客户端(浏览器?)没有按时关闭旧套接字,您也可以明确告诉它这样做
添加正确的 HTTP headers 可以解决这两个问题。因此,消息部分应该是这样的:
local message = { "HTTP/1.0 200 OK\r\nServer: NodeMCU on ESP8266\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n" }
counter = counter + 1
message[#message + 1] = "<html><head> <meta http-equiv=refresh content=1; URL=http://" .. own_ip .. "> </head>"
message[#message + 1] = "<body><h1> ESP8266 SHT-31 Web Server Ver 003</h1>"
message[#message + 1] = "<h2>some more text blabla blub" .. counter .. "</h2></body></html>"
注意 Connection: close
和 Content-Type: text/html
以及结构正确的 HTML 标记。
我正在测试具有自动更新功能的小型 Lua 网络服务器。 HTML 代码每秒重定向到 Web 服务器本身。所以客户端的网络浏览器总是从服务器获取新数据而不是 使用浏览器的缓存。
如果一段时间后我只连接一个客户端(我的 PC 或智能手机),NodeMCU 板会崩溃并显示此消息:
PANIC: unprotected error in call to Lua API (SO-WebSrv-Test.lua:27: out of memory)
我使用了 Marcel Stoer 的代码,他回答了类似的 "running out of memory"
我修改了 Marcel 的 Lua 代码,但随着时间的推移这段代码仍然会占用所有堆内存。
我稍微缩小了问题范围:如果 HTML 代码的刷新频率低于 30 秒,代码会占用堆内存。
那么我该如何修改这段代码来实现恒定的堆内存使用?
此致。
斯蒂芬
tmr.alarm(0, 1000, 1, function()
if wifi.sta.getip() == nil then
print("trying to connect to AccessPoint...")
else
own_ip, netmask, gateway=wifi.sta.getip()
print("connected to AccessPoint:")
print("IP Info: \nIP Address of this device: ",own_ip)
print("Netmask: ",netmask)
print("Gateway Addr: ",gateway,"\n")
print("type IP-Address "..own_ip.." into your browser to display SHT-31-website")
tmr.stop(0)
end
end)
counter = 0
srv = net.createServer(net.TCP, 28800)
print("Server created... \n")
srv:listen(80, function(conn)
conn:on("receive", function(sck, request)
local message = {}
counter = counter + 1
message[#message + 1] = "<head> <meta http-equiv=refresh content=1; URL=http://"..own_ip.."> </head>"
message[#message + 1] = "<h1> ESP8266 SHT-31 Web Server Ver 003</h1>"
message[#message + 1] = "<h2>some more text blabla blub"..counter.."</h2>"
local function send(sk)
if #message > 0 then
sk:send(table.remove(message, 1))
else
sk:close()
message = nil
print("Heap Available:" .. node.heap())
end
end
sck:on("sent", send)
send(sck)
end)
end)
您没有告诉我们您使用的固件版本。我在 Chromium 浏览器中测试了最新版本,没有发现任何内存问题。我在 700 多个重新加载周期后中止了测试,堆消耗绝对稳定。
今年早些时候我们不得不 reduce the TCP TIME_WAIT
parameter value 因为太多处于 time-wait 状态的废弃套接字正在耗尽内存。说明:
TIME-WAIT
(either server or client) represents waiting for enough time to pass to be sure the remote TCP received the acknowledgment of its connection termination request. [According to RFC 793 a connection can stay in TIME-WAIT for a maximum of four minutes known as two MSL (maximum segment lifetime).]
来源:https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Protocol_operation
更多详情:https://www.rfc-editor.org/rfc/rfc7230#section-6.6
但是:
- 您似乎打算通过 HTTP 将 HTML 发送回您的客户端,但不要告诉它,它可能不喜欢那样
- 如果您的客户端(浏览器?)没有按时关闭旧套接字,您也可以明确告诉它这样做
添加正确的 HTTP headers 可以解决这两个问题。因此,消息部分应该是这样的:
local message = { "HTTP/1.0 200 OK\r\nServer: NodeMCU on ESP8266\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n" }
counter = counter + 1
message[#message + 1] = "<html><head> <meta http-equiv=refresh content=1; URL=http://" .. own_ip .. "> </head>"
message[#message + 1] = "<body><h1> ESP8266 SHT-31 Web Server Ver 003</h1>"
message[#message + 1] = "<h2>some more text blabla blub" .. counter .. "</h2></body></html>"
注意 Connection: close
和 Content-Type: text/html
以及结构正确的 HTML 标记。