首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当reactor.stop被调用时,扭曲不会退出

当reactor.stop被调用时,扭曲不会退出
EN

Stack Overflow用户
提问于 2015-11-13 12:34:53
回答 1查看 2.5K关注 0票数 2

我试图在Python中重新实现netcat:

代码语言:javascript
复制
#!/usr/bin/env python2

from sys import stdin, stdout

from twisted.internet import reactor
from twisted.internet.protocol import Protocol
from twisted.internet.endpoints import TCP4ClientEndpoint, connectProtocol

class NcClient(Protocol):
    def dataReceived(self, data):
            stdout.write(data)

    def sendData(self, data):
        self.transport.write(data)
        self.transport.write("\n")

client = NcClient()

def cmdloop():
    while True:
        line = stdin.readline()
        if line == "":
            break
        else:
            client.sendData(line)
    if reactor.running:
        reactor.stop()

point = TCP4ClientEndpoint(reactor, "localhost", 6004)
connectProtocol(point, client)
reactor.callInThread(cmdloop)
reactor.run()

cmdloop检测到输入结束时,它调用reactor.stop。据我所知,reactor.stop将关机事件发送给Twisted管理的所有事物,如线程、连接等。响应这些事件,连接被关闭,线程等待它们的过程完成等等。因此,当调用reactor.stop()时,到localhost的连接:6004应该关闭,程序应该退出。

但是,这种情况不会立即发生,而只有当NcClient收到来自服务器的消息时才会发生。就好像它正在阻塞地读取这些消息一样,只在一个循环中,并且只有当它收到一个消息时,它才会继续处理关闭请求。

如何在收到消息之前关闭它?我知道reactor.crash(),但还有更礼貌的选择吗?

EN

回答 1

Stack Overflow用户

发布于 2015-12-10 02:02:16

您的主要问题是cmdloop运行在一个非反应堆线程中,但是它调用的是callFromThread以外的反应堆方法(具体来说是:transport.write通过client.sendData)。The 这方面的文档是非常清楚的。

除非另有说明,Twisted中的方法只能从反应堆线程调用。Twisted中很少有东西是线程安全的。

幸运的是,实现等价的netcat根本不需要线程处理。您可以简单地使用Twisted对标准I/O的内置支持作为数据源。下面是一个示例版本:

代码语言:javascript
复制
import sys

from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory
from twisted.internet.endpoints import clientFromString
from twisted.internet.stdio import StandardIO

class NcClient(Protocol):
    def __init__(self, forwardTo):
        self.forwardTo = forwardTo

    def connectionMade(self):
        self.transport.registerProducer(self.forwardTo.transport, True)
        self.forwardTo.transport.resumeProducing()
        self.forwardTo.transport.registerProducer(self.transport, True)

    def dataReceived(self, data):
        self.forwardTo.transport.write(data)

    def connectionLost(self, reason):
        reactor.stop()

class StdIo(Protocol):
    def connectionMade(self):
        self.transport.pauseProducing()
        f4p = Factory.forProtocol(lambda: NcClient(self))
        d = endpoint.connect(f4p)
        @d.addCallback
        def connected(proto):
            self.client = proto

    def dataReceived(self, data):
        self.client.transport.write(data)

    def connectionLost(self, reason):
        reactor.stop()

endpoint = clientFromString(reactor, sys.argv[1])

output = StandardIO(proto=StdIo(), reactor=reactor)

reactor.run()

如果出于某种原因仍然希望使用线程,可以修改NcClient以使用callFromThread来调用sendData,而不是直接调用它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33692874

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档