Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Rails support a neat way of listening to a UDP socket?

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.

like image 942
Paul Keeble Avatar asked Dec 28 '09 00:12

Paul Keeble


2 Answers

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.

like image 181
Azeem.Butt Avatar answered Oct 18 '22 22:10

Azeem.Butt


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.

like image 1
Wayne Conrad Avatar answered Oct 18 '22 23:10

Wayne Conrad