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
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