Section 16.5. Introduction to the Twisted Framework


16.5. *Introduction to the Twisted Framework

Twisted is a complete event-driven networking framework that allows you to both use and develop complete asynchronous networked applications and protocols. It is not part of the Python Standard library at the time of writing and must be downloaded and installed separately (see link at the end of the chapter). It provides a significant amount of support for you to build complete systems with: network protocols, threading, security and authentication, chat/IM, DBM and RDBMS database integration, Web/Internet, e-mail, command-line arguments, GUI toolkit integration, etc.

Using Twisted to implement our tiny simplistic example is like using a sledgehammer to pound a thumbtack, but you have to get started somehow, and our application is the equivalent to the "hello world" of networked applications.

Like SocketServer, most of the functionality of Twisted lies in its classes. In particular for our examples, we will be using the classes found in the reactor and protocol subpackages of Twisted's Internet component.

16.5.1. Creating a Twisted Reactor TCP Server

You will find our code similar to that of the SocketServer example. Instead of a handler class, we create a protocol class and override several methods in the same manner as installing callbacks. Also, this example is asynchronous. Let us take a look at the server now.

Line-by-Line Explanation
Lines 16

The setup lines of code include the usual module imports, most notably the protocol and reactor subpackages of twisted.internet and our constant port number.

Lines 814

We derive the Protocol class and call ours TSServProtocol for our timestamp server. We then override connectionMade(), a method that is executed when a client connects to us, and dataReceived(), called when a client sends a piece of data across the network. The reactor passes in the data as an argument to this method so we can get access to it right away without having to extract it ourselves.

Example 16.7. Twisted Reactor Timestamp TCP Server (tsTservTW.py)

This is a timestamp TCP server using Twisted Internet classes.

        1   #!/usr/bin/env python         2         3   from twisted.internet import protocol, reactor         4   from time import ctime         5         6   PORT = 21567         7         8   class TSServProtocol(protocol.Protocol):         9       def connectionMade(self):         10           clnt = self.clnt = self.transport.getPeer().host         11           print '...connected from:', clnt         12      def dataReceived(self, data):         13           self.transport.write('[%s] %s' % (         14                 ctime(), data))         15         16  factory = protocol.Factory()         17  factory.protocol = TSServProtocol         18  print 'waiting for connection...'         19  reactor.listenTCP(PORT, factory)         20  reactor.run()

The transport instance object is how we can communicate with the client. You can see how we use it in connectionMade() to get the host information about who is connecting to us as well as in dataReceived() to return data back to the client.

Lines 1620

In the final part of our server, we create a protocol Factory. It is called a "factory" so that an instance of our protocol is "manufactured" every time we get an incoming connection. We then install a TCP listener in our reactor to check for service requests and when it gets one, to create a TSServProtocol instance to take care of that client.

16.5.2. Creating a Twisted Reactor TCP Client

Unlike the SocketServer TCP client, this one will not look like all the other clients. This one is distinctly Twisted.

Example 16.8. Twisted Reactor Timestamp TCP Client (tsTclntTW.py)

Our familiar timestamp TCP client written from a Twisted point of view.

        1   #!/usr/bin/env python         2         3   from twisted.internet import protocol, reactor         4         5   HOST = 'localhost'         6   PORT = 21567         7         8   class TSClntProtocol(protocol.Protocol):         9       def sendData(self):         10           data = raw_input('> ')         11           if data:         12               print '...sending %s...' % data         13               self.transport.write(data)         14           else:         15                self.transport.loseConnection()         16         17      def connectionMade(self):         18           self.sendData()         19         20      def dataReceived(self, data):         21          print data         22          self.sendData()         23         24  class TSClntFactory(protocol.ClientFactory):         25       protocol = TSClntProtocol         26       clientConnectionLost = clientConnectionFailed = \         27          lambda self, connector, reason: reactor.stop()         28         29  reactor.connectTCP(HOST, PORT, TSClntFactory())         30  reactor.run()

Line-by-Line Explanation
Lines 16

Again, nothing really new here other than the import of Twisted components. It is very similar to all of our other clients.

Lines 822

Like the server, we extend Protocol by overriding the same methods, connectionMade() and dataReceived(). Both execute for the same reason as the server. We also add our own method for when data need to be sent and call it sendData().

Since we are the client this time, we are the ones initiating a conversation with the server. Once that connection has been established, we take the first step and send a message. The server replies, and we handle it by displaying it to the screen and sending another message to the server.

This continues in a loop until we terminate the connection by giving no input when prompted. Instead of calling the write() method of the transport object to send another message to the server, loseConnection() is executed, closing the socket. When this occurs, the factory's clientConnection-Lost() method will be called, and our reactor is stopped, completing execution of our script. We also stop the reactor if a clientConnection-Failed() for some other reason.

The final part of the script is where we create a client factory and make a connection to the server and run the reactor. Note that we instantiate the client factory here instead of passing it in to the reactor like in the server. This is because we are not the server waiting for clients to talk to us, and its factory makes a new protocol object for each connection. We are one client, so we make a single protocol object that connects to the server whose factory makes one to talk to ours.

16.5.3. Executing Our TCP Server and Client(s)

The Twisted client displays output similar to all our other clients:

    $ tsTclntTW.py     > Where is hope     ...sending Where is hope...     [Tue Apr 18 23:53:09 2006] Where is hope     > When words fail     ...sending When words fail...     [Tue Apr 18 23:53:14 2006] When words fail     >     $


The server is back to a single connection. Twisted maintains the connection and does not close the transport after every message:

   $ tsTservTW.py    waiting for connection...    ...connected from: 127.0.0.1


The "connection from" output does not have the other information because we only asked for the host/address from the getPeer() method of the server's transport object.



Core Python Programming
Core Python Programming (2nd Edition)
ISBN: 0132269937
EAN: 2147483647
Year: 2004
Pages: 334
Authors: Wesley J Chun

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net