This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Generic TCP Server for external requests
#1
I am not a big fan of the example : http://openrb.com/example-lm2-as-tcp-ser...-requests/

It uses the following principle :
- the resident script is the TCP server :
  - manages TCP clients
  - listen on UDP for internal LM requests
- the resident script do receive client request and process them
- other LM scripts/events use UDP to communicate to the TCP server and transmit data to be sent

For me, there is some limitations :
- only 5 messages per second are read by TCP server on the UDP side
- data can be lost with UDP

As I need to send a lot of data, I did use the internal storage instead of UDP.
I am sharing this as a generic TCP server that can be customized for every need.

So the idea is the following :
- the resident script is the TCP server :
  - manage TCP clients
  - read the internal storage for internal LM requests
- the resident script do receive client request and process them
- other LM scripts/events use internal storage to communicate to the TCP server and transmit data to be sent


First, the User Library :
Code:
-- TCP Server user library

--general debug
tcp_debug = false
--networking debug
tcp_debug_tcp = false
-- additionnal debug
tcp_debug_verbose = false

--store a message to be send into the queue
function tcp_queue(message)
 if (tcp_debug_verbose) then
   alert("tcp_queue : "..message)
 end

 local tcp_Q = storage.get('tcpQ')
 table.insert(tcp_Q,message)
    storage.set('tcpQ', tcp_Q)
end

Now the resident script with sleep interval 0 :
Code:
require('copas')

--[[
Resident script for TCP server
Manage client connexions
Receive requests from clients
Also send events through tcpQ storage

debug variables are set in the user library
]]--

--communication port to listen on
local tcp_port = 6789

if (tcp_debug) then
 alert ("TCP Server start")
end


-- send a message to the peers
function tcp_sendmessage(message)
 if (tcp_debug_tcp) then
   alert ("tcp_sendmessage : ".. message)
    end
 for id, sock in pairs(tcp_clients) do
   sock:send(message .. '\r\n')
 end
end

   
-- incoming data handler, manage each message sent by clients to LM
function tcp_datahandler(sock, data)
 local ip, port
 ip, port = sock:getpeername()
   
 if tcp_debug_tcp then
   alert('tcp_datahandler receive data from %s:%d - %s', ip, port, data)
 end

-- add your code to process data

end


-- connection handler, manage new peers
function tcp_connhandler(sock)

 -- enable keep-alive to check for disconnect events
 sock:setoption('keepalive', true)

 local ip, port, data, err, id

 -- get ip and port from socket
 ip, port = sock:getpeername()

 -- client id
 id = string.format('%s:%d', ip, port)

 alert('tcp_connhandler connection from %s', id)

 -- save socket reference
 tcp_clients[ id ] = sock

 -- main reader loop
 while true do
   -- wait for single line of data (until \n, \r is ignored)
   data, err = copas.receive(sock, '*l')

   -- error while receiving
   if err then
     alert('tcp_connhandler closed connection from %s:%d', ip, port)
     -- remove socket reference
     tcp_clients[ id ] = nil
     return
   end

   -- handle data frame
   tcp_datahandler(sock, data)
 end
end



-- init server handler
if not tcp_ready then
 
 if (tcp_debug) then
   alert ("TCP Server init start")
 end

    -- list of client sockets
 tcp_clients = {}

 --variable for the queue
 tcp_Q = {}
 --empty the storage queue
 storage.set('tcpQ', tcp_Q)

 -- bind to port
 tcp_tcpserver = socket.bind('*', tcp_port)

 -- error while binding, try again later
 if not tcp_tcpserver then
   os.sleep(5)
   error('tcp server realization init error: cannot bind')
 end

 -- set server connection handler
 copas.addserver(tcp_tcpserver, tcp_connhandler)

 tcp_ready = true
 
 if (tcp_debug) then
   alert ("TCP Server init end")
    end
end

-- loop to manage packets
while true do

 --retreive the queue
 tcp_Q = storage.get('tcpQ')
 storage.set('tcpQ', {})

 --sending the queue
 for index, value in ipairs(tcp_Q) do
   if tcp_debug then
        alert("TCP Server sending item "..tostring(index).." : "..tostring(value))
   end
   tcp_sendmessage(value)
 end

 --wait for tcp request during 0.1s
 copas.step(0.1)
end

if (tcp_debug) then
 alert ("TCP Server closed")
end

Event base script :
Code:
value = knxdatatype.decode(event.datahex, dt.bool)
tcp_queue('Lamp is' .. (value and 'ON' or 'OFF'))

Matthieu
Reply


Messages In This Thread
Generic TCP Server for external requests - by Matt - 14.07.2015, 06:57

Forum Jump: