Jump to content


Photo

Nonblocking TCP Sockets/Http Requests?


    5 replies to this topic

    #1 ScaryMonster

    ScaryMonster

      Newbie

    • Members
    • Pip
    • 2 posts

      Posted 14 June 2016 - 06:16 PM

      Hello,

       

      I'm in the process of creating an addon that needs to have some form of internet communication to function. I have all of the communication done, but am getting a blocked UI whenever waiting for a response. 

       

      I am new to LUA and was just wondering if there was any form of asynchronous callbacks / background thread that can be done.

       

       

      Here's what the code looks like now..

       

      function printItemPrices(itemID)
      	 local tcp = assert(socket.tcp())
           tcp:connect(host, port)
      	 tcp:send("GET /AHPrice/GetNamePriceForID.aspx?id=" .. itemID .. " HTTP/1.0\r\n\r\n")
      	
      	 lastLine = ''
      	
      	 local loopCount = 0
      	
      	 --This is where i am freezing
      	 while true do
      		 local s, status, partial = tcp:receive()
      		 lastLine = s or partial
      		 if status == "closed" or status == "Socket is not connected" then break end
      	 end
      	 tcp:close()
      	 tcp:shutdown("both")
      	 if (string.match(lastLine, ",")) then
      		  --handle response
      	 end
      	
       end
      

      Thanks!



      #2 Iryoku

      Iryoku

        Advanced Member

      • Windower Staff
      • 488 posts

        Posted 14 June 2016 - 09:07 PM

        Lua doesn't have any concept of threads. It has coroutines which on the surface may look similar to threads (they are even called threads by Lua internally), but are very different beasts entirely. Addons always run entirely on a single OS thread and there is no way to fork off a thread to run tasks in the background. Windower implements a coroutine scheduler which allows addons to yield control back to Windower (coroutine.yield) so that other code (even code from the same addon) can run; the scheduler will eventually resume the addon where it left off and the call to yield will return as if nothing had happened. (coroutine.sleep is also a Windower extension, and is implemented on top of coroutine.yield.)
         
        So using threads isn't an option. Callbacks are common in Lua (the Windower event API uses callbacks), but without a separate thread to perform the blocking operation on, they don't really solve the problem. The best you can do right now is set a timeout and poll the socket periodically to see if operations have completed.

        I believe we're shipping LuaSocket 2.0.2, so something like the following should work:
         
        First add this call after creating the socket (adjust the timeout as you see fit)
        tcp:settimeout(1)
        
        Next replace the call to connect with this loop
        repeat
            local result, error = tcp:connect()
            -- check the error here to see if the error was a timeout or something else
        
            -- this passes control back to the scheduler so that other code can run,
            -- without this you will still block the UI thread.
            coroutine.yield()
        until result == 1
        You will need to do similar loops for any other operaions that can block such as send, recieve and accept, so a helper function to do the loop may be a good idea.

        #3 trv

        trv

          Advanced Member

        • Members
        • PipPipPip
        • 34 posts

          Posted 16 June 2016 - 12:45 AM

          There's a really good chapter in the Lua book on coroutines which has this problem as an example. https://www.lua.org/pil/9.4.html

           

          Based on what Iryoku wrote, it sounds like socket.select won't work as it's intended, but the chapter is worth reading anyway.



          #4 sdahlka

          sdahlka

            Advanced Member

          • Members
          • PipPipPip
          • 324 posts

            Posted 16 June 2016 - 05:23 AM

            you must remember that(if i recall correctly) windowers lua is 5.1 while the latest version is 5.3 so do be careful of what you look up



            #5 trv

            trv

              Advanced Member

            • Members
            • PipPipPip
            • 34 posts

              Posted 16 June 2016 - 08:45 PM

              The online version of the Lua book was written for Lua 5.0. The coroutines chapter is still relevant, except for the use of the table.getn function. I was not clear: the function socket.select works as it should, but is an inexpensive way of blocking a program, which is not what ScaryMonster wants to do. If he needs a quick rundown of coroutines, that chapter is a good source.



              #6 ScaryMonster

              ScaryMonster

                Newbie

              • Members
              • Pip
              • 2 posts

                Posted 22 June 2016 - 01:11 AM

                Thanks all! I am just now able to get back to this and will report back which solution works best for me. 






                1 user(s) are reading this topic

                0 members, 1 guests, 0 anonymous users