Python:如何使用 Twisted 作为 SUDS 的传输方式?

Posted

技术标签:

【中文标题】Python:如何使用 Twisted 作为 SUDS 的传输方式?【英文标题】:Python: How can I use Twisted as the transport for SUDS? 【发布时间】:2011-02-09 21:41:11 【问题描述】:

我有一个基于 Twisted 的项目 与网络设备通信,我正在添加对新的支持 API 为 SOAP 的供应商 (Citrix NetScaler)。不幸的是 Twisted 中对 SOAP 的支持仍然依赖于 SOAPpy,这已经很糟糕了 日期。事实上,对于这个问题(我刚刚检查过),twisted.web.soap 本身甚至已经 21 个月没有更新了!

我想问一下是否有人愿意提供任何经验 与使用 Twisted 的出色异步传输分享 SUDS 的功能。好像插入了一个自定义的 Twisted 运输将非常适合SUDS'Client.options.transport,我只是有 很难绕开它。

我确实想出了一种使用 SUDS 调用 SOAP 方法的方法 通过使用twisted.internet.threads.deferToThread() 异步进行, 但这对我来说就像一个黑客攻击。

这是我所做的一个例子,给你一个想法:

# netscaler is a module I wrote using suds to interface with NetScaler SOAP
# Source: http://bitbucket.org/jathanism/netscaler-api/src
import netscaler
import os
import sys
from twisted.internet import reactor, defer, threads

# netscaler.API is the class that sets up the suds.client.Client object
host = 'netscaler.local'
username = password = 'nsroot'
wsdl_url = 'file://' + os.path.join(os.getcwd(), 'NSUserAdmin.wsdl')
api = netscaler.API(host, username=username, password=password, wsdl_url=wsdl_url)

results = []
errors = []

def handleResult(result):
    print '\tgot result: %s' % (result,)
    results.append(result)

def handleError(err):
    sys.stderr.write('\tgot failure: %s' % (err,))
    errors.append(err)

# this converts the api.login() call to a Twisted thread.
# api.login() should return True and is is equivalent to:
# api.service.login(username=self.username, password=self.password)
deferred = threads.deferToThread(api.login)
deferred.addCallbacks(handleResult, handleError)

reactor.run()

这按预期工作,并将 api.login() 调用的返回推迟到 它是完整的,而不是阻塞。但正如我所说,感觉不到 正确的。

提前感谢您的任何帮助、指导、反馈、批评, 侮辱,或整体解决方案。

更新:我找到的唯一解决方案是 twisted-suds,它是 Suds 的一个分支,经过修改后可以与 Twisted 一起使用。

【问题讨论】:

【参考方案1】:

transport 在 Twisted 上下文中的默认解释可能是 twisted.internet.interfaces.ITransport 的实现。在这一层,您基本上是在处理通过某种套接字(UDP、TCP 和 SSL 是最常用的三种)发送和接收的原始字节。这并不是 SUDS/Twisted 集成库真正感兴趣的内容。相反,您需要的是一个 HTTP 客户端,SUDS 可以使用该客户端发出必要的请求并显示所有响应数据,以便 SUDS 可以确定结果曾是。也就是说,SUDS 并不真正关心网络上的原始字节。它关心的是 HTTP 请求和响应。

如果您检查twisted.web.soap.Proxy(Twisted Web SOAP API 的客户端部分)的实现,您会发现它并没有真正做太多事情。大约 20 行代码将 SOAPpy 粘合到 twisted.web.client.getPage。也就是说,它以我上面描述的方式将 SOAPpy 连接到 Twisted。

理想情况下,SUDS 会提供类似于 SOAPpy.buildSOAPSOAPpy.parseSOAPRPC 的某种 API(也许 API 会更复杂一些,或者接受更多参数 - 我不是 SOAP 专家,所以我不知道 SOAPpy 的特定 API 是否遗漏了一些重要的东西——但基本思想应该是相同的)。然后,您可以改为基于 SUDS 编写类似 twisted.web.soap.Proxy 的内容。如果twisted.web.client.getPage 没有提供对请求的足够控制或关于响应的足够信息,您也可以改用twisted.web.client.Agent,它是最近引入的,对整个请求/响应过程提供了更多的控制。但同样,这与当前基于 getPage 的代码实际上是相同的想法,只是一个更灵活/更具表现力的实现。

刚刚查看了Client.options.transport 的 API 文档,听起来 SUDS 传输基本上是一个 HTTP 客户端。这种集成的问题在于 SUDS 想要发送请求,然后能够立即获得响应。由于 Twisted 主要基于 回调,因此基于 Twisted 的 HTTP 客户端 API 无法立即向 SUDS 返回响应。它只能返回一个Deferred(或等效项)。

这就是为什么如果关系颠倒,事情会变得更好。与其给 SUDS 一个 HTTP 客户端来玩,不如给 SUDS 和一个 HTTP 客户端给第三段代码,让它协调交互。

不过,不可能通过创建基于 Twisted 的 SUDS 传输(也称为 HTTP 客户端)来让事情正常进行。 Twisted 主要使用Deferred(又名回调)来公开事件这一事实并不意味着这是它可以工作的唯一方式。通过使用greenlet等第三方库,可以提供基于协程的API,其中异步操作的请求涉及将执行从一个协程切换到另一个,并通过切换回原始协程来传递事件.有一个名为corotwine 的项目可以做到这一点。 也许可以使用它为 SUDS 提供它想要的那种 HTTP 客户端 API;但是,不能保证。这取决于当上下文切换突然插入以前没有的位置时,SUDS 不会中断。这是 SUDS 的一个非常微妙和脆弱的属性,并且可以很容易地被 SUDS 开发人员在未来的版本中更改(甚至是无意的),所以它可能不是理想的解决方案,即使你能得到它现在就开始工作(除非你能得到 SUDS 维护者的合作,承诺以这种配置测试他们的代码,以确保它继续工作)。

顺便说一句,Twisted Web 的 SOAP 支持仍然基于 SOAPpy 并且近两年没有修改的原因是,没有出现任何明确的 SOAPpy 替代品。有很多竞争者(What SOAP client libraries exist for Python, and where is the documentation for them? 涵盖了其中的几个)。如果事情稳定下来,尝试更新 Twisted 的内置 SOAP 支持可能是有意义的。在那之前,我认为单独做这些集成库更有意义,这样它们可以更容易地更新,所以 Twisted 本身不会以一堆没人想要的不同 SOAP 集成而告终( 比目前的情况更糟,目前只有一个没有人想要的 SOAP 集成模块)。

【讨论】:

感谢您深思熟虑的回答。我绝对认为我是从错误的层面来解决这个问题的。默认情况下,SUDS 使用urllib2 作为客户端,所以也许 Twisted 的代理是一个不错的起点。肯定也会给corotwine 看看。我将不得不吸收这些信息并跟进!此外,我对 Twisted SOAP 传奇感到痛苦,尽管 SUDS 似乎是近来最有力的竞争者,而且肯定是我的最爱。 我一直在参考这个答案,所以我认为我在正确的轨道上。再次感谢! @jathanism,你找到解决方案了吗?我处于类似的情况(尽管修改了 HTTP 身份验证处理程序以解决 Microsoft 的 NTLM-mislabelled-as-SPNEGO 错误)。 在第一段中,“SUDS 可以使用的 HTTP 客户端”等描述了 suds 所称的传输,这与 Twisted 传输非常不同。

以上是关于Python:如何使用 Twisted 作为 SUDS 的传输方式?的主要内容,如果未能解决你的问题,请参考以下文章

Python:Twisted:如何从回调中访问列表

Python3 Twisted Mysql错误

Python/Twisted IRC 机器人日志记录问题

您如何通过 Python(而不是通过 Twisted)运行 Twisted 应用程序?

您如何通过Python(而不是通过Twisted)运行Twisted应用程序?

Python + Twisted + FtpClient + SOCKS