Как я могу корректно завершить работу своего TCP-сервера на основе Python? - PullRequest
0 голосов
/ 25 мая 2018

У меня есть сервер сокетов на основе Python 3, который прослушивает соединение TCP.Он работает отлично, но теперь я хочу иметь возможность корректно завершить работу всего приложения, даже если к серверу подключено еще одно или несколько клиентов.

Следующий код должен просто продемонстрировать структуру, которую я удалилнекоторые функции, которые не важны для вопроса:

    def createContentHandler(server = None):
        """
        Creates TCP Request Handler with given message handler
        """
        class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
            def handle(self):
                """
                Request handler in a loop receives and handles message and send back response
                """
                id = threading.get_ident()
                sock = self.request
                try:
                    while True:
                        msg = self.receiveMessage()
                        data = msg.decode("utf-8")
                        response = server._msghandler.handle(data)
                        self.sendMessage(response)
                except ConnectionResetError as e:
                    sock.close()
                    print("socket close by client")
                except Exception as e:
                    sock.close()
                    print("socket close by other reason")




        return ThreadedTCPRequestHandler

    #======================== CLASS =====================================       

    class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
        """
        Handle each request in a separate thread.
        """

    #======================== CLASS =====================================       

    class Socket_Server():

        def __init__(self, *, adress, port, msghandler):
            super(Socket_Server, self).__init__()
            self._adress = adress
            self._port = port
            self._msghandler = msghandler


        def run(self):
            print('TCP socket server starting...')
            server_address = (self._adress, self._port)
            tcpHandler = createContentHandler(self) 
            print('TCP socket server is running.')
            with ThreadedTCPServer(server_address, tcpHandler) as server:
                self._server = server
                server.serve_forever(0.5)

        def shutdown(self):
            if self._server is not None:
                self._server.shutdown()
                self._server.server_close()
                print("Server is shut down")

В принципе, сервер запускается server.serve_forever() и (благодаря некоторому волшебству) обработчик содержимого запускается в отдельном потоке для каждого соединения.

Обработчик содержимого вызывает self.receiveMessage(), который внутренне вызывает sock.recv(count) для получения данных из сокета.Этот вызов блокируется.

Когда я хочу закрыть приложение, я вызываю shutdown() на сервере из основного потока.Я получаю сообщение "Server is shut down", но приложение все еще висит в месте, где выполняется блокировка получения.Только после того, как все клиенты были отключены, приложение полностью закрывается из-за обработки ConnectionResetError.

Как я могу заставить обработчик содержимого для соединения закрываться по требованию?На самом деле мне нужно прервать блокирующий вызов внутри цикла в обработчике контента, но как?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...