Local Multiplayer with UDP/TCP

Ok, so you are sure they are connected (sock is not nil) and you are sure that the server received a message from the client? One thing that you need to be aware of is that when a message is sent it “succeeds” if it gets out to the internet. if for example the other device is off but didn’t disconnect from the server the server won’t know that. The message will be lost. Thus, I like to index my messages and have the server echo back that the message was received. This is not automatic. Also if you send three messages you can’t control which one gets there first, so again an index will help. If your server is capturing information and it got 1 and 3 the. It knows to wait for 2. Its not a big deal if it’s not on the pulse when the message gets there. As long as the socket is open you will process the message on the next pulse. But the socket needs to be ready to receive a message. This whole system is a bit nuanced and there are a lot of things that can go wrong when two computers talk to each other so you just kind of have to verify everything.

Thanks for your quick replies.  Yes, I did make sure the server was receiving from the client.  In the createServer method, where it checks for data from the clients, I made it echo what it had received, and verified that it had matched the info that the client had sent.   Next, when the server sends the “hello_client”, it does this continuously and it doesn’t appear that the client receives anything because the client’s receive-data buffer is empty when I try to echo it.

I understand what you mean by the messages not arriving; in fact I’m thinking of doing a ‘request’ and ‘ack’ method where the server and client both ensure that the messages had arrived; or I’ll just send a burst of like 3 messages instead of 1.

Here’s my entire code, which is based on the the original post.  This code is ready to run and shows output on the console:

main.lua:

local socket = require("socket") local server = require("server") server\_ip = 0 local getClientIP local findServer local connectToServer local createClientLoop getClientIP = function() local s = socket.udp() --creates a UDP object s:setpeername( "74.125.115.104", 80 ) --Google website local ip, sock = s:getsockname() print( "Client IP / socket:", ip, sock ) return ip end findServer = function() local newServers = {} local msg = "AwesomeGameServer" local listen = socket.udp() listen:setsockname( "226.192.1.1", 1234 ) --this only works if the device supports multicast local name = listen:getsockname() if ( name ) then --test to see if device supports multicast listen:setoption( "ip-add-membership", { multiaddr="226.192.1.1", interface = getClientIP() } ) else --the device doesn't support multicast so we'll listen for broadcast listen:close() --first we close the old socket; this is important listen = socket.udp() --make a new socket listen:setsockname( getClientIP(), 1234 ) --set the socket name to the real IP address end listen:settimeout( 0 ) --move along if there is nothing to hear local stop local counter = 0 --pulse counter local function look() repeat local data, ip, port = listen:receivefrom() --print( "data: ", data, "IP: ", ip, "port: ", port ) if data and data == msg then if not newServers[ip] then print( "Client hears a server at IP " .. ip .. " and port " .. port ) local params = { ["ip"]=ip, ["port"]=1235 } newServers[ip] = params server\_ip = ip end end until not data counter = counter + 1 if counter == 20 then --stop after 2 seconds stop() end end --pulse 10 times per second local beginLooking = timer.performWithDelay( 100, look, 0 ) function stop() timer.cancel( beginLooking ) --evaluateServerList( newServers ) --do something with your found servers listen:close() --never forget to close the socket! end end connectToServer = function( ip, port ) print("Sending message to IP " .. ip .. " and port " .. port) local sock, err = socket.connect( ip, port ) if sock == nil then return false end sock:settimeout( 0 ) sock:setoption( "tcp-nodelay", true ) --disable Nagle's algorithm sock:send("CLIENT " ..ip .. " " .. port .. "\n") return sock end createClientLoop = function( sock, ip, port ) local buffer = {} local clientPulse local function cPulse() local allData = {} local data, err -- Get line by line of data and store in allData repeat data, err = sock:receive() if data then allData[#allData+1] = data end if ( err == "closed" and clientPulse ) then --try again if connection closed print("Client connection closed. Re-connect and try to receive again.") connectToServer( ip, port ) data, err = sock:receive() if data then allData[#allData+1] = data end end until not data if ( #allData \> 0 ) then for i, thisData in ipairs( allData ) do print( "Client received from server:", thisData ) --------------------------- --react to incoming data --------------------------- end end -- TO DO: set a buffer to send, depending on action for i, msg in pairs( buffer ) do local data, err = sock:send(msg) if ( err == "closed" and clientPulse ) then --try to reconnect and resend print("Client connection closed. Re-connect and try to send again.") connectToServer( ip, port ) data, err = sock:send( msg ) end end end --pulse 10 times per second clientPulse = timer.performWithDelay( 100, cPulse, 0 ) local function stopClient() timer.cancel( clientPulse ) --cancel timer clientPulse = nil sock:close() end return stopClient end ------------------------------------------------------------------------------------ ----------------------- server.createServer() ----------------------- -- server\_b local serverb = display.newText("Advertise server", 400, 150, "pixelDR", 36) serverb:setTextColor(255, 0, 0) -- Advertise the server ----------------------------- serverbF = function(event) server.advertiseServer() end ----------------------------- serverb:addEventListener("tap",serverbF) -- client\_b local clientb = display.newText("Get client IP", 400, 200, "pixelDR", 36) clientb:setTextColor(0, 255, 0) -- Client finds out its IP address ----------------------- clientbF = function(event) findServer() end ----------------------- clientb:addEventListener("tap",clientbF) -- send\_b local sendb = display.newText("Connect to Server", 400, 290, "pixelDR", 36) sendb:setTextColor(255, 0, 255) -- Connect to server ----------------------- sendbF = function(event) -- Get a session ID ("sock") from server local sock = connectToServer(server\_ip,1235) createClientLoop(sock,server\_ip,1235) end ----------------------- sendb:addEventListener("tap",sendbF)

server.lua:

local S = {} local socket = require( "socket" ) local clientList = {} local clientBuffer = {} S.getServerIP = function() local s = socket.udp() s:setpeername( "74.125.115.104", 80 ) local ip, sock = s:getsockname() print( "Server IP / socket:", ip, sock ) return ip end S.createServer = function() local tcp, err = socket.bind( S.getServerIP(), 1235 ) --create a server object tcp:settimeout( 0 ) local function sPulse() ------------------------------------------------------ -- Check for available clients ------------------------------------------------------ repeat local client = tcp:accept() --allow a new client to connect if client then print( "Server detected a client" ) client:settimeout( 0 ) --just check the socket and keep going --TO DO: implement a way to check to see if the client has connected previously --consider assigning the client a session ID and use it on reconnect. clientList[#clientList+1] = client -- TO DO clientBuffer[client] = { "hello\_client" } --just including something to send below end until not client -- Check to see which client connections are available local ready, writeReady, err = socket.select( clientList, clientList, 0 ) ------------------------------------------------------- -- Look for data from clients ------------------------------------------------------- if err == nil then for i = 1, #ready do --list of clients who are available local client = ready[i] local allData = {} --this holds all lines from a given client -- From current client, get line by line of data and store in allData repeat local data, err = client:receive() -- get a line of data from the client, if any if data then allData[#allData+1] = data end until not data if ( #allData \> 0 ) then --figure out what the client said to the server -- Get each line from allData for i, thisData in ipairs( allData ) do print( "Server received from client:", thisData ) --------------------- -- Do stuff with data --------------------- end end end ------------------------------------------------------ -- Send whatever is in the server's buffer ------------------------------------------------------ for sock, buffer in pairs( clientBuffer ) do -- Grab each line from the buffer meant for current client, and send it for \_, msg in pairs( buffer ) do --might be empty print("Server sends to clients:", msg) local data, err = sock:send( msg ) --send the message to the clients print("Err: ",err) print("\n") end end end end -- Call above function every 100 ms local serverPulse = timer.performWithDelay( 100, sPulse, 0 ) local function stopServer() timer.cancel( serverPulse ) --cancel timer tcp:close() for i, v in pairs( clientList ) do v:close() end end return stopServer end S.advertiseServer = function() print("Advertise server") local send = socket.udp() send:settimeout( 0 ) --this is important (how long to wait before moving on) local stop local counter = 0 --using this, we can advertise our IP address for a limited time local function broadcast() local msg = "AwesomeGameServer" --multicast IP range from 224.0.0.0 to 239.255.255.255 send:sendto( msg, "226.192.1.1", 1234 ) --not all devices can multicast so it's a good idea to broadcast too --however, for broadcast to work, the network has to allow it send:setoption( "broadcast", true ) --turn on broadcast send:sendto( msg, "255.255.255.255", 1234 ) send:setoption( "broadcast", false ) --turn off broadcast counter = counter + 1 if ( counter == 80 ) then --stop after 8 seconds stop() -- variable to a function end end --pulse 10 times per second local serverBroadcast = timer.performWithDelay( 100, broadcast, 0 ) stop = function() timer.cancel( serverBroadcast ) --cancel timer stop = nil print("Stop server broadcast") end end return S

Try changing “hello_client” to “hello_client\n”. I think the socket on the client side is still waiting for more data.

[quote name=“mark_steelman” post=“286579” timestamp=“1425905259”]Try changing “hello_client” to “hello_client\n”. I think the socket on the client side is still waiting for more data.[/quote] Ah, that worked :slight_smile: How did I miss that …I must have removed the carriage return when playing with the strings. Sorry for the trouble. This is great, thanks!

Hi, I’ve used the code posted by @dislam, and changed the “hello_client” to “hello_client\n”

However, from the terminator, it shows this:

Client received from server:   hello_client

Client received from server:   hello_client

Server sends to client:           hello_client

Err: nil

Server sends to client:           hello_client

Err: nil

This chunk of strings kept running infinitely. Any help?

Thanks!

I can’t see your code so I’m going to have to make a general statement assuming you have pretty much copy and pasted the code above.

In the code above, the only way you would see “hello_client” over and over is if somehow the client was connecting to the server over and over and creating a new socket on each connection.

The mating of the devices should occur before the client loop begins. Once the socket object is created, it will persist until you dereference it.

@Mark

Yea I’ve copied the exact code posted above. Hmm… So the continuous loop occurs means that my devices are still not connected to each other? Are there any working examples out here which I can refer to?

Thanks!

Actually, if the other device is getting the message they are connected. What I think is happening is that you are connecting more than once.

From the code above, my best guess is that it is because you are using a “tap” listener and holding the button down. If you use a “touch” listener and make it connect on release then it should only connect once.

Thanks Mark for the amazing tutorial on creating a multiplayer connection.  Sorry for bumping this old thread, but it’s very useful and I have a question.

I’m following the example shown by GamingStudio17 and trying to figure out where in the code I would add createClientLoop from the tutorial, to allow the client to receive messages from the server.

For example, currently the server is continuously sending “hello_client” to every client.  So I added the following to the example at the top, but my client does not appear to receive anything:

sendbF = function(event) local sock = connectToServer(server\_ip,1235) createClientLoop(sock,server\_ip,1235) end

That looks ok. It must be something else that is causing the problem. Let me see your socket.send statement.

It’s the same send() operation as in the example:

 for sock, buffer in pairs( clientBuffer ) do for \_, msg in pairs( buffer ) do --might be empty print("Server sends to clients:", msg) local data, err = sock:send( msg ) --send the message to the clients end end

If I check the value of “err” from the sock:send() command, it is “nil”.

The clientBuffer array is in the form:  clientBuffer[client] = { “hello_client” }, where a client is the value returned by tcp:accept().

I’m using this for the createClientLoop():

createClientLoop = function( sock, ip, port ) local buffer = {} local clientPulse local function cPulse() local allData = {} local data, err -- Get line by line of data and store in allData repeat data, err = sock:receive() if data then allData[#allData+1] = data end if ( err == "closed" and clientPulse ) then --try again if connection closed print("Client connection closed. Re-connect and try to receive again.") connectToServer( ip, port ) data, err = sock:receive() if data then allData[#allData+1] = data end end until not data if ( #allData \> 0 ) then for i, thisData in ipairs( allData ) do print( "Client received from server:", thisData ) --------------------------- --react to incoming data --------------------------- end end -- TO DO: Set buffer for sending for i, msg in pairs( buffer ) do local data, err = sock:send(msg) if ( err == "closed" and clientPulse ) then --try to reconnect and resend print("Client connection closed. Re-connect and try to send again.") connectToServer( ip, port ) data, err = sock:send( msg ) end end end --pulse 10 times per second clientPulse = timer.performWithDelay( 100, cPulse, 0 ) local function stopClient() timer.cancel( clientPulse ) --cancel timer clientPulse = nil sock:close() end return stopClient end

As you can see from the above code (which is pretty much the same as your example), I never see the line “Client received from server”.

It appears nothing is in your buffer. For a quick and dirty experiment change local buffer = {} to local buffer = {“message to server\n”}

I already did send a message to the server when I called connectToServer, I had verified that it worked. The problem I’m having is that the client is not *receiving* from the server after the server had done its send() with the “hello_client” message.

Ok, so you are sure they are connected (sock is not nil) and you are sure that the server received a message from the client? One thing that you need to be aware of is that when a message is sent it “succeeds” if it gets out to the internet. if for example the other device is off but didn’t disconnect from the server the server won’t know that. The message will be lost. Thus, I like to index my messages and have the server echo back that the message was received. This is not automatic. Also if you send three messages you can’t control which one gets there first, so again an index will help. If your server is capturing information and it got 1 and 3 the. It knows to wait for 2. Its not a big deal if it’s not on the pulse when the message gets there. As long as the socket is open you will process the message on the next pulse. But the socket needs to be ready to receive a message. This whole system is a bit nuanced and there are a lot of things that can go wrong when two computers talk to each other so you just kind of have to verify everything.

Thanks for your quick replies.  Yes, I did make sure the server was receiving from the client.  In the createServer method, where it checks for data from the clients, I made it echo what it had received, and verified that it had matched the info that the client had sent.   Next, when the server sends the “hello_client”, it does this continuously and it doesn’t appear that the client receives anything because the client’s receive-data buffer is empty when I try to echo it.

I understand what you mean by the messages not arriving; in fact I’m thinking of doing a ‘request’ and ‘ack’ method where the server and client both ensure that the messages had arrived; or I’ll just send a burst of like 3 messages instead of 1.

Here’s my entire code, which is based on the the original post.  This code is ready to run and shows output on the console:

main.lua:

local socket = require("socket") local server = require("server") server\_ip = 0 local getClientIP local findServer local connectToServer local createClientLoop getClientIP = function() local s = socket.udp() --creates a UDP object s:setpeername( "74.125.115.104", 80 ) --Google website local ip, sock = s:getsockname() print( "Client IP / socket:", ip, sock ) return ip end findServer = function() local newServers = {} local msg = "AwesomeGameServer" local listen = socket.udp() listen:setsockname( "226.192.1.1", 1234 ) --this only works if the device supports multicast local name = listen:getsockname() if ( name ) then --test to see if device supports multicast listen:setoption( "ip-add-membership", { multiaddr="226.192.1.1", interface = getClientIP() } ) else --the device doesn't support multicast so we'll listen for broadcast listen:close() --first we close the old socket; this is important listen = socket.udp() --make a new socket listen:setsockname( getClientIP(), 1234 ) --set the socket name to the real IP address end listen:settimeout( 0 ) --move along if there is nothing to hear local stop local counter = 0 --pulse counter local function look() repeat local data, ip, port = listen:receivefrom() --print( "data: ", data, "IP: ", ip, "port: ", port ) if data and data == msg then if not newServers[ip] then print( "Client hears a server at IP " .. ip .. " and port " .. port ) local params = { ["ip"]=ip, ["port"]=1235 } newServers[ip] = params server\_ip = ip end end until not data counter = counter + 1 if counter == 20 then --stop after 2 seconds stop() end end --pulse 10 times per second local beginLooking = timer.performWithDelay( 100, look, 0 ) function stop() timer.cancel( beginLooking ) --evaluateServerList( newServers ) --do something with your found servers listen:close() --never forget to close the socket! end end connectToServer = function( ip, port ) print("Sending message to IP " .. ip .. " and port " .. port) local sock, err = socket.connect( ip, port ) if sock == nil then return false end sock:settimeout( 0 ) sock:setoption( "tcp-nodelay", true ) --disable Nagle's algorithm sock:send("CLIENT " ..ip .. " " .. port .. "\n") return sock end createClientLoop = function( sock, ip, port ) local buffer = {} local clientPulse local function cPulse() local allData = {} local data, err -- Get line by line of data and store in allData repeat data, err = sock:receive() if data then allData[#allData+1] = data end if ( err == "closed" and clientPulse ) then --try again if connection closed print("Client connection closed. Re-connect and try to receive again.") connectToServer( ip, port ) data, err = sock:receive() if data then allData[#allData+1] = data end end until not data if ( #allData \> 0 ) then for i, thisData in ipairs( allData ) do print( "Client received from server:", thisData ) --------------------------- --react to incoming data --------------------------- end end -- TO DO: set a buffer to send, depending on action for i, msg in pairs( buffer ) do local data, err = sock:send(msg) if ( err == "closed" and clientPulse ) then --try to reconnect and resend print("Client connection closed. Re-connect and try to send again.") connectToServer( ip, port ) data, err = sock:send( msg ) end end end --pulse 10 times per second clientPulse = timer.performWithDelay( 100, cPulse, 0 ) local function stopClient() timer.cancel( clientPulse ) --cancel timer clientPulse = nil sock:close() end return stopClient end ------------------------------------------------------------------------------------ ----------------------- server.createServer() ----------------------- -- server\_b local serverb = display.newText("Advertise server", 400, 150, "pixelDR", 36) serverb:setTextColor(255, 0, 0) -- Advertise the server ----------------------------- serverbF = function(event) server.advertiseServer() end ----------------------------- serverb:addEventListener("tap",serverbF) -- client\_b local clientb = display.newText("Get client IP", 400, 200, "pixelDR", 36) clientb:setTextColor(0, 255, 0) -- Client finds out its IP address ----------------------- clientbF = function(event) findServer() end ----------------------- clientb:addEventListener("tap",clientbF) -- send\_b local sendb = display.newText("Connect to Server", 400, 290, "pixelDR", 36) sendb:setTextColor(255, 0, 255) -- Connect to server ----------------------- sendbF = function(event) -- Get a session ID ("sock") from server local sock = connectToServer(server\_ip,1235) createClientLoop(sock,server\_ip,1235) end ----------------------- sendb:addEventListener("tap",sendbF)

server.lua:

local S = {} local socket = require( "socket" ) local clientList = {} local clientBuffer = {} S.getServerIP = function() local s = socket.udp() s:setpeername( "74.125.115.104", 80 ) local ip, sock = s:getsockname() print( "Server IP / socket:", ip, sock ) return ip end S.createServer = function() local tcp, err = socket.bind( S.getServerIP(), 1235 ) --create a server object tcp:settimeout( 0 ) local function sPulse() ------------------------------------------------------ -- Check for available clients ------------------------------------------------------ repeat local client = tcp:accept() --allow a new client to connect if client then print( "Server detected a client" ) client:settimeout( 0 ) --just check the socket and keep going --TO DO: implement a way to check to see if the client has connected previously --consider assigning the client a session ID and use it on reconnect. clientList[#clientList+1] = client -- TO DO clientBuffer[client] = { "hello\_client" } --just including something to send below end until not client -- Check to see which client connections are available local ready, writeReady, err = socket.select( clientList, clientList, 0 ) ------------------------------------------------------- -- Look for data from clients ------------------------------------------------------- if err == nil then for i = 1, #ready do --list of clients who are available local client = ready[i] local allData = {} --this holds all lines from a given client -- From current client, get line by line of data and store in allData repeat local data, err = client:receive() -- get a line of data from the client, if any if data then allData[#allData+1] = data end until not data if ( #allData \> 0 ) then --figure out what the client said to the server -- Get each line from allData for i, thisData in ipairs( allData ) do print( "Server received from client:", thisData ) --------------------- -- Do stuff with data --------------------- end end end ------------------------------------------------------ -- Send whatever is in the server's buffer ------------------------------------------------------ for sock, buffer in pairs( clientBuffer ) do -- Grab each line from the buffer meant for current client, and send it for \_, msg in pairs( buffer ) do --might be empty print("Server sends to clients:", msg) local data, err = sock:send( msg ) --send the message to the clients print("Err: ",err) print("\n") end end end end -- Call above function every 100 ms local serverPulse = timer.performWithDelay( 100, sPulse, 0 ) local function stopServer() timer.cancel( serverPulse ) --cancel timer tcp:close() for i, v in pairs( clientList ) do v:close() end end return stopServer end S.advertiseServer = function() print("Advertise server") local send = socket.udp() send:settimeout( 0 ) --this is important (how long to wait before moving on) local stop local counter = 0 --using this, we can advertise our IP address for a limited time local function broadcast() local msg = "AwesomeGameServer" --multicast IP range from 224.0.0.0 to 239.255.255.255 send:sendto( msg, "226.192.1.1", 1234 ) --not all devices can multicast so it's a good idea to broadcast too --however, for broadcast to work, the network has to allow it send:setoption( "broadcast", true ) --turn on broadcast send:sendto( msg, "255.255.255.255", 1234 ) send:setoption( "broadcast", false ) --turn off broadcast counter = counter + 1 if ( counter == 80 ) then --stop after 8 seconds stop() -- variable to a function end end --pulse 10 times per second local serverBroadcast = timer.performWithDelay( 100, broadcast, 0 ) stop = function() timer.cancel( serverBroadcast ) --cancel timer stop = nil print("Stop server broadcast") end end return S

Try changing “hello_client” to “hello_client\n”. I think the socket on the client side is still waiting for more data.

[quote name=“mark_steelman” post=“286579” timestamp=“1425905259”]Try changing “hello_client” to “hello_client\n”. I think the socket on the client side is still waiting for more data.[/quote] Ah, that worked :slight_smile: How did I miss that …I must have removed the carriage return when playing with the strings. Sorry for the trouble. This is great, thanks!

I tried this demo on two separate versions of corona to try to test this code it works fine on one simulator but when is try to have two simulators open the code i get this error "

File: server.lua

Line: 22

Attempt to index local ‘tcp’ (a nil value)"

stack traceback:

server.lua:22: in function ‘createServer’

main.lua:161: in main chunk"

here is my code

--main.lua local socket = require("socket") local server = require("server") server\_ip = 0 local getClientIP local findServer local connectToServer local createClientLoop getClientIP = function() local s = socket.udp() --creates a UDP object s:setpeername( "74.125.115.104", 80 ) --Google website local ip, sock = s:getsockname() print( "Client IP / socket:", ip, sock ) return ip end findServer = function() local newServers = {} local msg = "AwesomeGameServer" local listen = socket.udp() listen:setsockname( "226.192.1.1", 1234 ) --this only works if the device supports multicast local name = listen:getsockname() if ( name ) then --test to see if device supports multicast listen:setoption( "ip-add-membership", { multiaddr="226.192.1.1", interface = getClientIP() } ) else --the device doesn't support multicast so we'll listen for broadcast listen:close() --first we close the old socket; this is important listen = socket.udp() --make a new socket listen:setsockname( getClientIP(), 1234 ) --set the socket name to the real IP address end listen:settimeout( 0 ) --move along if there is nothing to hear local stop local counter = 0 --pulse counter local function look() repeat local data, ip, port = listen:receivefrom() --print( "data: ", data, "IP: ", ip, "port: ", port ) if data and data == msg then if not newServers[ip] then print( "Client hears a server at IP " .. ip .. " and port " .. port ) local params = { ["ip"]=ip, ["port"]=1235 } newServers[ip] = params server\_ip = ip end end until not data counter = counter + 1 if counter == 20 then --stop after 2 seconds stop() end end --pulse 10 times per second local beginLooking = timer.performWithDelay( 100, look, 0 ) function stop() timer.cancel( beginLooking ) --evaluateServerList( newServers ) --do something with your found servers listen:close() --never forget to close the socket! end end connectToServer = function( ip, port ) print("Sending message to IP " .. ip .. " and port " .. port) local sock, err = socket.connect( ip, port ) if sock == nil then return false end sock:settimeout( 0 ) sock:setoption( "tcp-nodelay", true ) --disable Nagle's algorithm sock:send("CLIENT " ..ip .. " " .. port .. "\n") return sock end createClientLoop = function( sock, ip, port ) local buffer = {} local clientPulse local function cPulse() local allData = {} local data, err -- Get line by line of data and store in allData repeat data, err = sock:receive() if data then allData[#allData+1] = data end if ( err == "closed" and clientPulse ) then --try again if connection closed print("Client connection closed. Re-connect and try to receive again.") connectToServer( ip, port ) data, err = sock:receive() if data then allData[#allData+1] = data end end until not data if ( #allData \> 0 ) then for i, thisData in ipairs( allData ) do print( "Client received from server:", thisData ) --------------------------- --react to incoming data --------------------------- end end -- TO DO: set a buffer to send, depending on action for i, msg in pairs( buffer ) do local data, err = sock:send(msg) if ( err == "closed" and clientPulse ) then --try to reconnect and resend print("Client connection closed. Re-connect and try to send again.") connectToServer( ip, port ) data, err = sock:send( msg ) end end end --pulse 10 times per second clientPulse = timer.performWithDelay( 100, cPulse, 0 ) local function stopClient() timer.cancel( clientPulse ) --cancel timer clientPulse = nil sock:close() end return stopClient end ------------------------------------------------------------------------------------ ----------------------- server.createServer() ----------------------- -- server\_b local serverb = display.newText("Advertise server", display.contentCenterX, display.contentCenterY-100, nil, 36) serverb:setTextColor(255, 0, 0) -- Advertise the server ----------------------------- serverbF = function(event) server.advertiseServer() end ----------------------------- serverb:addEventListener("tap",serverbF) -- client\_b local clientb = display.newText("Get client IP", display.contentCenterX, display.contentCenterY-50, nil, 36) clientb:setTextColor(0, 255, 0) -- Client finds out its IP address ----------------------- clientbF = function(event) findServer() end ----------------------- clientb:addEventListener("tap",clientbF) -- send\_b local sendb = display.newText("Connect to Server", display.contentCenterX, display.contentCenterY, nil, 36) sendb:setTextColor(255, 0, 255) -- Connect to server ----------------------- sendbF = function(event) -- Get a session ID ("sock") from server local sock = connectToServer(server\_ip,1235) createClientLoop(sock,server\_ip,1235) end ----------------------- sendb:addEventListener("tap",sendbF)

--server.lua local S = {} local socket = require( "socket" ) local clientList = {} local clientBuffer = {} local tableTest= {} tableTest[1]= "hi\n" S.getServerIP = function() local s = socket.udp() s:setpeername( "74.125.115.104", 80 ) local ip, sock = s:getsockname() print( "Server IP / socket:", ip, sock ) return ip end S.createServer = function() local tcp, err = socket.bind( S.getServerIP(), 1235 ) --create a server object tcp:settimeout( 0 ) local function sPulse() ------------------------------------------------------ -- Check for available clients ------------------------------------------------------ repeat local client = tcp:accept() --allow a new client to connect if client then print( "Server detected a client" ) client:settimeout( 0 ) --just check the socket and keep going --TO DO: implement a way to check to see if the client has connected previously --consider assigning the client a session ID and use it on reconnect. clientList[#clientList+1] = client -- TO DO clientBuffer[client] = { tableTest[1] } --just including something to send below end until not client -- Check to see which client connections are available local ready, writeReady, err = socket.select( clientList, clientList, 0 ) ------------------------------------------------------- -- Look for data from clients ------------------------------------------------------- if err == nil then for i = 1, #ready do --list of clients who are available local client = ready[i] local allData = {} --this holds all lines from a given client -- From current client, get line by line of data and store in allData repeat local data, err = client:receive() -- get a line of data from the client, if any if data then allData[#allData+1] = data end until not data if ( #allData \> 0 ) then --figure out what the client said to the server -- Get each line from allData for i, thisData in ipairs( allData ) do print( "Server received from client:", thisData ) --------------------- -- Do stuff with data --------------------- end end end ------------------------------------------------------ -- Send whatever is in the server's buffer ------------------------------------------------------ for sock, buffer in pairs( clientBuffer ) do -- Grab each line from the buffer meant for current client, and send it for \_, msg in pairs( buffer ) do --might be empty print("Server sends to clients:", msg) local data, err = sock:send( msg ) --send the message to the clients print("Err: ",err) print("\n") end end end end -- Call above function every 100 ms local serverPulse = timer.performWithDelay( 100, sPulse, 0 ) local function stopServer() timer.cancel( serverPulse ) --cancel timer tcp:close() for i, v in pairs( clientList ) do v:close() end end return stopServer end S.advertiseServer = function() print("Advertise server") local send = socket.udp() send:settimeout( 0 ) --this is important (how long to wait before moving on) local stop local counter = 0 --using this, we can advertise our IP address for a limited time local function broadcast() local msg = "AwesomeGameServer" --multicast IP range from 224.0.0.0 to 239.255.255.255 send:sendto( msg, "226.192.1.1", 1234 ) --not all devices can multicast so it's a good idea to broadcast too --however, for broadcast to work, the network has to allow it send:setoption( "broadcast", true ) --turn on broadcast send:sendto( msg, "255.255.255.255", 1234 ) send:setoption( "broadcast", false ) --turn off broadcast counter = counter + 1 if ( counter == 80 ) then --stop after 8 seconds stop() -- variable to a function end end --pulse 10 times per second local serverBroadcast = timer.performWithDelay( 100, broadcast, 0 ) stop = function() timer.cancel( serverBroadcast ) --cancel timer stop = nil print("Stop server broadcast") end end return S

thanks,

Scott

Hi, I’ve used the code posted by @dislam, and changed the “hello_client” to “hello_client\n”

However, from the terminator, it shows this:

Client received from server:   hello_client

Client received from server:   hello_client

Server sends to client:           hello_client

Err: nil

Server sends to client:           hello_client

Err: nil

This chunk of strings kept running infinitely. Any help?

Thanks!

I can’t see your code so I’m going to have to make a general statement assuming you have pretty much copy and pasted the code above.

In the code above, the only way you would see “hello_client” over and over is if somehow the client was connecting to the server over and over and creating a new socket on each connection.

The mating of the devices should occur before the client loop begins. Once the socket object is created, it will persist until you dereference it.