diff -r f555ef42ad62 Doc/library/socketserver.rst --- a/Doc/library/socketserver.rst Sun Feb 21 09:21:35 2016 -0800 +++ b/Doc/library/socketserver.rst Sun Feb 21 22:44:42 2016 +0200 @@ -52,11 +52,12 @@ overriding its :meth:`~BaseRequestHandler.handle` method; this method will process incoming requests. Second, you must instantiate one of the server classes, passing it -the server's address and the request handler class. Then call the +the server's address and the request handler class. It is recommended to initiate +the class using :keyword:`with` statement. Then call the :meth:`~BaseServer.handle_request` or :meth:`~BaseServer.serve_forever` method of the server object to process one or many requests. Finally, call :meth:`~BaseServer.server_close` -to close the socket. +to close the socket ( Unless you used the :keyword:`with` statement). When inheriting from :class:`ThreadingMixIn` for threaded connection behavior, you should explicitly declare how you want your threads to behave on an abrupt @@ -353,6 +354,11 @@ default implementation always returns :const:`True`. + .. versionadded:: 3.6 + Support for the :term:`context manager` protocol was added. Exiting the + context manager is equivalent to calling :meth:`server_close`. + + Request Handler Objects ----------------------- @@ -433,11 +439,11 @@ HOST, PORT = "localhost", 9999 # Create the server, binding to localhost on port 9999 - server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) + with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server: - # Activate the server; this will keep running until you - # interrupt the program with Ctrl-C - server.serve_forever() + # 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):: @@ -529,8 +535,8 @@ if __name__ == "__main__": HOST, PORT = "localhost", 9999 - server = socketserver.UDPServer((HOST, PORT), MyUDPHandler) - server.serve_forever() + with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server: + server.serve_forever() This is the client side:: @@ -591,23 +597,22 @@ # Port 0 means to select an arbitrary unused port HOST, PORT = "localhost", 0 - server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) - ip, port = server.server_address + with ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) as server: + 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.daemon = True - server_thread.start() - print("Server loop running in thread:", server_thread.name) + # 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.daemon = True + server_thread.start() + print("Server loop running in thread:", server_thread.name) - client(ip, port, "Hello World 1") - client(ip, port, "Hello World 2") - client(ip, port, "Hello World 3") + client(ip, port, "Hello World 1") + client(ip, port, "Hello World 2") + client(ip, port, "Hello World 3") - server.shutdown() - server.server_close() + server.shutdown() The output of the example should look something like this:: diff -r f555ef42ad62 Lib/socketserver.py --- a/Lib/socketserver.py Sun Feb 21 09:21:35 2016 -0800 +++ b/Lib/socketserver.py Sun Feb 21 22:44:42 2016 +0200 @@ -383,6 +383,12 @@ traceback.print_exc() print('-'*40, file=sys.stderr) + def __enter__(self): + return self + + def __exit__(self, *args): + self.server_close() + class TCPServer(BaseServer): diff -r f555ef42ad62 Lib/test/test_socketserver.py --- a/Lib/test/test_socketserver.py Sun Feb 21 09:21:35 2016 -0800 +++ b/Lib/test/test_socketserver.py Sun Feb 21 22:44:42 2016 +0200 @@ -100,11 +100,11 @@ self.test_files.append(fn) return fn - def make_server(self, addr, svrcls, hdlrbase): + @reap_threads + def run_server(self, svrcls, hdlrbase, testfunc): class MyServer(svrcls): def handle_error(self, request, client_address): self.close_request(request) - self.server_close() raise class MyHandler(hdlrbase): @@ -113,38 +113,31 @@ self.wfile.write(line) if verbose: print("creating server") - server = MyServer(addr, MyHandler) - self.assertEqual(server.server_address, server.socket.getsockname()) - return server + with MyServer(self.pickaddr(svrcls.address_family), MyHandler) as server: + self.assertEqual(server.server_address, server.socket.getsockname()) + # We had the OS pick a port, so pull the real address out of + # the server. + addr = server.server_address + if verbose: + print("ADDR =", addr) + print("CLASS =", svrcls) - @reap_threads - def run_server(self, svrcls, hdlrbase, testfunc): - server = self.make_server(self.pickaddr(svrcls.address_family), - svrcls, hdlrbase) - # We had the OS pick a port, so pull the real address out of - # the server. - addr = server.server_address - if verbose: - print("ADDR =", addr) - print("CLASS =", svrcls) - - t = threading.Thread( - name='%s serving' % svrcls, - target=server.serve_forever, - # Short poll interval to make the test finish quickly. - # Time between requests is short enough that we won't wake - # up spuriously too many times. - kwargs={'poll_interval':0.01}) - t.daemon = True # In case this function raises. - t.start() - if verbose: print("server running") - for i in range(3): - if verbose: print("test client", i) - testfunc(svrcls.address_family, addr) - if verbose: print("waiting for server") - server.shutdown() - t.join() - server.server_close() + t = threading.Thread( + name='%s serving' % svrcls, + target=server.serve_forever, + # Short poll interval to make the test finish quickly. + # Time between requests is short enough that we won't wake + # up spuriously too many times. + kwargs={'poll_interval':0.01}) + t.daemon = True # In case this function raises. + t.start() + if verbose: print("server running") + for i in range(3): + if verbose: print("test client", i) + testfunc(svrcls.address_family, addr) + if verbose: print("waiting for server") + server.shutdown() + t.join() self.assertEqual(-1, server.socket.fileno()) if verbose: print("done")