【问题标题】:Python Twisted: separate protocol from processingPython Twisted:将协议与处理分开
【发布时间】:2014-01-27 17:54:56
【问题描述】:

我想实现一个自己的基于 TCP 的协议,以便在 Twisted 之上的服务器中使用。这种协议实现的机制很明确(从 Protocol 继承并覆盖四个继承的方法,构建 Factory)。

但是,我希望我的协议与应用程序逻辑分开,以这样的方式:

  • 协议:从客户端接收数据,解码字节流并填充 Python 数据结构,获取数据结构,编码为字节流(基于文本)并响应客户端

  • 应用逻辑:接收所述数据结构,评估并返回响应数据结构

我将如何以一种既不依赖另一个方式(即松散耦合)的方式构建 Twisted 应用程序?我会想象协议类将使用应用程序逻辑回调作为参数来实例化?

编辑:

与此同时,我有这个:

from twisted.internet.protocol import Protocol
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet import reactor

class Logic:
    def process(self, data):
        return "Processed: %s" % data

class LineProtocol(Protocol):
    def dataReceived(self, data):
        print "Received: %s" % data
        if self.factory._logic_callback:
            ret = self.factory._logic_callback.process(data)
            print "Sent: %s" % ret
            self.transport.write(ret)

class LineFactory(Factory):
    protocol = LineProtocol

    def __init__(self, logic_callback = None):
        if logic_callback:
            self._logic_callback = logic_callback()
        else:
            self._logic_callback = None

endpoint = TCP4ServerEndpoint(reactor, 1234)
endpoint.listen(LineFactory(Logic))
reactor.run()

你会认为这是“扭曲”的方式吗?有什么需要改进的吗?

代码在 LineFactory 内创建一个逻辑实例。放在那里好吗?

【问题讨论】:

  • 到目前为止你得到了什么?
  • process 是使用任何库的任何语言中最糟糕的方法名称之一。
  • @Jean-PaulCalderone:同意,请原谅我在此示例上下文中使用它。

标签: python protocols twisted


【解决方案1】:

请注意,您的计划中已经有了一个松散耦合的示例。处理 TCP 实现细节的传输与您的协议是分开的,这两个对象通过一个定义明确的接口进行交互:dataReceived 等在协议上,write 等在传输上。

只需将这个想法再扩展一步。让您的应用程序对象和协议通过定义明确的接口进行交互。应用程序对象是否作为__init__ 参数提供给协议在某种程度上取决于预期的交互。如果应用程序是纯反应式的(即,它只是对协议上发生的事情做出反应,它本身不会启动事情),那么这是一个好方法。如果应用程序对驱动操作更感兴趣(例如,考虑驱动 HTTP 客户端协议的应用程序:在应用程序决定要发送请求之前,网络上什么都不会发生),那么您可能需要明确定义一个接口让您的协议具有应用程序预期使用的特性(例如,HTTP 客户端协议可能具有采用 URL、HTTP 方法等的 request 方法)。

请记住,有一些很好的 API 可以为您提供新的协议实例。例如:

from sys import argv

from twisted.internet.protocol import Protocol
from twisted.internet.endpoints import connectProtocol, clientFromString
from twisted.internet.task import react

def main(reactor, description):
    endpoint = clientFromString(reactor, description)
    connecting = connectProtocol(endpoint, Protocol())
    def connected(protocol):
        # Now `protocol` is connected somewhere and you can start
        # calling useful methods on it, if it has any.
        ...
    connecting.addCallback(connected)
    return connecting

react(main, argv[1:])

将一些有用的代码放入connected,将Protocol() 替换为您更有趣的协议类的实例,然后使用an argument like "tcp:localhost:25" 运行。

从你的例子:

def dataReceived(self, data):
    print "Received: %s" % data
    if self.factory._logic_callback:
        ret = self.factory._logic_callback.process(data)
        print "Sent: %s" % ret
        self.transport.write(ret)

这并没有什么好处。你实际上并没有在你的协议中实现任何协议逻辑。你所做的就是让self.factory._logic_callback 负责实现协议。这是几个额外的对象,没有真正的好处。我不建议这样做。

您想在协议类中进行所有解析和序列化。仅将根据结构化对象(您所做的任何解析的输出)实现的更高级别的逻辑委托给协议以外的事物。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-10
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多