Twisted is explicit. If you kill a script that uses your protocol, it might die before data transmission finishes, unless you handle it yourself.
Transports provide the loseConnection
method that flushes the data to
the wire and then disconnects. All we have to do is wait for it to finish.
Predictably, it finishes asyncronously. Our Protocol
subclass can be notified though, by
implementing the connectionLost
method. The plan: provide a disconnect
method that calls transport.loseConnection
and returns a Deferred that we errback on connectionLost
.
class MyProtocol(Protocol): def __init__(self): self.disconnecting = None def connectionLost(self, reason): if self.disconnecting is not None: self.disconnecting.errback(reason) def disconnect(self): if self.disconnecting is None: self.disconnecting = Deferred() self.transport.loseConnection() return self.disconnecting
We can then ensure the client code will "wait" until the deferred errbacks
before continuing
@inlineCallbacks def use_my_protocol(): try: client = ClientCreator(reactor, MyProtocol) protocol = yield client.connectTCP("127.0.0.1", 8080) protocol.transport.write(r"foo") # here we would do some work yield protocol.disconnect() finally: returnValue(True)
In case we want to handle a signal and gracefully kill our program,
after all pending data is transmitted, we can register
a callback with the reactor using addSystemEventTrigger
. For example
reactor.addSystemEventTrigger("before", "shutdown", protocol.disconnect) reactor.callWhenRunning(my_main_function) reactor.run()