How to send multiple data (conn:send()) with the new SDK (NodeMCU)

后端 未结 2 1364
南笙
南笙 2021-01-03 10:42

I\'ve been reading the NodeMCU documentation and several closed issues about the change of SDK that previouly allowed to send multiple data streams (acting like a queued net

相关标签:
2条回答
  • 2021-01-03 11:26

    Here is my solution without using tables, saving some memory:

    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)
    

    And this is for serving single files:

    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)
    
    0 讨论(0)
  • 2021-01-03 11:27

    Thank you for the reply. I actually added the header you mentioned, I didn't know that was necessary and I also removed the sck argument in the sender function. My first code was actually working, I don't know what was wrong last time.

    Anyway, it helped me understanding what was happening: the following code seems to concatenate the response array, since the event sent of the socket calls back the sender function (sck:on("sent", sender))

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

    In fact, table.remove(array, 1) returns the first item of the array, and removes this item of the array. Calling this line multiple times has the effect to read through it, item by item.

    For the sake of simplicity, here is the code of a simple webserver able to serve multiple files:

    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)
    

    This example was taken from this instructables and fixed to work with the new SDK (which do not allow multiple :send anymore). Please let me know if this code has some issues.

    I don't know what is the size limit of the files though. Nevertheless, I manage to append more than 2Ko to the response variable and send it at once without any issue.

    0 讨论(0)
提交回复
热议问题