In short, look at "handle raw events" in the tornado server implementation. You'll write a method which does that but invokes your UDP handler for each call.
Since UDP provides you a complete datagram each time an event is received, its very simple and requires no buffering like the IOStream has to do.
Just try it out, it is the easiest network programming you'll ever do!
The changes you have to make are centered around here:
https://github.com/facebook/tornado/blob/master/tornado/netutil.py#L316
For UDP, we don't call socket.accept() - we merely get some data from
the socket (read the Stephens book to get a better understanding of
why the socket library APIs are different for the different protocol
families).
Without some refactoring it's hard to make generic, but I just pushed
my socket creation and binding into a super "Server" class (for
multiple sockets on a single server, also, so multiple UDP/TCP ports
can be served by the one server), and then handlers into separate
classes again (which in my case are network proxies rather than HTTP
servers).
I changed the factoring so that this method calls the callback with
some data, rather than a connection and an address, so that inner
accept_handler() method looks much like this. Note the trick to get
our local server address also (i.e., the addr/port tuple that socket
is bound to - I need this for internal routing, you may not require
it). The server and client addresses below are both address/port
tuples.
def accept_handler(fd, events):
while True:
try:
server_address = sock.getsockname()
data, client_address = sock.recvfrom(2000) # see note
except socket.error, e:
if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
# No more to read, right now.
return
else:
raise
try:
callback(server_address, client_address, data)
except Exception:
# log an error here
note: if you want to know how much data you should read, rather than
using a constant, you can find out by doing an ioctl for NIOREAD,
which is slightly ugly in Python because there's no API wrapper for
the ioctl, but you can do it like this:
>>> import ctypes, termios, fcntl, socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# bind the socket
>>> size_int = ctypes.c_int()
>>> fcntl.ioctl(s, termios.FIONREAD, size_int)
>>> print size_int.value
0
that's how much data is waiting on my udp socket.socket() object "s".
In theory you might want to do this rather than setting an arbitarily
large value like 9000, but I've never run into this problem.
-a
> On Apr 7, 2012 12:51 AM, "Matt Dawson" <matthew...@gmail.com> wrote:
>>
>> Hi all -
>>
>> I came across a few threads here asking about the availability of UDP
>> tools for Tornado. So I know there's nothing included with Tornado and that
>> I'll have to stay away from IOStream, using the IOLoop directly.
>>
>> But I was wondering if anyone had ever put together a proof-of-concept
>> demo that they'd be willing to share. I've never needed to build UDP
>> services before, and since I've spent a fair amount of time in the last
>> month getting up to speed with Tornado, I'd love to use what I've learned to
>> tackle this project. (As opposed to, for example, picking up Twisted for the
>> task.)
>>
>> Any help is greatly appreciated!
>>
>> Matt
--
Andreux Fort (af...@choqolat.org)