Left here for archival purposes.

User avatar
By ThomasW
#6690
alonewolfx2 wrote:Lua can't send jpeg files over tcp or any other protocol yet. You can upload with tftpd but you can't use :)


This should be possible with the new file.read(bytes) feature, Markus seems to have it working already:
viewtopic.php?f=18&t=1163#p6652

Thomas
User avatar
By raz123
#7333
Markus Gritsch wrote:@picstart: Here is a slightly modified function from ThomasW (viewtopic.php?f=19&t=702&start=30#p4467) which quickly delivers a big file:
Code: Select allfunction testserver()
   local srv = net.createServer(net.TCP, 100)
   srv:listen(80, function(conn)
      conn:on("receive", function(conn, payload)
         local isopen = false

         conn:on("sent", function(conn)
            if not isopen then
               isopen = true
               file.open("bigfile.html", "r")
            end
            local data = file.read()
            if data then
               conn:send(data)
            else
               file.close()
               conn:close()
               conn = nil
            end
         end)

         conn:send("HTTP/1.1 200 OK\r\n")
         conn:send("Content-type: text/html\r\n")
         conn:send("Connection: close\r\n\r\n")
      end)
   end)
end
testserver()


Exactly what I needed! Thanks!
User avatar
By raz123
#10693
Markus Gritsch wrote:@picstart: Here is a slightly modified function from ThomasW (viewtopic.php?f=19&t=702&start=30#p4467) which quickly delivers a big file:
Code: Select allfunction testserver()
   local srv = net.createServer(net.TCP, 100)
   srv:listen(80, function(conn)
      conn:on("receive", function(conn, payload)
         local isopen = false

         conn:on("sent", function(conn)
            if not isopen then
               isopen = true
               file.open("bigfile.html", "r")
            end
            local data = file.read()
            if data then
               conn:send(data)
            else
               file.close()
               conn:close()
               conn = nil
            end
         end)

         conn:send("HTTP/1.1 200 OK\r\n")
         conn:send("Content-type: text/html\r\n")
         conn:send("Connection: close\r\n\r\n")
      end)
   end)
end
testserver()


I've been spending a bit more time analyzing this and I'm not sure that I understand how this works. Can someone throw a hint?

It seems like the entire file is read into a variable and is then sent out using conn:send.

Knowing that the send buffer is limited to 1460 bytes until a "sent" callback takes place, how is this code managing to send out a large file's entire data in a single send?

Also, wouldn't this code be problematic if the file read into the variable is bigger than what the variable can hold in terms of memory?
User avatar
By raz123
#10698 Found the answer.

File.read() will sequentially read until EOF (end of file), in chunks of LUAL_BUFFERSIZE.

Until build 2015-02-13, LUAL_BUFFERSIZE was 1024 bytes.

Therefore, in the code above, a file.read() was returning 1024 bytes into the "data" variable, which was then sent out. When the callback arrived, another file.read() would gather 1024 bytes, and so on, until the whole file is sent. This worked since bursts of 1024 bytes fits in the SDK's buffer size (1460 bytes) to send data out.

As of 2015-02-13, LUAL_BUFFERSIZE was changed to 4096. This means that a call such as:

Code: Select alla = file.read()


Will gather up to 4096 bytes.

When those 4096 byte are sent, and as this is bigger than the SDK's buffer size, data loss will inevitably take place.
A workaround is to manually read a fixed number of bytes rather than to rely on LUAL_BUFFERSIZE.

Eg:

Code: Select alla = file.read(1460)