У меня есть сервер сокетов на основе 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
.
Как я могу заставить обработчик содержимого для соединения закрываться по требованию?На самом деле мне нужно прервать блокирующий вызов внутри цикла в обработчике контента, но как?