LuaSocket questions

Hello all,
Not sure much of us would know about this topic as it has yet to be implemented in to Codea(unless you are a beta tester, and even then it’s not documented), but I have been taking a look at the LuaSocket docs and have a few questions I was hoping I could get answered:

  1. Will the Codea implementation of LuaSocket be changed at all from the normal library? Just wondering, and I assume not.

  2. In most multiplayer games, you can scan for local games. Is there a way to do this, to check for IP’s on the local network hosting games and then connect to the sockets from there with any of the LuaSocket libraries?

  3. Can you send anything other than strings over the sockets? I don’t really care, but if it is just strings then I see a lot of loadstring()() in my future.

  4. Will TCP be the only implementation of LuaSocket, or will there be any others such as FTP, etc?

Thanks for taking the time to read my stupid questions if anyone knows, and answering this brings me one step closer to building a simple multiplayer library for you all! Thanks!

-TheSolderKing

@SkyTheCoder, can he set the category to beta even though he isn’t a tester?

@JakAttak I didn’t realize he wasn’t a beta tester. How does he know about sockets, though?

Category is reset.

Let’s talk sockets.

@SkyTheCoder Simeon mentioned it here

Does anybody actually know how to write socket code?

@Goatboy76 Sorry, I missed that.

@Ignatz I think @toffer does, he posted this code that works:

function setup()
    socket=require("socket") --EDIT added by ignatz  
    server = socket.tcp()
    -- Replace with your local IPad ip
    server:bind("ip goes here, example: 123.456.7.89",52096)
    server:listen()
    server:settimeout(0.0)
    local ip,port = server:getsockname()
    print("please telnet to", ip, "on port", port)
    client = nil
    buf = {}
end

local _twu = tween.update
tween.update = function(...)
    if not client then
        client = server:accept()
        if client then
            client:settimeout(0.0)
            local ip,po = client:getsockname()
            client:send("Welcome to the REPL mr(s) "..ip.." "..po.."\
")
            client:send("Type bye to quit\
")
        end
    end
    if client then
        local lin, err = client:receive()
        if not err then
            if lin == "bye" then
                client:close()
                client = nil
            else
                table.insert(buf,lin)
                local f,e = load(table.concat(buf,"\
"))
                if not e then
                    f()
                    client:send("> eval\
")
                    buf = {}
                end
          end
        end
    end
    _twu(...)
end

The ip address referred to in the code above is your internal network ip. You get this from Settings, tap your (ticked) Wifi provider and you should see an ip address.

toffer has used a clever hack to keep listening for socket messages. He replaces the normal tween update function (which runs each time a frame is drawn) with the function above, so it checks for socket messages instead. He has, however, stored the name of the original tween update function in _twu, and runs this at the end of the function above, so that the tweens do get updated. So he has basically just added some code into the tween update function.

This means that Codea will run normally while the socket is listening.

EDIT - it worked fine to start with, now Codea knows when I send messages from my PC, but doesn’t recognise “bye” and is unable to print what I type. Hmmm…
:-?

I think I understand the sockets somewhat…

For example, if I wanted to send data between two iPads I believe it would be something like this:

function setup()
    socket = require("socket")

    local myip, myport = getLocalIP(), 5400
    print("Connect to " .. myip .. ":" .. myport)
    
    server = socket.udp()
    server:setsockname(myip, myport)
    server:settimeout(0)

    client = socket.udp()
    client:setpeername(myip, myport)
    client:settimeout(0)

    parameter.text("msg_to_send", "")
    parameter.action("send message", sendMessage)
end

function getLocalIP()
    local randomIP = "192.167.188.122"
    local randomPort = "3102" 
    local randomSocket = socket.udp() 
    randomSocket:setpeername(randomIP,randomPort) 

    local localIP, somePort = randomSocket:getsockname()
    
    randomSocket:close()
    randomSocket = nil
    
    return localIP
end

function sendMessage()
    client:send(msg_to_send)

    print("Client sent to server: '" .. msg_to_send .. "' at", os.date("%x, %X", os.time()))
end

function draw()
    background(255, 255, 255, 255)
    
    local data, msg_or_ip, port_or_nil = server:receivefrom()
    if data then
        print("Server received from client: '" .. data .. "' at", os.date("%x, %X", os.time()))
    end
end

Though obviously the client code would run on one and the server code on the other.

EDIT: updated with method to get local ip (so the server iPad could tell you it’s ip, which you could then tell the client iPad to connect to)

remote control?

@JakAttak - thanks! =D>

@JakAttak - nice shot for the ip retrieval!

@JakAttak Is the code working correctly. If I put in an ip of 0.0.0.0 , the ip stays at 0’s, but it still says the message was sent and received. I don’t know anything about sockets, so I can’t say what’s happening.

@dave1707, I believe it will work as long as the ip given to the client and server is the same. Of course, the true test will be running this on two iPads, which I will try once 2.3 comes out.

Thanks everyone for your help and example code! You answered most of my questions, but still, is there any way I can make a game where both players do not need to know the other’s ip, ie scanning for nearby games? Thanks!

@TheSolderKing, well, the programs will still heed to know each other IPs, in order to communicate efficiently. Several ways that can be done.

One approach could be as simple as periodically broadcasting your ip via a specially addressed (255.255.255.255) udp packet, which gets delivered to all devices on your local network. The packet can contain a simple message like: “my ip is 192.168.1.5” or whatever it is. Another client does the same, and this way they can discover each other.

Another approach could be writing a discovery service, which could be running on your desktop computer, and then each client will be able to register with it, and also ask for all the others who had registered with it too. (that could be a simple HTTP service, you don’t necessarily need to use raw sockets)

@TheSolderKing, @juce - for home networks, local ip addresses are usually sequential and only the last digit changes, perhaps making it easy to scan for a player who sets up as the server.

@Ignatz, that’s true. Just scanning the IPs sequentially would sort of work too, although then you have to guess what valid range is and such. I guess my main point (which i failed to mention :slight_smile: ) was that the whole process consists of two steps:

  1. Discover the peer to play with
  2. Use discovered IP addr of the peer to communicate directly

I haven’t tried the latest code above, but using toffers’ code, I was able to send messages but not read them at the other end, eg pritning them showed nothing, and “bye” wasn’t recognised