Beginning Python - From Novice to Professional
Beginning Python - From Novice to Professional Beginning Python - From Novice to Professional
CHAPTER 27 ■ PROJECT 8: FILE SHARING WITH XML-RPC 501 Useful Tools In this project, you’ll use quite a few standard library modules. I won’t describe them all in detail; refer to Chapter 10 and the Python Library Reference for additional details. The main modules you’ll be using are xmlrpclib and its close friend SimpleXMLRPCServer. The xmlrpclib module is discussed in Chapter 15, and SimpleXMLRPCServer is explored in more detail in this chapter. ■Caution Make sure you have an updated version of xmlrpclib and SimpleXMLRPCServer to avoid some security problems present in older versions. See the caution in the “XML-RPC” section of Chapter 15. For the interface to the file sharing program, you’ll be using a module from the standard library, called cmd (already mentioned in Chapter 24); to get some (very limited) parallelism, you’ll use the threading module, and to extract the components of a URL, you’ll use the urlparse module. All of these modules are explained later in the chapter. Other modules you might want to brush up on are random, string, time, and os.path. Preparations First of all, you must make sure you have the proper libraries (that you can import xmlrpclib and SimpleXMLRPCServer). Make sure you’ve got an updated version of SimpleXMLRPCServer. You don’t strictly have to be connected to a network to use the software in this project, but it will make things more interesting. If you have access to two (or more) separate machines that are connected, you can run the software on each of these machines and have them communicate with each other. For testing purposes, it is also possible to run multiple file sharing nodes on the same machine. First Implementation Before you can write a first prototype of the Node class (a single node or peer in the system), you have to learn a bit about how the SimpleXMLRPCServer class works. It is instantiated with a tuple of the form (servername, port). The server name is the name of the machine on which the server will run (you can use an empty string here to indicate localhost, the machine where you’re actually executing the program). The port number can be any port you have access to, typically 1024 and above. After you have instantiated the server, you may register an instance that implements its “remote methods,” with the register_instance method. Alternatively, you can register individual functions with the register_function method. When you’re ready to run the server (so that it can respond to requests from outside), you call its method serve_forever. You can easily try this out. Start two interactive Python interpreters. In the first one, enter the code that appears after the caution.
502 CHAPTER 27 ■ PROJECT 8: FILE SHARING WITH XML-RPC ■Caution You may not be able to stop the server easily when you run it in an interpreter like this. You should be prepared to terminate the interpreter itself. An alternative is to enter the following code in a script and run that from the command line. Then you should be able to terminate the server with Ctrl+C (UNIX) or Ctrl+Break (Windows). >>> from SimpleXMLRPCServer import SimpleXMLRPCServer >>> s = SimpleXMLRPCServer(("", 4242)) # Localhost at port 4242 >>> def twice(x): # Example function ... return x*2 ... >>> s.register_function(twice) # Add functionality to the server >>> s.serve_forever() # Start the server After executing the last statement, the interpreter should seem to “hang.” Actually, it’s waiting for RPC requests. To make such a request, switch to the other interpreter and execute the following: >>> from xmlrpclib import ServerProxy # ...or simply Server, if you prefer >>> s = ServerProxy('http://localhost:4242') # Localhost again... >>> s.twice(2) 4 Pretty impressive, eh? Especially considering that the client part (using xmlrpclib) could be run on a different machine. (In that case, you would have to use the actual name of the server machine instead of simply localhost.) Now that we’ve got the XML-RPC technicalities covered, it’s time to get started with the coding. (The full source code of the first prototype is found in Listing 27-1, at the end of this section.) To find out where to begin, it might be a good idea to review your requirements from earlier in this chapter. You’re mainly interested in two things: what information must your Node hold (attributes) and what actions must it be able to perform (methods)? The Node must have at least the following attributes: • A directory name, so it knows where to find/store its files. • A “secret” (or password) that can be used by others to identify themselves (as trusted parties). • A set of known peers (URLs). • A URL, which may be added to the query history, or possibly supplied to other Nodes. (This project won’t implement the latter.) The Node constructor will simply set these four attributes. In addition, you’ll need a method for querying the Node, a method for making it fetch and store a file, and a method to introduce
- Page 481 and 482: 450 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 483 and 484: 452 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 486 and 487: CHAPTER 24 ■ ■ ■ Project 5: A
- Page 488 and 489: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 490 and 491: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 492 and 493: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 494 and 495: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 496 and 497: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 498 and 499: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 500 and 501: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 502 and 503: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 504 and 505: CHAPTER 25 ■ ■ ■ Project 6: R
- Page 506 and 507: CHAPTER 25 ■ PROJECT 6: REMOTE ED
- Page 508 and 509: CHAPTER 25 ■ PROJECT 6: REMOTE ED
- Page 510 and 511: CHAPTER 25 ■ PROJECT 6: REMOTE ED
- Page 512: CHAPTER 25 ■ PROJECT 6: REMOTE ED
- Page 515 and 516: 484 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 517 and 518: 486 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 519 and 520: 488 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 521 and 522: 490 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 523 and 524: 492 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 525 and 526: 494 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 527 and 528: 496 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 529 and 530: 498 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 531: 500 CHAPTER 27 ■ PROJECT 8: FILE
- Page 535 and 536: 504 CHAPTER 27 ■ PROJECT 8: FILE
- Page 537 and 538: 506 CHAPTER 27 ■ PROJECT 8: FILE
- Page 539 and 540: 508 CHAPTER 27 ■ PROJECT 8: FILE
- Page 541 and 542: 510 CHAPTER 27 ■ PROJECT 8: FILE
- Page 543 and 544: 512 CHAPTER 27 ■ PROJECT 8: FILE
- Page 545 and 546: 514 CHAPTER 27 ■ PROJECT 8: FILE
- Page 547 and 548: 516 CHAPTER 27 ■ PROJECT 8: FILE
- Page 549 and 550: 518 CHAPTER 28 ■ PROJECT 9: FILE
- Page 551 and 552: 520 CHAPTER 28 ■ PROJECT 9: FILE
- Page 553 and 554: 522 CHAPTER 28 ■ PROJECT 9: FILE
- Page 555 and 556: 524 CHAPTER 28 ■ PROJECT 9: FILE
- Page 558 and 559: CHAPTER 29 ■ ■ ■ Project 10:
- Page 560 and 561: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
- Page 562 and 563: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
- Page 564 and 565: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
- Page 566 and 567: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
- Page 568 and 569: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
- Page 570 and 571: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
- Page 572 and 573: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
- Page 574 and 575: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
- Page 576 and 577: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
- Page 578 and 579: APPENDIX A ■ ■ ■ The Short Ve
- Page 580 and 581: APPENDIX A ■ THE SHORT VERSION 54
502 CHAPTER 27 ■ PROJECT 8: FILE SHARING WITH XML-RPC<br />
■Caution You may not be able <strong>to</strong> s<strong>to</strong>p the server easily when you run it in an interpreter like this. You<br />
should be prepared <strong>to</strong> terminate the interpreter itself. An alternative is <strong>to</strong> enter the following code in a script<br />
and run that from the command line. Then you should be able <strong>to</strong> terminate the server with Ctrl+C (UNIX) or<br />
Ctrl+Break (Windows).<br />
>>> from SimpleXMLRPCServer import SimpleXMLRPCServer<br />
>>> s = SimpleXMLRPCServer(("", 4242)) # Localhost at port 4242<br />
>>> def twice(x): # Example function<br />
... return x*2<br />
...<br />
>>> s.register_function(twice) # Add functionality <strong>to</strong> the server<br />
>>> s.serve_forever() # Start the server<br />
After executing the last statement, the interpreter should seem <strong>to</strong> “hang.” Actually, it’s<br />
waiting for RPC requests.<br />
To make such a request, switch <strong>to</strong> the other interpreter and execute the following:<br />
>>> from xmlrpclib import ServerProxy # ...or simply Server, if you prefer<br />
>>> s = ServerProxy('http://localhost:4242') # Localhost again...<br />
>>> s.twice(2)<br />
4<br />
Pretty impressive, eh? Especially considering that the client part (using xmlrpclib) could<br />
be run on a different machine. (In that case, you would have <strong>to</strong> use the actual name of the<br />
server machine instead of simply localhost.)<br />
Now that we’ve got the XML-RPC technicalities covered, it’s time <strong>to</strong> get started with the<br />
coding. (The full source code of the first pro<strong>to</strong>type is found in Listing 27-1, at the end of this<br />
section.)<br />
To find out where <strong>to</strong> begin, it might be a good idea <strong>to</strong> review your requirements from<br />
earlier in this chapter. You’re mainly interested in two things: what information must your Node<br />
hold (attributes) and what actions must it be able <strong>to</strong> perform (methods)?<br />
The Node must have at least the following attributes:<br />
• A direc<strong>to</strong>ry name, so it knows where <strong>to</strong> find/s<strong>to</strong>re its files.<br />
• A “secret” (or password) that can be used by others <strong>to</strong> identify themselves (as trusted<br />
parties).<br />
• A set of known peers (URLs).<br />
• A URL, which may be added <strong>to</strong> the query his<strong>to</strong>ry, or possibly supplied <strong>to</strong> other Nodes.<br />
(This project won’t implement the latter.)<br />
The Node construc<strong>to</strong>r will simply set these four attributes. In addition, you’ll need a method<br />
for querying the Node, a method for making it fetch and s<strong>to</strong>re a file, and a method <strong>to</strong> introduce