UDPIPE Description

Connects clients and servers with UDP.

When connecting, is uses handshaking, and when connected, it uses PING packets to discover closed connections.  When the connection is stalled, it can queue the messages, which are sent out after the connection is reestablished.

You can use a subclass instance and implement callbacks to react on new packets.

Summary
UDPIPE DescriptionConnects clients and servers with UDP.
The minimal exampleHere is an example of a simple client and server using UDPIPE.
UDPIPE ProtocolExample of a raw network protocol when connecting UDPIPE client and server.
Using callbacksFor any real life application you need to use UDPIPE.Callbacks.
Useful UDPIPE methods

The minimal example

Here is an example of a simple client and server using UDPIPE.

Client side

UDPIPE=require 'UDPIPE'
client=UDPIPE()
host, port='127.0.0.1', 1234
client:connect(host, port)

function client:onConnect(sock)
  self:send("HelloWorld")
end

function client:onNewMessage(msg)
  print('Got message:', msg)
end

while true do
  client:step()
end

Server side

UDPIPE=require 'UDPIPE'
server=UDPIPE()
host, port='127.0.0.1', 1234
server:start(port, host)

function server:onNewMessage(msg, sock)
  self:send('Reply from server: '..msg, sock)
end

while true do
  server:step()
end

UDPIPE Protocol

Example of a raw network protocol when connecting UDPIPE client and server.  You can sniff network packets with tcpdump/wireshark to see it for yourself.

C->S: HELLO token
S->C: CONNECT IP PORT
S->C: GO AWAY!

C->SC: CONNECT
SC->C: CONNECTED

C->SC: PING
SC->C: PONG

SC->C: PING
C->SC: PONG

C->SC: data
SC->C: data

C->SC: CLOSE
SC->C: CLOSED

SC->C: CLOSE
C->SC: CLOSED

Here the letters mean

  • C - client side (private IP address and a randomly generated port)
  • S - server side (public IP address and a known serwer port)
  • SC - server side (the same public IP address, and different, randomly generated port)

The “S” server socket is used only for initializing the connection.  The “SC” server socket is used for all data transmission.

The workflow is like this

  • The client connects to the server’s IP:port with a “HELLO token”, where token is valid only for this game/program.  If the server thinks the token was wrong, it sends cle client away with “GO AWAY!” message.  If the token was OK, the server opens a new socket (on random port), and sends the new pair IP (the same) and PORT (just generated) to the client.
  • When the client gets the new port, it “connects” to this final port by sending “CONNECT”.  If the server accepts the connection (a packet from this client), it acks by sending back “CONNECTED”.  From this point both client and server can assume that the connection between them is established.
  • Both client and server can PING the other side: after PING packet is received, UDPIPE sends back a PONG packet.  This is used to check if the other side is still alive and responding to packets.
  • During normal operation, both client and server can send arbitrary data.  The data can be arbitrary string, except those defined/described above as protocol commands.
  • When one side wants to close the connection, it sends the “CLOSE” message.  When the “CLOSE” message arrives at either side, it acks closing connection by sending “CLOSED” message, and then closes the network socket.  Also, when the other side stops working (does not send in any packets, and does not respond do PING packets in 30 secs), it also gets “CLOSED” (just in case) and the socket is closed.

Using callbacks

For any real life application you need to use UDPIPE.Callbacks.  Check the API in the documentation.  When implementing your code, you can change:

UDPIPE=require 'UDPIPE'

to this:

UDPIPE=require 'UDPIPEVERBOSE'

And when you run your code from the text console, you get some debugging messages which will help you getting things up.

Short callbacks overview

  • UDPIPE.onNewClient - used only on server side.  Called when a new client is connected.  It is used internally for adding a new client socket to the pool.  Here you can increase the counter of connected users, or check if the IP should be banned and then close the connection etc.
  • UDPIPE.onNewMessage - used on both sides.  Obviously the most used callback.  This is where your game/application messages are exchanged.  According to those messages you shuld call your server/client functions.  To simplify game development, you can use UDPROXY instead of directly messing with this callback.
  • UDPIPE.onConnect - used on both sides.  For client side, you should send your initial data here, like authorization, requesting the game state from the server etc.  For server side, you can increase the counter of connected clients, send some initial data (game state, message-of-the-day etc).
  • UDPIPE.onDisconnect - used on both sides.  For client side, it means the server is “disconnected” (stops responding).  You can mark your player as offline.  The client will try to reconnect, unless you call UDPIPE.close.  For client side, it means that one of the client connections was closed, so you may remove the player from the list, or mark him as unavailable.
  • UDPIPE.onClose - used on both sides.  It means that the other side intentionally closed the connection, so the client should no longer try to connect to the server (reconnecting is switched off for you), so the player can be informed about this.  For server side it means that the client probably will not reconnect, so you can clean all the data for that connection (logout the player etc).
  • UDPIPE.onConnecting - used on server side, when the client is half-way during the handshake process.  You probably don’t want to use this.  I may remove it in the future, unless there is useful case for it.
  • UDPIPE.onStalled/UDPIPE.onUnstalled - used on both sides.  When there is no packet within 10 secs from the other side, the onStalled callback is called, and the PING packet is sent to the other side.  If there is any incoming packet afterwards, the unStalled is called.  If there is no packet within 30 secs, the onDisconnect is called.  You may use this callback to warn the client about connection problems etc.
  • UDPIPE.onMaxClients - used on server side.  Called when there are more than 1000 clients (this is arbitrary number hidden in the code, just to be safe).  You know that there is lots of clients, or your server is being flooded.
  • UDPIPE.onPing/UDPIPE.onPong - used on both sides.  Called when relevant message arrives.  You probably don’t want to use those callbacks, as everything is done for you automatically.
  • UDPIPE.onBadToken - used on server side.  Called when the client uses bad “HELLO <token>” sequence.  Which could mean he want to connect to a different game (token can be a game name), or it is not related UDP packet.  For simple games you can skip this.

Useful UDPIPE methods

Here are some UDPIPE methods you can use in your code

  • UDPIPE.setTimeout - used on both sides.  If there is outer main loop (like in your game client), this timeout should be small.  Probably you can leave it as is.
  • UDPIPE.setToken - used on both sides.  The server will only accept connections with this token, so the client must set this before connecting to the server.  The default token is “default”.  You can set different tokens for different applications/games to minimize confusions.
  • UDPIPE.start - used on server side.  Starts the server (opens the listening port)
  • UDPIPE.step - used on both sides.  Keeps UDPIPE running.  You should call it in your main loop.
  • UDPIPE.connect - used on client side.  Starts connecting to the server.  As this is asynchronous process, you should put your code in onConnected, if you want to be sure you are in connected state.  If there is a timeout, the client will keep reconnecting untill you call UDPIPE.close.
  • UDPIPE.send - used on both sides.  It sends a message to the server, or to one of the clients (in case of server side) referenced by a socket.
  • UDPIPE.sendAll - used on server side.  It sends a message to all of the clients.  Used to update the game state etc.
  • UDPIPE.ping - used on both sides.  Send a ping message to the other side.  It will answer with PONG for you.  You don’t need it probably.
  • UDPIPE.getSentPackets/UDPIPE.getReceivedPackets - used on both sides.  Gets the number of packets sent/received.  Useful for debugging only.

So now you can code your multiplayer games.

function M:onNewClient(msg,
ip,
port,
ipc,
portc)
Called when new client is connected.
function M:onNewMessage(msg,
sock)
Called when new message arrives.
Simplifies calling UDPIPE, by serializing command names and its arguments, and sending it to the server.
function M:onConnect(sock,
ip,
port)
Called when client connected to the Server, or a new client has connected.
function M:onDisconnect(sock)
Called when a socket is disconnected.
function M:close(skt)
Close the connection.
function M:onClose(sock)
Called when client or server closed the connection.
function M:onConnecting(sock,
ip,
port)
Called when client is connecting to the Server on a final port.
function M:onStalled(sock)
Called when the connection lags.
function M:onUnstalled(sock)
Connection is no longer stalled.
function M:onMaxClients(msg,
ip,
port)
Called when too much client connections is open.
function M:onPing(sock)
Called when PING packet is received.
function M:onPong(sock)
Called when PONG packet is received.
function M:onBadToken(msg,
ip,
port)
Called when bad token is received in HELLO packet.
function M:setTimeout(t)
Sets the timeout for all current and newly opened sockets.
function M:setToken(t)
Sets the token for handshaking.
function M:start(port,
host,
timeout)
Starts the server.
function M:step(dt)
Keeps the client/server running.
function M:connect(host,
port,
timeout)
Connects as a client to the server.
function M:send(msg,
sock)
Sends a message to a connected socket.
function M:sendAll(msg)
Sends a message to all connected sockets (clients).
function M:ping(sock)
Sends a ping message to server (in client mode) or all connected sockets (in server mode).
function M:getSentPackets()
Returns the number of packets sent out.
function M:getReceivedPackets()
Returns the number of packets received.
Close