UDP APIs

I have written a function that listens to incoming data and also checks if a data string is due to be sent to the server (data string present in UDPSendBuffer) then it will send the packet and goes back to listening mode after, and this is a self-calling routine. The listener doesn’t work, data are reaching the server but when sending the other way around nothing is showing in the receivefrom(), however I noticed that the socket doesn’t timeout when there is data coming from the server.

function send_UDP () 
       if UDPSendBuffer == nil then
              local UDPRec = assert(socket.udp())
        UDPRec:setsockname("192.168.13.31", UDP_Port)
        UDPRec:settimeout(2)
             for i = 1 , 5 do              
              local ServerData, ip, port = UDPRec:receivefrom()
              end
        print ("#########ACK",ServerACK, ip, port)
        UDPRec:close()
      send_UDP ()
       elseif UDPSendBuffer ~= nil then
              local UDPBuffer = UDPSendBuffer
              UDPSendBuffer = nil
              local host, port = UDP_IP_Address, UDP_Port   
              local UDP = assert(socket.udp())
           UDP:setpeername(host, port)
           local UDPreturn = UDP:send(UDPBuffer)
           print("###############", UDPBuffer)
           if UDPreturn ~= string.len(UDPBuffer) then
                   print ("UDP sending failed")
                   UDP:close()
      else
             UDP:close()
             send_UDP ()
        end  
       end

Hi m2mconnectivity13,

You code has a complex workflow already. In order to actually test the UDP API on your setup could you run this very simple app:

local sched     = require "sched"   -- Lua scheduling and synchronization lib
local socket    = require "socket"  -- Socket services


--------------------------------------------------------------------------------
--
-- 
function main ()

	local sock = assert(socket.udp())
	assert(sock:setsockname("*", 59577))
	assert(sock:settimeout(5))
	print("Now waiting for datagrams")
	while true do
		local p, err = sock:receivefrom()
		if p then
			if p:match("stop") then print("bye bye") os.exit(0) end -- exit the application when it receives a packet containing the word 'stop'
			print(string.format("Received a datagram: [%q]", p)) -- %q make sure the string is pritable (i.e. escape non ASCII chars)
		else
			-- p is nil, and error was returned! (timeout is an error)
			print("Socket receivefrom() returned an error:", err)
		end
	end
end


--------------------------------------------------------------------------------
-- Schedule the main function, and launch the scheduler main loop
sched.run(main)
sched.loop()

This program will just wait for incoming datagram and print them. The socket has a 5 s timeout, so a print is done every 5 seconds at most, but all this is inside an infinite loop. If a received packet contains the word ‘stop’ it will close the application.

To send datagram to the app I used netcat utility on Linux: “nc -u 192.168.14.31 59577” (type what you want, and press enter to actually send the datagram)

One important aspect to understand when using USP API is that datagram are not bufferized by the system. You must have a thread blocked on a receive() or receivefrom() call before the other part send the datagram. If nothing ‘wait’ on a receive call the datagram is simply discarded on reception. (This is different from TCP socket)

If you need you program to do other things while you wait for a datagram, you have to create another thread using the sched.run() API.

the data that i will be sending to the server will be coming from within the code (in fact it will be captured on the serial port) so how can i incorporate the send function in the code you have provided, i will need to connect to the server IP, same port though.

You can create the udp socket object before calling the send and receive function (use the same object).

I do not know the protocol and use case, so it is hard give a precise answer. But if your protocol is request-answer type, then you can just have in (pseudo code):

Create UDP socket
loop
Send your datagram
Wait for the response
Do adequate processing given the answer

The code example I provided in the other post is really for you to try in your setup, and make sure the UDP API is working as expected.

The important information is the udp object does not bufferize any data, so your code must be calling receive() before the UDP datagram is sent to the interface.

i think i got it, not sure why previously it wasnt allowing me to reuse the same port, it was giving me an error when i attempt to reopen the socket.
I have added the send routine which will run if there is data in the send buffer, please let me know if there are any concerns?

local sock = assert(socket.udp())
assert(sock:setsockname("*", 20500))
assert(sock:settimeout(5))
print(“Now waiting for datagrams”)
while true do
local p, err = sock:receivefrom()
if p then
if p:match(“stop”) then print(“bye bye”) os.exit(0) end – exit the application when it receives a packet containing the word ‘stop’
print(string.format(“Received a datagram: [%q]”, p)) – %q make sure the string is pritable (i.e. escape non ASCII chars)
else
– p is nil, and error was returned! (timeout is an error)
print(“Socket receivefrom() returned an error:”, err)
end
if UDPSendBuffer ~= nil then
local host, port = UDP_IP_Address, UDP_Port
local UDP = assert(socket.udp())
UDP:setpeername(host, port)
local UDPreturn = UDP:send(UDPSendBuffer)
print("###############", UDPSendBuffer)
DPSendBuffer = nil
UDP:close()
end
end
end

Do you have to send to different peer IP/port for each datagram ? If not I would recommend to put that

local host, port = UDP_IP_Address, UDP_Port
        local UDP = assert(socket.udp())
        UDP:setpeername(host, port)

Outside of the while loop. Other than that no concerns, just remove code you do not need (the ‘stop’ match was just for example)

Another comment: you may use a single udp socket in your example.