如何使用新的SDK(NodeMCU)发送多个数据(conn:send())

我一直在阅读关于NodeMCU文档和许多关闭的问题,关于先前允许发送多个数据流(类似于排队的net.socket: send)的SDK更改。

似乎这里(#730)和这里(#993)甚至还有这里(#999)都引发了一场巨大的辩论。但是,我没有找到任何令人信服的Web服务器代码示例,可以允许我读取多个html文件(例如head.htmlbody.html)以显示页面。以下是TerryE的示例,我试图适应它,但没有成功:

srv=net.createServer(net.TCP)
srv:listen(80,function(conn)
    conn:on ("receive", function(sck, req)
        local response = {}

        local f = file.open("head.html","r")
        if f ~= nil then
            response[#response+1] = file.read()
            file.close()
        end

        local f = file.open("body.html","r")
        if f ~= nil then
            response[#response+1] = file.read()
            file.close()
        end

        local function sender (sck)
            if #response>0 then sck:send(table.remove(response,1))
            else sck:close()
            end
        end
        sck:on("sent", sender)
        sender(sck)
    end )
end )

连接到ESP8266时,没有任何加载,我从lua终端中没有任何错误。

供您参考,head.html包含:

<html>
<head>
</head>

body.html包含:

<body>
<h1>Hello World</h1>
</body>
</html>

我非常新于NodeMCU,请包涵。

点赞
用户6059658
用户6059658

谢谢您的回复。我实际上添加了您提到的标头,我不知道是否必要,我还删除了sender函数中的sck参数。我的第一行代码实际上是起作用的,我不知道上次出了什么问题。

不管怎样,这帮助我理解了发生了什么:下面的代码似乎连接了response数组,因为socket的sent事件回调sender函数(sck:on("sent",sender)

sck:send(table.remove(response,1))

实际上,table.remove(array,1)返回数组的第一个项目,并将此项目从数组中删除。多次调用此行将以逐项的方式读取它。

为了简单起见,这里是简单Web服务器的代码,可以为多个文件提供服务:

header = "HTTP/1.0 200 OK\r\nServer: NodeMCU on ESP8266\r\nContent-Type: text/html\r\n\r\n"
srv=net.createServer(net.TCP)
srv:listen(80,function(conn)
    conn:on ("receive", function(sck, req)
        local response = {header}

        tgtfile = string.sub(req,string.find(req,"GET /") +5,string.find(req,"HTTP/") -2 )
        if tgtfile == "" then tgtfile = "index.htm" end
        local f = file.open(tgtfile,"r")
        if f ~= nil then
            response[#response+1] = file.read()
            file.close()
        else
            response[#response+1] = "<html>"
            response[#response+1] = tgtfile.." not Found - 404 error."
            response[#response+1] = "<a href='index.htm'>Home</a>"
        end
        collectgarbage()
        f = nil
        tgtfile = nil

        local function sender ()
            if #response>0 then sck:send(table.remove(response,1))
            else sck:close()
            end
        end
        sck:on("sent", sender)
        sender()
    end)
end)

这个例子来自这个说明,并已经修复以适应新的SDK(不再允许多个:send)。如果这个代码有问题,请告诉我。

我不知道文件的大小限制是多少。尽管如此,我设法将超过2Ko附加到response变量并一次性发送,没有任何问题。

2016-03-18 22:36:27
用户939269
用户939269

以下是不使用表格来节约内存的解决方案:

function Sendfile(sck, filename, sentCallback)
    if not file.open(filename, "r") then
        sck:close()
        return
    end
    local function sendChunk()
        local line = file.read(512)
        if line then
            sck:send(line, sendChunk)
        else
            file.close()
            collectgarbage()
            if sentCallback then
                sentCallback()
            else
                sck:close()
            end
        end
    end
    sendChunk()
end

srv = net.createServer(net.TCP)
srv:listen(80, function(conn)
    conn:on("receive", function(sck, req)
        sck:send("HTTP/1.1 200 OK\r\n" ..
            "Server: NodeMCU on ESP8266\r\n" ..
            "Content-Type: text/html; charset=UTF-8\r\n\r\n",
            function()
                Sendfile(sck, "head.html", function() Sendfile(sck, "body.html") end)
            end)
    end)
end)

以下是仅用于提供单个文件的解决方案:

function Sendfile(client, filename)
    if file.open(filename, "r") then
        local function sendChunk()
            local line = file.read(512)
            if line then
                client:send(line, sendChunk)
            else
                file.close()
                client:close()
                collectgarbage()
            end
        end
        client:send("HTTP/1.1 200 OK\r\n" ..
            "Server: NodeMCU on ESP8266\r\n" ..
            "Content-Type: text/html; charset=UTF-8\r\n\r\n", sendChunk)
    else
        client:send("HTTP/1.0 404 Not Found\r\n\r\nPage not found")
        client:close()
    end
end

srv = net.createServer(net.TCP)
srv:listen(80, function(conn)
    conn:on ("receive", function(client, request)
        local path = string.match(request, "GET /(.+) HTTP")
        if path == "" then path = "index.htm" end
        Sendfile(client, path)
    end)
end)
2016-03-23 01:01:07