Use case - listen on unix sockets and http serve on a port

818 views
Skip to first unread message

Srini K

unread,
Jan 29, 2014, 12:39:46 AM1/29/14
to python-...@googlegroups.com
I am trying to setup tornado in a way it behaves as a regular http server where it listens for http connections and serves data on a given port.

But tornado app should also listen on a unix socket which is used by an external program to communicate with.

How do I setup this use case? Should I go with a seperate unix socket client on a thread with a Queue for message passing? Is there any other simpler way that I am missing from tornado's point of view?

thanks,
-Srini

Ben Darnell

unread,
Jan 29, 2014, 9:08:36 PM1/29/14
to Tornado Mailing List
There is no need to create multiple threads; you can listen to different sockets on the same IOLoop.  If you're speaking HTTP over the unix socket, just create two HTTPServers (which can share a single Application or use two different ones depending on your use case), and for the second use `server.add_socket(tornado.netutil.bind_unix_socket(path))`.  If the unix socket is not speaking HTTP, use bind_unix_socket and add_accept_handler from tornado.netutil to establish a callback for it.  

-Ben


--
You received this message because you are subscribed to the Google Groups "Tornado Web Server" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python-tornad...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

A. Jesse Jiryu Davis

unread,
Jan 29, 2014, 10:16:32 PM1/29/14
to python-...@googlegroups.com
For fun, I hacked up an example of this:

import re
from functools import partial

import tornado.ioloop
import tornado.iostream
import tornado.httpserver
import tornado.netutil
import tornado.tcpserver
import tornado.web


messages = []


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_header('Content-Type', 'text')
        self.write('\n'.join(messages))


def accept(connection, address):
    stream = tornado.iostream.IOStream(connection)
    callback = partial(talk, stream)
    stream.read_until('\n', callback)


quit_pattern = re.compile('quit\s*', re.IGNORECASE)


def talk(stream, message):
    stream.write('I got your message: %r\r\n' % message)
    if quit_pattern.match(message):
        stream.close()
    else:
        messages.append(message)
        
        # Read next message.
        callback = partial(talk, stream)
        stream.read_until('\n', callback)


if __name__ == "__main__":
    application = tornado.web.Application(handlers=[
        (r"/", MainHandler),
    ])

    application.listen(8888)

    unix_socket = tornado.netutil.bind_unix_socket('/tmp/sock.sock')
    tornado.netutil.add_accept_handler(unix_socket, accept)

    tornado.ioloop.IOLoop.instance().start()

You can run "telnet -u /tmp/sock.sock" on the terminal and talk to the application:

Trying /tmp/sock.sock...
Connected to (null).
Escape character is '^]'.
asdf
I got your message: 'asdf\r\n'
foo
I got your message: 'foo\r\n'
quit
I got your message: 'quit\r\n'
Connection closed by foreign host.

To demonstrate data-sharing between the unix socket listener and the HTTP server, the unix socket server adds each message to the global 'messages' list. The HTTP server presents a page on http://localhost:8888 with all the messages received.

(This is not relevant to Srini's question right now, but it harkens back to our discussion about making IOStream coroutine-friendly. Once those changes are complete, accept() and talk() can be neatly combined into one coroutine.)

Srini K

unread,
Jan 30, 2014, 10:35:42 AM1/30/14
to python-...@googlegroups.com
Great. Thanks guys. Wow this is convenient.
Reply all
Reply to author
Forward
0 new messages