[How-To] Using an Async Socket in Corona

Hi,

I work with the network library quite a bit when building cloud bits. I wanted to share some code that shows how to create an asynchronous (non-blocking) socket connection in Corona. This is a method that works for me, but I’m sure you could approach this in different ways. If you’re not sure what an async socket is, then you probably don’t need it. :slight_smile:

The following will only work in a Corona project due to some usage of the internal SDK.

[lua]

–==============================================================–

–== Init TCP socket

–==============================================================–

local sock = require( ‘socket’ ).tcp()

–==============================================================–

–== Init message queue

–==============================================================–

local msg_queue = {}

local function checkMessageQueue( client )

  for _, msg in ipairs( msg_queue ) do

    client:write( msg … ‘\r\n’ )

  end

end

–==============================================================–

–== Socket connection + options

–==============================================================–

local ok, msg = sock:connect( host, port )

if not ok then

  error( msg )

end

sock:settimeout( 0 )

sock:setoption( “tcp-nodelay”, true )

–==============================================================–

–== Socket loop

–==============================================================–

local tick = function()

  local input, output = sock.select( {sock}, {sock}, 0 )

  for _, client in ipairs( input ) do

    local data, err, partial = client:recieve(’*l’)

    if data and not err then --incoming!

      --data contains string line from client

    else

      if err == ‘closed’ then

        --do close stuff

      elseif err == ‘timeout’ then

        --handle client timeout

      else

        error( err ) --catch-all error

      end

    end

  end

  --pump message queue

  for _, client in ipairs( output ) do

    checkMessageQueue( client )

  end

end

–==============================================================–

–== Start socket loop

–==============================================================–

local s_loop = timer.performWithDelay( 50, tick, -1 )

[/lua]

Sending a message:

To send a message over the connection, it must be added to the message queue, which will be sent over the first available opening in the loop.

[lua]

table.insert( msg_queue,  “Hello server!” )

[/lua]

What’s going on here?

From a high-level overview, we are using some of the methods of the socket library to create a “send/receive” loop, which would normally be blocking (freeze all on-screen activity). We use the performWithDelay method to create the “timer loop”, which is actually a kind of light thread. By co-opting the timer, we can create an “async” style socket.

The argument “*l” in the sock.select() method is allowing us to use line endings as a message delimiter. Every 50 ms – anything below that barely registers to the human eye – the loop will trigger.

Because we are looking for line endings (\r\n) you must make sure the network data being sent to the Corona client is properly terminated with a newline, generally represented with ‘\r\n’

Within the loop there is a check for waiting sockets (here we are only using one) and if the socket has data, it’s pulled. If a message is queued, it’s sent. And around we go.

This code was extracted from a larger client module for Coronium GS, it should work as shown, but let me know if something is acting wonky.

References:

https://docs.coronalabs.com/api/library/timer/performWithDelay.html

https://docs.coronalabs.com/api/library/socket/index.html

http://w3.impa.br/~diego/software/luasocket/reference.html

https://goo.gl/Hii5al

Cheers.

Of course the show stopper for serious developers for using async sockets in Corona is you cannot secure it using TLS 1.2. 

Hi,

Yes, I have mentioned this once to engineering, and will do so again.

Cheers.

Builds 2825 onward supports TLS 1.2/LuaSec 0.5.1. If you could confirm this, or file a bug report with the specifications of the connection that is failing for you, I will look into it. Please post back here with the case number if you do find a bug.

Initial testing results are good. It seems to work in the Mac simulator, will test on physical devices  (Android and iOS) over the next few days. Guess I should test on Windows at some point too. 

Thanks for the heads up. I’ve been waiting for this functionality since 2013. Why isn’t this bug fix/update listed on the daily builds release notes? I don’t even see a build 2825 on the list? 

Again, thanks. Greatly appreciated. Might be able to use Corona for my next effort now!

Plugins are not part of the daily build release cycle. Plugins can just require a minimum Corona version that they will work in. The plan was to bump it down to support 2731 after testing, but I haven’t gotten around to doing so yet.

We are working on some improvements to our plugin system, and hope to have change logs better exposed.

Of course the show stopper for serious developers for using async sockets in Corona is you cannot secure it using TLS 1.2. 

Hi,

Yes, I have mentioned this once to engineering, and will do so again.

Cheers.

Builds 2825 onward supports TLS 1.2/LuaSec 0.5.1. If you could confirm this, or file a bug report with the specifications of the connection that is failing for you, I will look into it. Please post back here with the case number if you do find a bug.

Initial testing results are good. It seems to work in the Mac simulator, will test on physical devices  (Android and iOS) over the next few days. Guess I should test on Windows at some point too. 

Thanks for the heads up. I’ve been waiting for this functionality since 2013. Why isn’t this bug fix/update listed on the daily builds release notes? I don’t even see a build 2825 on the list? 

Again, thanks. Greatly appreciated. Might be able to use Corona for my next effort now!

Plugins are not part of the daily build release cycle. Plugins can just require a minimum Corona version that they will work in. The plan was to bump it down to support 2731 after testing, but I haven’t gotten around to doing so yet.

We are working on some improvements to our plugin system, and hope to have change logs better exposed.