我有一个扭曲的ServerFactory,我正在用它来推动客户的工作。该协议包含一个包含所有作业的队列。如果客户端请求新作业,此队列耗尽后,服务器将断开客户端连接。最终这将不会保持客户端连接,服务器将准备关闭。
我的问题是:
我知道对于客户来说,最佳做法是使用twisted.internet.task.react来连接和处理连接丢失,从而关闭父进程。但我不确定服务器的情况是否也是如此。
目前这是我处理关闭的方式:
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
。
我很确定我之前已经阅读过这不是运行客户端所接受的模式,我认为服务器也是如此,但我还没有看到一个很好的例子。
答案 0 :(得分:1)
我不得不相信这个人。
完全不需要RunServer类。对ServerFactory
进行子类化并将RunServer.__init__
中的逻辑放入子类__init__
将允许更好的控制具有相同的行为。然后,您可以定义main
方法,并使用文档(twisted.internet.task.react
)
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])