LuaLanes and LuaSockets

I am working on a small Lua application (under Lua for Windows, if that is important) that uses sockets to communicate with the outside world. (LuaSocket)

And I'm trying to make several requests in parallel. So I thought LuaLanes is the way to go. (I am open to alternatives, of course, if there is a better solution, but would prefer not to deal with coroutines for this.)

Something like that:

server = assert (socket.bind ('*', 1234)) client = server : accept () -- set id to some unique value allClients [id] = client theLane = lanes.gen ("", laneTest) ( id ) print (theLane [1]) 

Where the laneTest function laneTest defined as follows:

 function laneTest (id) local client = allClients [id] print ('peer: ', client:getpeername()) end 

My problem is that inside the laneTest function laneTest when I run as a strip, I get this beautiful error message:

try indexing local "client" (value userdata)

(from client:getpeername() )

So, I'm not sure what is going on here? Are the stripes incompatible with sockets, or am I doing something very wrong?

I think it may be that the version of the tracks that comes with Lua for Windows is ancient ( luaforwindows ) and does not work with sockets, but can the latest version? (Lanes 2.0.4 and later 3.xx)

I really don’t know how to do this in order to update the version of Lanes that I received, otherwise I would try to do this so far. I would appreciate any advice if there where I could go, or there is something more obvious that I did wrong.

Edit: I went ahead and installed lanes through luarocks, and I have the same problem using lanes 3.1.6-1, which are set like stone.

Edit 2: Tried this (and still failed):

 require ('socket') require ('lanes') local allClients = {} function theLane (id) print ('the id:', id) -- correctly prints out the id passed to the function local SOCKET = require ('socket') local client = allClients [id] print ('peer:', client:getpeername()) client : close () end local server = assert (SOCKET.bind ('*', 1234)) local ip, port = server:getsockname () local laneFunc = lanes.gen('', theLane) local client = server:accept () allClients [1] = client local x = laneFunc (1) print (x[1]) 
  • This is not consistent with the statement: attempt to call global 'require' (a nil value)
  • Removing the require ('socket') inside the function and retrying also fail: attempt to index local 'client' (a userdata value)

I apologize in advance for the lack of the obvious, but ... how do you get sockets for working with tracks?

Edit 3:

Well, I am editing this for future reference :)

As far as I can tell, there is no way to use Lanes with sockets without the luasockets patch. See the discussion here for more on this; but shorter (and as explained in Deco's answer): stripes do not work with user data. luasocket does not provide another way to access socket / socket information.

I have no desire to impose luasocket as I would prefer to use stripes, I will go forward and stick to copas or couroutines.

Thanks everyone!

+6
source share
2 answers

Lua programming has an example of continuous multithreading (using coroutines), which you can probably use almost directly. In my opinion, coroutines will be the best solution for your use case.

There is also a copas library that describes itself as a "coroutine-based dispatcher that can be used by TCP / IP servers," but you can really use it to send requests asynchronously (using a combination of addthread and step calls).

+5
source

Lua Lanes creates a completely new (but minimal) Lua state for each strip. Any overfulfilled or passed arguments are copied, not referenced; this means that your allClients table is copied along with the sockets it contains.

The error occurs because the sockets are userdata, which Lua Lanes cannot copy without any advice from module C. Unfortunately, LuaSocket does not offer such advice. (There are ways around this, but be careful: LuaSocket is not thread safe, and synchronization errors are very difficult to track.)

Although this will not solve your problem, you should notice that you need to use LuaSocket on your spawned strip; it is not copied by default.

Solutions!

They are ordered from simple to hard (and are basically rewritten from my other answer here ).

Single threaded poll

Repeatedly invoke polling functions in LuaSocket:

  • Lock: call socket.select without a time argument and wait for the socket to read.
  • Non-blocking: call socket.select with a timeout argument of 0 and use sock:settimeout(0) on the socket you are reading.

Just call them again. I suggest using an accompanying scheduler for the non-blocking version so that other parts of the program can continue to run without undue delay.

(If you go for this decision, I suggest considering Paul's answer .)

Dual-stream survey

Your main topic is not about sockets at all. Instead, it creates another track that requires LuaSocket, processes all clients, and communicates with the main thread through linda .

This is probably the most effective option for you.

Multithreaded poll

The same as above, except that each thread processes a subset of all clients (from 1 to 1 is possible, but a decreasing return will be set with a large number of clients).

I made a simple example of this, available here . It relies on Lua Lanes 3.4.0 ( GitHub repo ) and patched LuaSocket 2.0.2 ( source , patch ,:

The results are promising, although you should definitely reorganize my sample code if you exit it.

LuaJIT + ENet

ENet is a great library. It provides the perfect connection between TCP and UDP: reliable when necessary, otherwise unreliable. It also abstracts the specific details of the operating system, like LuaSocket. You can use the Lua API to bind or directly access it through LuaJIT FFI (recommended).

+4
source

All Articles