# Tutorial:Networking with UDP-TheClient

The complete source for the UDP client

    -- to start with, we need to require the 'socket' lib (which is compiled-- into love). socket provides low-level networking features.local socket = require "socket"

    -- the address and port of the server
    local address, port = "localhost", 12345

    local entity -- entity is what we'll be controlling
    local updaterate = 0.1 -- how long to wait, in seconds, before requesting an update

    local world = {} -- the empty world-state
    local t

    -- love.load, hopefully you are familiar with it from the callbacks tutorial
    function love.load()

    	-- first up, we need a udp socket, from which we'll do all
    	-- out networking.
    	udp = socket.udp()

    	-- normally socket reads block until they have data, or a
    	-- certain amout of time passes.
    	-- that doesn't suit us, so we tell it not to do that by setting the
    	-- 'timeout' to zero
    	udp:settimeout(0)

    	-- unlike the server, we'll just be talking to the one machine,
    	-- so we'll "connect" this socket to the server's address and port
    	-- using setpeername.
    	--
    	-- [NOTE: UDP is actually connectionless, this is purely a convenience
    	-- provided by the socket library, it doesn't actually change the
    	--'bits on the wire', and in-fact we can change / remove this at any time.]
    	udp:setpeername(address, port)

    	-- seed the random number generator, so we don't just get the
    	-- same numbers each time.
    	math.randomseed(os.time())

    	-- entity will be what we'll be controlling, for the sake of this
    	-- tutorial its just a number, but it'll do.
    	-- we'll just use random to give us a reasonably unique identity for little effort.
    	--
    	-- [NOTE: random isn't actually a very good way of doing this, but the
    	-- "correct" ways are beyond the scope of this article. the *simplest*
    	-- is just an auto-count, they get a *lot* more fancy from there on in]

    	entity = tostring(math.random(99999))

    	-- Here we do our first bit of actual networking:
    	-- we set up a string containing the data we want to send (using 'string.format')
    	-- and then send it using 'udp.send'. since we used 'setpeername' earlier
    	-- we don't even have to specify where to send it.
    	--
    	-- thats...it, really. the rest of this is just putting this context and practical use.
    	local dg = string.format("%s %s %d %d", entity, 'at', 320, 240)
    	udp:send(dg) -- the magic line in question.

    	-- t is just a variable we use to help us with the update rate in love.update.
    	t = 0 -- (re)set t to 0
    end

    -- love.update, hopefully you are familiar with it from the callbacks tutorial
    function love.update(deltatime)

    	t = t + deltatime -- increase t by the deltatime

    	-- its *very easy* to completely saturate a network connection if you
    	-- aren't careful with the packets we send (or request!), we hedge
    	-- our chances by limiting how often we send (and request) updates.
    	--
    	-- for the record, ten times a second is considered good for most normal
    	-- games (including many MMOs), and you shouldn't ever really need more
    	-- than 30 updates a second, even for fast-paced games.
    	if t > updaterate then
    		-- we could send updates for every little move, but we consolidate
    		-- the last update-worth here into a single packet, drastically reducing
    		-- our bandwidth use.
    		local x, y = 0, 0
    		if love.keyboard.isDown('up') then 	y=y-(20*t) end
    		if love.keyboard.isDown('down') then 	y=y+(20*t) end
    		if love.keyboard.isDown('left') then 	x=x-(20*t) end
    		if love.keyboard.isDown('right') then 	x=x+(20*t) end

    		-- again, we prepare a packet *payload* using string.format,
    		-- then send it on its way with udp:send
    		-- this one is the move update mentioned above
    		local dg = string.format("%s %s %f %f", entity, 'move', x, y)
    		udp:send(dg)

    		-- and again! this is a require that the server send us an update for
    		--  the world state
    		--
    		-- [NOTE: in most designs you don't request world-state updates, you
    		-- just get them sent to you periodically. theres various reasons for
    		-- this, but theres one *BIG* one you will have to solemnly take note
    		-- of: 'anti-griefing'. World-updates are probably one of biggest things
    		-- the average game-server will pump out on a regular basis, and greifing
    		-- with forged update requests would be simple effective. so they just
    		-- don't support update requests, instead giving them out when they feel
    		-- its appropriate]
    		local dg = string.format("%s %s $", entity, 'update')
    		udp:send(dg)

    		t=t-updaterate -- set t for the next round
    	end

    	-- there could well be more than one message waiting for us, so we'll
    	-- loop until we run out!
    	repeat
    		-- and here is something new, the much anticipated other end of udp:send!
    		-- receive return a waiting packet (or nil, and an error message).
    		-- data is a string, the payload of the far-end's send. we can deal with it
    		-- the same ways we could deal with any other string in lua (needless to
    		-- say, getting familiar with lua's string handling functions is a must.
    		data, msg = udp:receive()

    		if data then -- you remember, right? that all values in lua evaluate as true, save nil and false?

    			-- match is our freind here, its part of string.*, and data is
    			-- (or should be!) a string. that funky set of characters bares some
    			-- explanation, though.
    			-- (need summary of patterns, and link to section 5.4.1)
    			ent, cmd, parms = data:match("^(%S*) (%S*) (.*)")
    			if cmd == 'at' then
    				-- more patterns, this time with sets, and more length selectors!
    				local x, y = parms:match("^(%-?[%d.e]*) (%-?[%d.e]*)$")
    				assert(x and y) -- validation is better, but asserts will serve.

    				-- don't forget, even if you matched a "number", the result is still a string!
    				-- thankfully conversion is easy in lua.
    				x, y = tonumber(x), tonumber(y)
    				-- and finally we stash it away
    				world[ent] = {x=x, y=y}
    			else
    				-- this case shouldn't trigger often, but its always a good idea
    				-- to check (and log!) any unexpected messages and events.
    				-- it can help you find bugs in your code...or people trying to hack the server.
    				-- never forget, you can not trust the client!
    				print("unrecognised command:", cmd)
    			end

    		-- if data was nil, then msg will contain a short description of the
    		-- problem (which are also error id...).
    		-- the most common will be 'timeout', since we settimeout() to zero,
    		-- anytime there isn't data *waiting* for us, it'll timeout.
    		--
    		-- but we should check to see if its a *different* error, and act accordingly.
    		-- in this case we don't even try to save ourselves, we just error out.
    		elseif msg ~= 'timeout' then
    			error("Network error: "..tostring(msg))
    		end
    	until not data

    end

    -- love.draw, hopefully you are familiar with it from the callbacks tutorial
    function love.draw()
    	-- pretty simple, we just loop over the world table, and print the
    	-- name (key) of everything in their, at its own stored co-ords.
    	for k, v in pairs(world) do
    		love.graphics.print(k, v.x, v.y)
    	end
    end

    -- And thats the end of the udp client example.