diff options
author | Georg Brandl <georg@python.org> | 2008-05-25 18:19:30 (GMT) |
---|---|---|
committer | Georg Brandl <georg@python.org> | 2008-05-25 18:19:30 (GMT) |
commit | b533e26dfae98f00facb50a6d3d6c200771d051f (patch) | |
tree | c41061c14b853728742903222b936b9614ff1d93 /Doc | |
parent | cea777423b67a5ea1ed104b217373556d6ff0383 (diff) | |
download | cpython-b533e26dfae98f00facb50a6d3d6c200771d051f.zip cpython-b533e26dfae98f00facb50a6d3d6c200771d051f.tar.gz cpython-b533e26dfae98f00facb50a6d3d6c200771d051f.tar.bz2 |
Merged revisions 63412,63445-63447,63449-63450,63452,63454,63459,63463,63465,63470,63483-63484,63496-63497,63499-63501,63530-63531,63540,63614 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r63412 | georg.brandl | 2008-05-17 19:57:01 +0200 (Sat, 17 May 2008) | 2 lines
#961805: fix Edit.text_modified().
........
r63445 | georg.brandl | 2008-05-18 10:52:59 +0200 (Sun, 18 May 2008) | 2 lines
GHOP #180 by Michael Schneider: add examples to the socketserver documentation.
........
r63446 | georg.brandl | 2008-05-18 11:12:20 +0200 (Sun, 18 May 2008) | 2 lines
GHOP #134, #171, #137: unit tests for the three HTTPServer modules.
........
r63447 | georg.brandl | 2008-05-18 12:39:26 +0200 (Sun, 18 May 2008) | 3 lines
Take namedtuple item names only from ascii_letters (this blew up on OSX),
and make sure there are no duplicate names.
........
r63449 | georg.brandl | 2008-05-18 13:46:51 +0200 (Sun, 18 May 2008) | 2 lines
GHOP #217: add support for compiling Python with coverage checking enabled.
........
r63450 | georg.brandl | 2008-05-18 13:52:36 +0200 (Sun, 18 May 2008) | 2 lines
GHOP #257: test distutils' build_ext command, written by Josip Dzolonga.
........
r63452 | georg.brandl | 2008-05-18 15:34:06 +0200 (Sun, 18 May 2008) | 2 lines
Add GHOP students.
........
r63454 | georg.brandl | 2008-05-18 18:32:48 +0200 (Sun, 18 May 2008) | 2 lines
GHOP #121: improve test_pydoc, by Benjamin Peterson.
........
r63459 | benjamin.peterson | 2008-05-18 22:48:07 +0200 (Sun, 18 May 2008) | 2 lines
bring test_pydoc up to my high standards (now that I have them)
........
r63463 | georg.brandl | 2008-05-18 23:10:19 +0200 (Sun, 18 May 2008) | 2 lines
Fix test_pyclbr after another platform-dependent function was added to urllib.
........
r63465 | benjamin.peterson | 2008-05-19 01:07:07 +0200 (Mon, 19 May 2008) | 2 lines
change some imports in tests so they will not be skipped in 3.0
........
r63470 | georg.brandl | 2008-05-19 18:47:25 +0200 (Mon, 19 May 2008) | 2 lines
test_httpservers has unpredictable refcount behavior.
........
r63483 | georg.brandl | 2008-05-20 08:15:36 +0200 (Tue, 20 May 2008) | 2 lines
Activate two more test cases in test_httpservers.
........
r63484 | georg.brandl | 2008-05-20 08:47:31 +0200 (Tue, 20 May 2008) | 2 lines
Argh, this is the *actual* test that works under Windows.
........
r63496 | georg.brandl | 2008-05-20 10:07:36 +0200 (Tue, 20 May 2008) | 2 lines
Improve diffing logic and output for test_pydoc.
........
r63497 | georg.brandl | 2008-05-20 10:10:03 +0200 (Tue, 20 May 2008) | 2 lines
Use inspect.getabsfile() to get the documented module's filename.
........
r63499 | georg.brandl | 2008-05-20 10:25:48 +0200 (Tue, 20 May 2008) | 3 lines
Patch #1775025: allow opening zipfile members via ZipInfo instances.
Patch by Graham Horler.
........
r63500 | georg.brandl | 2008-05-20 10:40:43 +0200 (Tue, 20 May 2008) | 2 lines
#2592: delegate nb_index and the floor/truediv slots in weakref.proxy.
........
r63501 | georg.brandl | 2008-05-20 10:48:34 +0200 (Tue, 20 May 2008) | 2 lines
#615772: raise a more explicit error from Tkinter.Misc.__contains__.
........
r63530 | benjamin.peterson | 2008-05-22 02:57:02 +0200 (Thu, 22 May 2008) | 2 lines
use more specific asserts in test_opcode
........
r63531 | benjamin.peterson | 2008-05-22 03:02:23 +0200 (Thu, 22 May 2008) | 2 lines
remove redundant invocation of json doctests
........
r63540 | benjamin.peterson | 2008-05-23 01:09:26 +0200 (Fri, 23 May 2008) | 3 lines
fix test_pydoc so it works on make installed Python installations
Also let it pass when invoked directly
........
r63614 | georg.brandl | 2008-05-25 10:07:37 +0200 (Sun, 25 May 2008) | 2 lines
#2959: allow multiple close() calls for GzipFile.
........
Diffstat (limited to 'Doc')
-rw-r--r-- | Doc/library/socketserver.rst | 251 | ||||
-rw-r--r-- | Doc/library/zipfile.rst | 33 |
2 files changed, 253 insertions, 31 deletions
diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst index e24b429..b176ca3 100644 --- a/Doc/library/socketserver.rst +++ b/Doc/library/socketserver.rst @@ -236,8 +236,8 @@ users of the server object. .. function:: handle_timeout() - This function is called when the :attr:`timeout` attribute has been set to a - value other than :const:`None` and the timeout period has passed with no + This function is called when the :attr:`timeout` attribute has been set to a + value other than :const:`None` and the timeout period has passed with no requests being received. The default action for forking servers is to collect the status of any child processes that have exited, while in threading servers this method does nothing. @@ -284,27 +284,28 @@ request. .. function:: finish() - Called after the :meth:`handle` method to perform any clean-up actions required. - The default implementation does nothing. If :meth:`setup` or :meth:`handle` - raise an exception, this function will not be called. + Called after the :meth:`handle` method to perform any clean-up actions + required. The default implementation does nothing. If :meth:`setup` or + :meth:`handle` raise an exception, this function will not be called. .. function:: handle() - This function must do all the work required to service a request. The default - implementation does nothing. Several instance attributes are available to it; - the request is available as :attr:`self.request`; the client address as - :attr:`self.client_address`; and the server instance as :attr:`self.server`, in - case it needs access to per-server information. + This function must do all the work required to service a request. The + default implementation does nothing. Several instance attributes are + available to it; the request is available as :attr:`self.request`; the client + address as :attr:`self.client_address`; and the server instance as + :attr:`self.server`, in case it needs access to per-server information. - The type of :attr:`self.request` is different for datagram or stream services. - For stream services, :attr:`self.request` is a socket object; for datagram - services, :attr:`self.request` is a string. However, this can be hidden by using - the request handler subclasses :class:`StreamRequestHandler` or - :class:`DatagramRequestHandler`, which override the :meth:`setup` and - :meth:`finish` methods, and provide :attr:`self.rfile` and :attr:`self.wfile` - attributes. :attr:`self.rfile` and :attr:`self.wfile` can be read or written, - respectively, to get the request data or return data to the client. + The type of :attr:`self.request` is different for datagram or stream + services. For stream services, :attr:`self.request` is a socket object; for + datagram services, :attr:`self.request` is a pair of string and socket. + However, this can be hidden by using the request handler subclasses + :class:`StreamRequestHandler` or :class:`DatagramRequestHandler`, which + override the :meth:`setup` and :meth:`finish` methods, and provide + :attr:`self.rfile` and :attr:`self.wfile` attributes. :attr:`self.rfile` and + :attr:`self.wfile` can be read or written, respectively, to get the request + data or return data to the client. .. function:: setup() @@ -312,3 +313,217 @@ request. Called before the :meth:`handle` method to perform any initialization actions required. The default implementation does nothing. + +Examples +-------- + +:class:`socketserver.TCPServer` Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the server side:: + + import socketserver + + class MyTCPHandler(socketserver.BaseRequestHandler): + """ + The RequestHandler class for our server. + + It is instantiated once per connection to the server, and must + override the handle() method to implement communication to the + client. + """ + + def handle(self): + # self.request is the TCP socket connected to the client + self.data = self.request.recv(1024).strip() + print "%s wrote:" % self.client_address[0] + print self.data + # just send back the same data, but upper-cased + self.request.send(self.data.upper()) + + if __name__ == "__main__": + HOST, PORT = "localhost", 9999 + + # Create the server, binding to localhost on port 9999 + server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) + + # Activate the server; this will keep running until you + # interrupt the program with Ctrl-C + server.serve_forever() + +An alternative request handler class that makes use of streams (file-like +objects that simplify communication by providing the standard file interface):: + + class MyTCPHandler(socketserver.StreamRequestHandler): + + def handle(self): + # self.rfile is a file-like object created by the handler; + # we can now use e.g. readline() instead of raw recv() calls + self.data = self.rfile.readline().strip() + print "%s wrote:" % self.client_address[0] + print self.data + # Likewise, self.wfile is a file-like object used to write back + # to the client + self.wfile.write(self.data.upper()) + +The difference is that the ``readline()`` call in the second handler will call +``recv()`` multiple times until it encounters a newline character, while the +single ``recv()`` call in the first handler will just return what has been sent +from the client in one ``send()`` call. + + +This is the client side:: + + import socket + import sys + + HOST, PORT = "localhost", 9999 + data = " ".join(sys.argv[1:]) + + # Create a socket (SOCK_STREAM means a TCP socket) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # Connect to server and send data + sock.connect((HOST, PORT)) + sock.send(data + "\n") + + # Receive data from the server and shut down + received = sock.recv(1024) + sock.close() + + print "Sent: %s" % data + print "Received: %s" % received + + +The output of the example should look something like this: + +Server:: + + $ python TCPServer.py + 127.0.0.1 wrote: + hello world with TCP + 127.0.0.1 wrote: + python is nice + +Client:: + + $ python TCPClient.py hello world with TCP + Sent: hello world with TCP + Received: HELLO WORLD WITH TCP + $ python TCPClient.py python is nice + Sent: python is nice + Received: PYTHON IS NICE + + +:class:`socketserver.UDPServer` Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is the server side:: + + import socketserver + + class MyUDPHandler(socketserver.BaseRequestHandler): + """ + This class works similar to the TCP handler class, except that + self.request consists of a pair of data and client socket, and since + there is no connection the client address must be given explicitly + when sending data back via sendto(). + """ + + def handle(self): + data = self.request[0].strip() + socket = self.request[1] + print "%s wrote:" % self.client_address[0] + print data + socket.sendto(data.upper(), self.client_address) + + if __name__ == "__main__": + HOST, PORT = "localhost", 9999 + server = socketserver.UDPServer((HOST, PORT), BaseUDPRequestHandler) + server.serve_forever() + +This is the client side:: + + import socket + import sys + + HOST, PORT = "localhost" + data = " ".join(sys.argv[1:]) + + # SOCK_DGRAM is the socket type to use for UDP sockets + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + + # As you can see, there is no connect() call; UDP has no connections. + # Instead, data is directly sent to the recipient via sendto(). + sock.sendto(data + "\n", (HOST, PORT)) + received = sock.recv(1024) + + print "Sent: %s" % data + print "Received: %s" % received + +The output of the example should look exactly like for the TCP server example. + + +Asynchronous Mixins +~~~~~~~~~~~~~~~~~~~ + +To build asynchronous handlers, use the :class:`ThreadingMixIn` and +:class:`ForkingMixIn` classes. + +An example for the :class:`ThreadingMixIn` class:: + + import socket + import threading + import socketserver + + class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): + + def handle(self): + data = self.request.recv(1024) + cur_thread = threading.currentThread() + response = "%s: %s" % (cur_thread.getName(), data) + self.request.send(response) + + class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): + pass + + def client(ip, port, message): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect((ip, port)) + sock.send(message) + response = sock.recv(1024) + print "Received: %s" % response + sock.close() + + if __name__ == "__main__": + # Port 0 means to select an arbitrary unused port + HOST, PORT = "localhost", 0 + + server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) + ip, port = server.server_address + + # Start a thread with the server -- that thread will then start one + # more thread for each request + server_thread = threading.Thread(target=server.serve_forever) + # Exit the server thread when the main thread terminates + server_thread.setDaemon(True) + server_thread.start() + print "Server loop running in thread:", t.getName() + + client(ip, port, "Hello World 1") + client(ip, port, "Hello World 2") + client(ip, port, "Hello World 3") + + server.shutdown() + +The output of the example should look something like this:: + + $ python ThreadedTCPServer.py + Server loop running in thread: Thread-1 + Received: Thread-2: Hello World 1 + Received: Thread-3: Hello World 2 + Received: Thread-4: Hello World 3 + + +The :class:`ForkingMixIn` class is used in the same way, except that the server +will spawn a new process for each request. diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index 9b77214..6e933f6 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -150,11 +150,11 @@ ZipFile Objects .. method:: ZipFile.open(name[, mode[, pwd]]) Extract a member from the archive as a file-like object (ZipExtFile). *name* is - the name of the file in the archive. The *mode* parameter, if included, must be - one of the following: ``'r'`` (the default), ``'U'``, or ``'rU'``. Choosing - ``'U'`` or ``'rU'`` will enable universal newline support in the read-only - object. *pwd* is the password used for encrypted files. Calling :meth:`open` - on a closed ZipFile will raise a :exc:`RuntimeError`. + the name of the file in the archive, or a :class:`ZipInfo` object. The *mode* + parameter, if included, must be one of the following: ``'r'`` (the default), + ``'U'``, or ``'rU'``. Choosing ``'U'`` or ``'rU'`` will enable universal newline + support in the read-only object. *pwd* is the password used for encrypted files. + Calling :meth:`open` on a closed ZipFile will raise a :exc:`RuntimeError`. .. note:: @@ -173,14 +173,20 @@ ZipFile Objects create a new file object that will be held by the ZipExtFile, allowing it to operate independently of the ZipFile. + .. note:: + + The :meth:`open`, :meth:`read` and :meth:`extract` methods can take a filename + or a :class:`ZipInfo` object. You will appreciate this when trying to read a + ZIP file that contains members with duplicate names. + .. method:: ZipFile.extract(member[, path[, pwd]]) - Extract a member from the archive to the current working directory, using its - full name. Its file information is extracted as accurately as possible. - *path* specifies a different directory to extract to. *member* can be a - filename or a :class:`ZipInfo` object. *pwd* is the password used for - encrypted files. + Extract a member from the archive to the current working directory; *member* + must be its full name or a :class:`ZipInfo` object). Its file information is + extracted as accurately as possible. *path* specifies a different directory + to extract to. *member* can be a filename or a :class:`ZipInfo` object. + *pwd* is the password used for encrypted files. .. method:: ZipFile.extractall([path[, members[, pwd]]]) @@ -203,9 +209,10 @@ ZipFile Objects .. method:: ZipFile.read(name[, pwd]) - Return the bytes of the file in the archive. The archive must be open for read - or append. *pwd* is the password used for encrypted files and, if specified, it - will override the default password set with :meth:`setpassword`. Calling + Return the bytes of the file *name* in the archive. *name* is the name of the + file in the archive, or a :class:`ZipInfo` object. The archive must be open for + read or append. *pwd* is the password used for encrypted files and, if specified, + it will override the default password set with :meth:`setpassword`. Calling :meth:`read` on a closed ZipFile will raise a :exc:`RuntimeError`. |