To address the issue where Python’s http.server module doesn’t close sockets automatically, we’ll create a custom HTTPServer subclass that ensures all sockets are closed upon shutdown. Here’s how to implement it:
Solution Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
import http.server import socket import sys class CustomHTTPServer(http.server.HTTPServer): def __init__(self, server_address, RequestHandlerClass): super().__init__(server_address, RequestHandlerClass) self._base_sockets = [] def _get_socket(self, sock): “”“Helper method to add sockets to the list for later cleanup.”“” self._base_sockets.append(sock) def close_sockets(self): “”“Closes all open sockets associated with the server.”“” for sock in self._base_sockets: try: sock.close() except socket.error: pass def shutdown(self): “”“Shuts down the server and closes all associated sockets.”“” super().shutdown() self.close_sockets() def run_server(): server_address = (”, 8000) handler = http.server.SimpleHTTPRequestHandler server = CustomHTTPServer(server_address, handler) try: server.serve_forever() except KeyboardInterrupt: print(“\nShutting down the server…”) server.shutdown() finally: server.close_sockets() if __name__ == “__main__”: run_server() |
Explanation
- CustomHTTPServer Class:
- Inherits from http.server.HTTPServer.
- Maintains a list of sockets ( _base_sockets) to track all open connections.
-
Overrides the shutdown() method to close all sockets before calling the parent’s shutdown.
-
close_sockets() Method:
- Iterates over _base_sockets and closes each socket using sock.close().
-
Uses a try-except block to handle any potential errors during closure.
-
run_server() Function:
- Creates an instance of CustomHTTPServer.
- Starts the server with server.serve_forever(), which handles requests until interrupted.
- On interruption, it calls server.shutdown(), ensuring all sockets are closed properly.
This solution ensures that when the server is stopped, either through a keyboard interrupt or other means, all associated sockets are gracefully closed, preventing resource leaks.