views:

196

answers:

3

In Rails what would be the best way of integrating a UDP listening process that updated certain elements of the model (specifically its going to be adding rows to one of the tables).

The simple answer seems to be start a thread with the UDP socket object within the same process, but its not clear quite where I should even do that which fits with the rails way. Is there a neat way to start listening to UDP? Specifically I'd love to be able to write a UDPController and have a particular method called on each Datagram message. Ideally I would want to avoid using HTTP over UDP (as it would waste some of what in this case is very precious space) but I am fully in control of the message format so I can provide Rails with any information it would need.

+1  A: 

Rails is a web application framework, not a server daemon framework. Unless you know of a web server that passes UDP packets, I imagine you would have to write and run a separate process and either have it talk to your Rails app via HTTP or just manipulate the database directly.

Azeem.Butt
A: 

You probably want TCPSuper:

http://ruby-doc.org/stdlib/libdoc/socket/rdoc/classes/TCPServer.html

With sockets and all. Not sure if you can integrate directly into Rails, but you can probably built it up as a ruby daemon with a class that mapped to the ActiveRecord model you want. That daemon will do the work up of updating the tables.

(You may also need to make sure that it forks as well, otherwise, you'll have port blocking issues. You can find most of that in the Ruby docs).

Rilindo
A: 

Let me make a pitch for TCP. UDP is a "throw the packet to the wind" protocol which provides no reliability. It finds uses in, for example, voice over IP where the odd dropped packet is acceptable. By using a TCP socket, you can still avoiding using HTTP, plus TCP stack will handle retries & etc. for you.

A TCP server which is launched by inetd is the simplest thing in the world: you write a program that reads from stdin and writes to stdout, then tell inetd to run that program whenever requests come in on a certain port. You won't have to write any network code.

Here's a simple inetd tcp server:

#!/usr/bin/ruby1.8

input = gets
puts "You said: #{input}"

Here's how to tell inetd to run it:

1024            stream  tcp     nowait    wconrad /tmp/tcpserver.rb

This means to listen for tcp connections on port 1024. When they occur, launch /tmp/tcpserver.rb as user wconrad. man inetd.conf for more information.

You can test it with telnet:

$ telnet localhost 1024
Trying 127.0.0.1...
Connected to ceres.
Escape character is '^]'.
Howdy!
You said: Howdy!
Connection closed by foreign host.
$

Or you can use a simple client:

$ cat /tmp/tcpclient.rb
#!/usr/bin/ruby1.8

require 'socket'

t = TCPSocket.new('localhost', 1024)
t.puts "Hello"
t.close_write
puts t.read
t.close

$ /tmp/tcpclient.rb
You said: Hello

and just to show that tcp servers in Ruby are easy:

!/usr/bin/ruby1.8

require 'socket'

def handle_session(socket)
  s = socket.gets
  socket.puts "You said: #{s}"
  socket.close
end

server = TCPServer.new('localhost', 1024)
while (session = server.accept)
  Thread.new do
    handle_session(session)
  end
end

With TCP being so easy, you need a compelling reason to bother with UDP.

Wayne Conrad