【问题标题】:Python twisted: A server that writes to the connection after an asynchronous operation?Python 扭曲:异步操作后写入连接的服务器?
【发布时间】:2012-08-13 19:59:02
【问题描述】:

我有一个服务器,我在其中实现了 NetstringReceiver 协议的子协议。我希望它根据客户端的请求执行异步操作(使用 txredisapi),然后以操作结果进行响应。我的代码的概括:

class MyProtocol(NetstringReceiver):
  def stringReceived(self, request):
    d = async_function_that_returns_deferred(request)
    d.addCallback(self.respond)
    # self.sendString(myString)

  def respond(self, result_of_async_function):
    self.sendString(result_of_async_function)

在上面的代码中,连接到我的服务器的客户端没有得到响应。但是,如果我取消注释,它确实会得到 myString

# self.sendString(myString)

我也知道 result_of_async_function 是一个非空字符串,因为我将它打印到 stdout 。

我该怎么做才能让我用异步函数的结果响应客户端?

更新:可运行的源代码

from twisted.internet import reactor, defer, protocol
from twisted.protocols.basic import NetstringReceiver
from twisted.internet.task import deferLater

def f():
  return "RESPONSE"

class MyProtocol(NetstringReceiver):
  def stringReceived(self, _):
    d = deferLater(reactor, 5, f)
    d.addCallback(self.reply)
    # self.sendString(str(f())) # Note that this DOES send the string.

  def reply(self, response):
    self.sendString(str(response)) # Why does this not send the string and how to fix?

class MyFactory(protocol.ServerFactory):
  protocol = MyProtocol

def main():
  factory = MyFactory()
  from twisted.internet import reactor
  port = reactor.listenTCP(8888, factory, )
  print 'Serving on %s' % port.getHost()
  reactor.run()

if __name__ == "__main__":
  main()

【问题讨论】:

  • 你不应该在某个地方有reactor.callLater(X, d.callback, ...)吗?
  • 以上代码只是我认为相关的部分。我有一个使用这个协议的工厂,我调用 reactor.listenTCP(port, factory, )。
  • 你能把这个例子填写得更详细些吗?使其完整且可运行?您在这里的想法是正确的,这意味着问题出在细节上,因此为了回答您的问题,我需要查看细节。您可以使用twisted.internet.task.deferLater 模拟异步操作以进行演示。
  • @Glyph,感谢您的意见。我已经编写了说明问题的可运行代码。以防万一我在运行它的方式上做错了什么: 1. 我运行文件:python example.py 2. 在另一个 shell 中:nc localhost 8888 1:a,在这种情况下,我确实收到了来自注释掉的 sendString 但不是来自内部的 sendString 回复(self,response) P.S:抱歉回复晚了,我之前回复过,但刚刚发现 [at]username 功能

标签: python networking asynchronous twisted deferred


【解决方案1】:

NetstringReceiver 有一个特殊功能:

如果收到非法消息,连接将丢失

你确定你的消息符合djb's Netstring protocol吗?

显然客户端发送了无法解析的非法字符串,协议条件导致连接丢失。 您的代码中的其他一切看起来都不错

如果你不需要那个特定的协议,你最好继承LineReceiver而不是NetstringReceiver

【讨论】:

  • 感谢您的回答。如果一切都失败了,我可能会使用 LineReceiver 协议重新编写,但我还没有准备好放弃 NetstringReceiver。我相当确定我的问题与格式错误无关(我相信 NetstringReceiver 会为我处理格式)。就像我说的,注释掉的 sendString 确实有效,所以我相当肯定它与我使用延迟的方式有关。我实际上怀疑连接在延迟触发之前关闭..
  • 你是对的,如果你使用的是 sendString(而不是 transport.write)NetstringReceiver 应该为你自己处理网络字符串的语法。
  • 所以我最终决定切换到 LineReceiver 并且它起作用了。我仍然不确定为什么 NetstringReceiver 不起作用,因为我相当确定我正确使用了它。也许它是一个错误?注意:如果你使用 lineReceiver,你应该使用 telnet 而不是 netcat(因为分隔符问题)
【解决方案2】:

您从未收到响应的原因是,在发送响应时,连接已关闭。连接关闭的原因是您使用“nc”发送的消息是:
1:a,\n
因为您必须键入换行符才能让 nc 发送消息,但 nc 将其作为消息的一部分包含在内。这违反了 NetString 协议... 我通过发送此消息来解决它(您的代码修改了一些额外的打印):
1:a,40:\n blahblahblah这里不要回车,等待回复
8:RESPONSE,

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多