Twisted - 在子进程中使用 adoptStreamConnection 后,如何告诉反应器处理协议对象?
Twisted - How can I tell the reactor to dispose a Protocol object after using adoptStreamConnection in a subprocess?
我正在尝试使用 adoptStreamConnection 将 TCP 连接传递给 Twisted 子进程,但我无法弄清楚如何在完成后将进程释放到主进程中。
我想要的流程是这样的:
- 完成写入协议传输等待的任何数据
- 当我们知道写入缓冲区为空时发送 AMP 消息以将套接字传输到子进程
- 在主进程中配置协议实例
我尝试什么都不做,loseConnection、abortConnection,以及猴子修补 _socketClose 并使用 loseConnection。请在此处查看代码:
import weakref
from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.python.sendmsg import getsockfam
from twisted.internet.protocol import Factory, Protocol
import twisted.internet.abstract
class EchoProtocol(Protocol):
def dataReceived(self, data):
self.transport.write(data)
class EchoFactory(Factory):
protocol = EchoProtocol
class TransferProtocol(Protocol):
def dataReceived(self, data):
self.transport.write('main process still listening!: %s' % (data))
def connectionMade(self):
self.transport.write('this message should make it to the subprocess\n')
# attempt 1: do nothing
# everything works fine in the adopt (including receiving the written message), but old protocol still exists (though isn't doing anything)
# attempt 1: try calling loseConnection
# we lose connection before the adopt opens the socket (presumably TCP disconnect message was sent)
#
# self.transport.loseConnection()
# attempt 2: try calling abortConnection
# result is same as loseConnection
#
# self.transport.abortConnection()
# attempt 3: try monkey patching the socket close out and calling loseConnection
# result: same as doing nothing-- adopt works (including receiving the written message), old protocol still exists
#
# def ignored(*args, **kwargs):
# print 'ignored :D'
#
# self.transport._closeSocket = ignored
# self.transport.loseConnection()
reactor.callLater(0, adopt, self.transport.fileno())
class ServerFactory(Factory):
def buildProtocol(self, addr):
p = TransferProtocol()
self.ref = weakref.ref(p)
return p
f = ServerFactory()
def adopt(fileno):
print "does old protocol still exist?: %r" % (f.ref())
reactor.adoptStreamConnection(fileno, getsockfam(fileno), EchoFactory())
port = 1337
endpoint = TCP4ServerEndpoint(reactor, port)
d = endpoint.listen(f)
reactor.run()
在所有情况下,协议对象在套接字传输后仍然存在于主进程中。我该如何清理它?
提前致谢。
loseConnection
和 abortConnection
都没有告诉反应堆 "forget" 连接;他们关闭连接,这是非常不同的;他们告诉 peer 连接已经断开。
您想调用 self.transport.stopReading()
和 self.transport.stopWriting()
从反应器中删除对它的引用。
此外,除非您先调用 gc.collect()
,否则使用弱引用来测试对象的剩余存在是无效的。
至于确保所有数据都已发送:唯一可靠的方法是 application-level 确认您已发送的数据。这就是为什么需要涉及更改协议的握手的协议——例如,STARTTLS
——有一个特定的握手,其中发起者说 "I'm going to switch"(然后停止发送),然后对等方说 "OK, you can switch now"。在这种情况下,另一种处理方法是通过其他渠道将您想要写入的数据传递给子进程,而不是将其传递给 transport.write
.
我正在尝试使用 adoptStreamConnection 将 TCP 连接传递给 Twisted 子进程,但我无法弄清楚如何在完成后将进程释放到主进程中。
我想要的流程是这样的:
- 完成写入协议传输等待的任何数据
- 当我们知道写入缓冲区为空时发送 AMP 消息以将套接字传输到子进程
- 在主进程中配置协议实例
我尝试什么都不做,loseConnection、abortConnection,以及猴子修补 _socketClose 并使用 loseConnection。请在此处查看代码:
import weakref
from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.python.sendmsg import getsockfam
from twisted.internet.protocol import Factory, Protocol
import twisted.internet.abstract
class EchoProtocol(Protocol):
def dataReceived(self, data):
self.transport.write(data)
class EchoFactory(Factory):
protocol = EchoProtocol
class TransferProtocol(Protocol):
def dataReceived(self, data):
self.transport.write('main process still listening!: %s' % (data))
def connectionMade(self):
self.transport.write('this message should make it to the subprocess\n')
# attempt 1: do nothing
# everything works fine in the adopt (including receiving the written message), but old protocol still exists (though isn't doing anything)
# attempt 1: try calling loseConnection
# we lose connection before the adopt opens the socket (presumably TCP disconnect message was sent)
#
# self.transport.loseConnection()
# attempt 2: try calling abortConnection
# result is same as loseConnection
#
# self.transport.abortConnection()
# attempt 3: try monkey patching the socket close out and calling loseConnection
# result: same as doing nothing-- adopt works (including receiving the written message), old protocol still exists
#
# def ignored(*args, **kwargs):
# print 'ignored :D'
#
# self.transport._closeSocket = ignored
# self.transport.loseConnection()
reactor.callLater(0, adopt, self.transport.fileno())
class ServerFactory(Factory):
def buildProtocol(self, addr):
p = TransferProtocol()
self.ref = weakref.ref(p)
return p
f = ServerFactory()
def adopt(fileno):
print "does old protocol still exist?: %r" % (f.ref())
reactor.adoptStreamConnection(fileno, getsockfam(fileno), EchoFactory())
port = 1337
endpoint = TCP4ServerEndpoint(reactor, port)
d = endpoint.listen(f)
reactor.run()
在所有情况下,协议对象在套接字传输后仍然存在于主进程中。我该如何清理它?
提前致谢。
loseConnection
和 abortConnection
都没有告诉反应堆 "forget" 连接;他们关闭连接,这是非常不同的;他们告诉 peer 连接已经断开。
您想调用 self.transport.stopReading()
和 self.transport.stopWriting()
从反应器中删除对它的引用。
此外,除非您先调用 gc.collect()
,否则使用弱引用来测试对象的剩余存在是无效的。
至于确保所有数据都已发送:唯一可靠的方法是 application-level 确认您已发送的数据。这就是为什么需要涉及更改协议的握手的协议——例如,STARTTLS
——有一个特定的握手,其中发起者说 "I'm going to switch"(然后停止发送),然后对等方说 "OK, you can switch now"。在这种情况下,另一种处理方法是通过其他渠道将您想要写入的数据传递给子进程,而不是将其传递给 transport.write
.