Beginning Python - From Novice to Professional
Beginning Python - From Novice to Professional Beginning Python - From Novice to Professional
CHAPTER 14 ■ NETWORK PROGRAMMING 309 other system, download a source archive. (If you’re using a package manager such as Portage, RPM, APT, or Fink, you can probably get it to download and install Twisted directly.) The Windows installer is a self-explanatory step-by-step wizard. It may take some time compiling and unpacking things, but all you have to do is wait. To install the source archive, you first unpack it (using tar and then either gunzip or bunzip2, depending on which type of archive you downloaded) and then run the Distutils script: python setup.py install You should then be able to use Twisted. Writing a Twisted Server The basic socket servers written earlier in this chapter are very explicit. Some of them have an explicit event loop, looking for new connections and new data; SocketServer-based servers have an implicit loop where the server looks for connections and creates a handler for each connection, but the handlers still have to be explicit about trying to read data. Twisted (and the asyncore/asynchat framework, discussed in Chapter 24) uses an even more event-based approach. To write a basic server, you implement event handlers that deal with situations such as a new client connecting, new data arriving, and a client disconnecting (as well as many other events). Specialized classes can build more refined events from the basic ones, such as wrapping “data arrived” events, collecting the data until a newline is found, and then dispatching a “line of data arrived” event. (Such a class is discussed later.) ■Note One thing I have not dealt with in this section, but which is somewhat characteristic of Twisted, is the concept of deferreds and deferred execution. See the Twisted documentation for more information (see, for example, the tutorial called “Deferreds are beautiful,” available from the HOWTO page of the Twisted docs). Your event handlers are defined in a protocol; you also need a factory that can construct such protocol objects when a new connection arrives, but if you just want to create instances of a custom protocol class, you can use the factory that comes with Twisted, the Factory class in the module twisted.internet.protocol. When you write your protocol, use the Protocol from the same module as your superclass. When you get a connection, the event handler connectionMade is called; when you lose a connection, connectionLost is called. Data is received from the client through the handler dataReceived. Of course, you can’t use the event-handling strategy to send data back to the client; for that you use the object self.transport, which has a write method. It also has a client attribute, which contains the client address (host name and port). Listing 14-8 contains a Twisted version of the server from Listings 14-6 and 14-7. I hope you agree that the Twisted version is quite a bit simpler and more readable. There is a little bit of setup involved; you have to instantiate Factory and set its protocol attribute so it knows which protocol to use when communicating with clients (that is, your custom protocol). Then you start listening at a given port with that factory standing by to handle connections by instantiating protocol objects. You do this using the listenTCP function from the reactor module. Finally, you start the server by calling the run function from the same module.
310 CHAPTER 14 ■ NETWORK PROGRAMMING Listing 14-8. A Simple Server Using Twisted from twisted.internet import reactor from twisted.internet.protocol import Protocol, Factory class SimpleLogger(Protocol): def connectionMade(self): print 'Got connection from', self.transport.client def connectionLost(self, reason): print self.transport.client, 'disconnected' def dataReceived(self, data): print data factory = Factory() factory.protocol = SimpleLogger reactor.listenTCP(1234, factory) reactor.run() If you connected to this server using telnet, to test it out, you may have gotten a single character on each line of output, depending on buffering and the like. You could, of course, simply use sys.stdout.write instead of print, but in many cases you might like to get a single line at a time, instead of just arbitrary data. Writing a custom protocol that handled this for you would be quite easy, but there is, in fact, such a class available already. The module twisted.protocols.basic contains a couple of useful preexisting protocols, among them LineReceiver. It implements dataReceived and calls the event handler lineReceived whenever a full line is received. ■Tip If you need to do something when you receive data in addition to using lineReceived, which depends on the LineReceiver implementation of dataReceived, you can use the new event handler defined by LineReceiver called rawDataReceived. Switching the protocol requires only a minimum of work. Listing 14-9 shows the result. If you look at the resulting output when running this server, you’ll see that the newlines are stripped; in other words, using print won’t give you double newlines anymore. Listing 14-9. An Improved Logging Server, Using the LineReceiver Protocol from twisted.internet import reactor from twisted.internet.protocol import Factory from twisted.protocols.basic import LineReceiver
- Page 289 and 290: 258 CHAPTER 11 ■ FILES AND STUFF
- Page 291 and 292: 260 CHAPTER 11 ■ FILES AND STUFF
- Page 293 and 294: 262 CHAPTER 11 ■ FILES AND STUFF
- Page 295 and 296: 264 CHAPTER 11 ■ FILES AND STUFF
- Page 297 and 298: 266 CHAPTER 11 ■ FILES AND STUFF
- Page 299 and 300: 268 CHAPTER 11 ■ FILES AND STUFF
- Page 301 and 302: 270 CHAPTER 12 ■ GRAPHICAL USER I
- Page 303 and 304: 272 CHAPTER 12 ■ GRAPHICAL USER I
- Page 305 and 306: 274 CHAPTER 12 ■ GRAPHICAL USER I
- Page 307 and 308: 276 CHAPTER 12 ■ GRAPHICAL USER I
- Page 309 and 310: 278 CHAPTER 12 ■ GRAPHICAL USER I
- Page 311 and 312: 280 CHAPTER 12 ■ GRAPHICAL USER I
- Page 313 and 314: 282 CHAPTER 12 ■ GRAPHICAL USER I
- Page 316 and 317: CHAPTER 13 ■ ■ ■ Database Sup
- Page 318 and 319: CHAPTER 13 ■ DATABASE SUPPORT 287
- Page 320 and 321: CHAPTER 13 ■ DATABASE SUPPORT 289
- Page 322 and 323: CHAPTER 13 ■ DATABASE SUPPORT 291
- Page 324 and 325: CHAPTER 13 ■ DATABASE SUPPORT 293
- Page 326: CHAPTER 13 ■ DATABASE SUPPORT 295
- Page 329 and 330: 298 CHAPTER 14 ■ NETWORK PROGRAMM
- Page 331 and 332: 300 CHAPTER 14 ■ NETWORK PROGRAMM
- Page 333 and 334: 302 CHAPTER 14 ■ NETWORK PROGRAMM
- Page 335 and 336: 304 CHAPTER 14 ■ NETWORK PROGRAMM
- Page 337 and 338: 306 CHAPTER 14 ■ NETWORK PROGRAMM
- Page 339: 308 CHAPTER 14 ■ NETWORK PROGRAMM
- Page 343 and 344: 312 CHAPTER 14 ■ NETWORK PROGRAMM
- Page 345 and 346: 314 CHAPTER 15 ■ PYTHON AND THE W
- Page 347 and 348: 316 CHAPTER 15 ■ PYTHON AND THE W
- Page 349 and 350: 318 CHAPTER 15 ■ PYTHON AND THE W
- Page 351 and 352: 320 CHAPTER 15 ■ PYTHON AND THE W
- Page 353 and 354: 322 CHAPTER 15 ■ PYTHON AND THE W
- Page 355 and 356: 324 CHAPTER 15 ■ PYTHON AND THE W
- Page 357 and 358: 326 CHAPTER 15 ■ PYTHON AND THE W
- Page 359 and 360: 328 CHAPTER 15 ■ PYTHON AND THE W
- Page 361 and 362: 330 CHAPTER 15 ■ PYTHON AND THE W
- Page 363 and 364: 332 CHAPTER 15 ■ PYTHON AND THE W
- Page 365 and 366: 334 CHAPTER 15 ■ PYTHON AND THE W
- Page 367 and 368: 336 CHAPTER 15 ■ PYTHON AND THE W
- Page 369 and 370: 338 CHAPTER 15 ■ PYTHON AND THE W
- Page 372 and 373: CHAPTER 16 ■ ■ ■ Testing, 1-2
- Page 374 and 375: CHAPTER 16 ■ TESTING, 1-2-3 343 W
- Page 376 and 377: CHAPTER 16 ■ TESTING, 1-2-3 345 d
- Page 378 and 379: CHAPTER 16 ■ TESTING, 1-2-3 347 u
- Page 380 and 381: CHAPTER 16 ■ TESTING, 1-2-3 349 F
- Page 382 and 383: CHAPTER 16 ■ TESTING, 1-2-3 351 P
- Page 384 and 385: CHAPTER 16 ■ TESTING, 1-2-3 353 "
- Page 386: CHAPTER 16 ■ TESTING, 1-2-3 355 N
- Page 389 and 390: 358 CHAPTER 17 ■ EXTENDING PYTHON
CHAPTER 14 ■ NETWORK PROGRAMMING 309<br />
other system, download a source archive. (If you’re using a package manager such as Portage,<br />
RPM, APT, or Fink, you can probably get it <strong>to</strong> download and install Twisted directly.) The<br />
Windows installer is a self-explana<strong>to</strong>ry step-by-step wizard. It may take some time compiling<br />
and unpacking things, but all you have <strong>to</strong> do is wait. To install the source archive, you first<br />
unpack it (using tar and then either gunzip or bunzip2, depending on which type of archive you<br />
downloaded) and then run the Distutils script:<br />
python setup.py install<br />
You should then be able <strong>to</strong> use Twisted.<br />
Writing a Twisted Server<br />
The basic socket servers written earlier in this chapter are very explicit. Some of them have an<br />
explicit event loop, looking for new connections and new data; SocketServer-based servers<br />
have an implicit loop where the server looks for connections and creates a handler for each<br />
connection, but the handlers still have <strong>to</strong> be explicit about trying <strong>to</strong> read data. Twisted (and the<br />
asyncore/asynchat framework, discussed in Chapter 24) uses an even more event-based approach.<br />
To write a basic server, you implement event handlers that deal with situations such as a new<br />
client connecting, new data arriving, and a client disconnecting (as well as many other events).<br />
Specialized classes can build more refined events from the basic ones, such as wrapping “data<br />
arrived” events, collecting the data until a newline is found, and then dispatching a “line of<br />
data arrived” event. (Such a class is discussed later.)<br />
■Note One thing I have not dealt with in this section, but which is somewhat characteristic of Twisted, is<br />
the concept of deferreds and deferred execution. See the Twisted documentation for more information (see,<br />
for example, the tu<strong>to</strong>rial called “Deferreds are beautiful,” available from the HOWTO page of the Twisted docs).<br />
Your event handlers are defined in a pro<strong>to</strong>col; you also need a fac<strong>to</strong>ry that can construct<br />
such pro<strong>to</strong>col objects when a new connection arrives, but if you just want <strong>to</strong> create instances<br />
of a cus<strong>to</strong>m pro<strong>to</strong>col class, you can use the fac<strong>to</strong>ry that comes with Twisted, the Fac<strong>to</strong>ry class<br />
in the module twisted.internet.pro<strong>to</strong>col. When you write your pro<strong>to</strong>col, use the Pro<strong>to</strong>col<br />
from the same module as your superclass. When you get a connection, the event handler<br />
connectionMade is called; when you lose a connection, connectionLost is called. Data is received<br />
from the client through the handler dataReceived. Of course, you can’t use the event-handling<br />
strategy <strong>to</strong> send data back <strong>to</strong> the client; for that you use the object self.transport, which has a<br />
write method. It also has a client attribute, which contains the client address (host name<br />
and port).<br />
Listing 14-8 contains a Twisted version of the server from Listings 14-6 and 14-7. I hope<br />
you agree that the Twisted version is quite a bit simpler and more readable. There is a little bit<br />
of setup involved; you have <strong>to</strong> instantiate Fac<strong>to</strong>ry and set its pro<strong>to</strong>col attribute so it knows<br />
which pro<strong>to</strong>col <strong>to</strong> use when communicating with clients (that is, your cus<strong>to</strong>m pro<strong>to</strong>col). Then<br />
you start listening at a given port with that fac<strong>to</strong>ry standing by <strong>to</strong> handle connections by instantiating<br />
pro<strong>to</strong>col objects. You do this using the listenTCP function from the reac<strong>to</strong>r module. Finally,<br />
you start the server by calling the run function from the same module.