16.5. *Introduction to the Twisted FrameworkTwisted 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 ServerYou 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 ExplanationLines 16The 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 814We 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)
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 1620In 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 ClientUnlike 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)
Line-by-Line ExplanationLines 16Again, nothing really new here other than the import of Twisted components. It is very similar to all of our other clients. Lines 822Like 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. |