Python 关闭twisted服务器

Python 关闭twisted服务器,python,tcp,server,twisted,Python,Tcp,Server,Twisted,我有一个怪癖,我用它把工作推给客户。该协议包含一个包含所有作业的队列。如果客户机请求新作业,则此队列耗尽后,服务器将断开客户机的连接。最终,这将使客户端无法连接,服务器将准备关闭 我的问题是: 一旦ServerFactory完成工作,是否有一个公认的最佳做法来关闭它? 我知道,对于客户端来说,最佳做法是使用连接和处理连接丢失,从而关闭父进程。但我不确定服务器是否也是如此 目前,我是这样处理关闭的: from twisted.application import internet, service

我有一个怪癖,我用它把工作推给客户。该协议包含一个包含所有作业的队列。如果客户机请求新作业,则此队列耗尽后,服务器将断开客户机的连接。最终,这将使客户端无法连接,服务器将准备关闭

我的问题是:

一旦ServerFactory完成工作,是否有一个公认的最佳做法来关闭它? 我知道,对于客户端来说,最佳做法是使用连接和处理连接丢失,从而关闭父进程。但我不确定服务器是否也是如此

目前,我是这样处理关闭的:

from twisted.application import internet, service
from twisted.internet import reactor
from twisted.internet.protocol import ServerFactory
from twisted.protocols.basic import LineReceiver


class ServerProtocol(LineReceiver):
    """Twisted Protocol for sending and receiving lines of bytes."""
    clients = []
    logger = logging.getLogger('launcher.Launcher.RunServer')

    def connectionMade(self) -> None:
        """When a connection is made add the client to the clients list."""
        self.clients.append(self)

    def lineReceived(self, line: bytes) -> None:
        """Whenver a line is received send work to the sending client.

        Parameters
        ----------
        line
            The message received from a client.

        """
        msg = 'Received: ' + line.decode('utf-8') + ' from ' +\
            self.transport.hostname
        self.logger.info(msg)
        if not self.queue.empty():
            run = self.queue.get()
            run_bytes = bytes(run, 'utf-8')
            self.logger.info('Sending run bytes to %s',
                             self.transport.hostname)
            self.sendLine(run_bytes)
        else:
            self.clients.remove(self)
            self.transport.loseConnection()
            if not self.clients:
                self.logger.info('Shutting down RunServer')
                self.reactor.stop()


class RunServer(object):
    """Class for containing twisted server components.

    Parameters
    ----------
    workers
        List of workers that will serve as clients.
    queue
        Queue of runs to execute.

    Attributes
    ----------
    factory
        Twisted ServerFactory for producing protocols.

    """
    def __init__(self, queue: Queue) -> None:
        self.factory = ServerFactory()
        self.factory.protocol = ServerProtocol
        self.factory.protocol.queue = queue
        self.factory.protocol.reactor = reactor

    def start(self) -> None:
        """Start the server and thereby the execution of runs."""
        self.factory.protocol.reactor.listenTCP(80, self.factory)
        self.factory.protocol.reactor.run()
如您所见,我正在将反应器存储在
self.factory.protocol.reactor
中,并在所有作业用完且客户端断开连接后使用
reactor.stop


我很确定我以前读过,这不是运行客户机的公认模式,我假设服务器也是如此,但我还没有看到一个好的例子。

我必须相信我熟悉这个例子

绝对不需要RunServer类。子类化
ServerFactory
并将逻辑从
RunServer.\uuuu init\uuu
放入子类
\uuuuu init\uuuu
将允许相同的行为,并具有更好的控制。然后您可以定义一个
main
方法,并使用
react
,如文档中所述()

以下是更新的代码:

from twisted.internet.defer import Deferred
from twisted.internet import reactor
from twisted.internet.protocol import ServerFactory
from twisted.protocols.basic import LineReceiver


class QueueingProtocol(LineReceiver):
    def connectionMade(self) -> None:
        self.factory.connectionMade()

    def connectionLost(self, reason) -> None:
        self.factory.connectionLost(reason)

    def lineReceived(self, line: bytes) -> None:
        msg = 'Received: ' + line.decode('utf-8') + ' from ' +\
            self.transport.hostname
        self.logger.info(msg)
        if self.factory.empty():
            self.transport.lostConnection()
        else:
            run = self.factory.get()
            run_bytes = bytes(run, 'utf-8')
            self.logger.info('Sending run bytes to %s',
                             self.transport.hostname)
            self.sendLine(run_bytes)


class QueueingFactory(ServerFactory):
    protocol = QueueingProtocol

    def __init__(self, queue) -> None:
        self.queue = queue
        self.connections = 0
        self.queueHandled = Deferred()

    def connectionMade(self) -> None:
        self.connections += 1

    def empty(self):
        return self.queue.empty()

    def get(self):
        return self.queue.get()

    def connectionLost(self, reason) -> None:
        self.connections -= 1
        if self.connections == 0 and self.empty():
            self.queueHandled.callback("done")


def main(reactor, queue):
    factory = QueueingFactory(queue)
    reactor.listenTCP(80, factory)
    return factory.queueHandled

然后您可以在需要的地方导入
main
,并调用
react(main,[some_queue])

这没有什么明显的“错误”design@notorious.no我同意,但根据文档
react
“是一种使用定义良好的完成条件启动应用程序的方法。”在这个AWS和Docker服务器的新时代,停止将更为常见。大多数当前的twisted服务器持续运行。我想向你重申你的剧本是有效的。很好的回答顺便说一句