首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在twisted.protocols.ftp.FTP中实现REST?

在twisted.protocols.ftp.FTP中实现REST?
EN

Stack Overflow用户
提问于 2010-11-29 15:23:20
回答 2查看 1.6K关注 0票数 1

是否有人能在twisted的FTP服务器中实现REST命令?我目前的尝试是:

代码语言:javascript
复制
from twisted.protocols import ftp
from twisted.internet import defer

class MyFTP(ftp.FTP):
    def ftp_REST(self, pos):
        try:
            pos = int(pos)
        except ValueError:
            return defer.fail(CmdSyntaxError('Bad argument for REST'))

        def all_ok(result):
            return ftp.REQ_FILE_ACTN_PENDING_FURTHER_INFO # 350

        return self.shell.restart(pos).addCallback(all_ok)

class MyShell(ftp.FTPShell):
    def __init__(self, host, auth):
        self.position = 0
        ...

    def restart(self, pos):
        self.position = pos
        print "Restarting at %s"%pos
        return defer.succeed(pos)

当客户端发送REST命令时,在脚本输出中看到这个命令需要几秒钟时间:

代码语言:javascript
复制
Traceback (most recent call last):
Failure: twisted.protocols.ftp.PortConnectionError: DTPFactory timeout
Restarting at <pos>

我做错了什么?在我看来,应该立即响应REST命令,为什么套接字超时?

更新:

在启用Jean-Paul Calderone建议的日志记录之后,在DTP连接因缺乏连接而超时之前,REST命令甚至都没有到达我的FTP类(时间戳简化为MM:SS以表示简洁):

代码语言:javascript
复制
09:53 [TrafficLoggingProtocol,1,127.0.0.1] cleanupDTP
09:53 [TrafficLoggingProtocol,1,127.0.0.1] <<class 'twisted.internet.tcp.Port'> of twisted.protocols.ftp.DTPFactory on 37298>
09:53 [TrafficLoggingProtocol,1,127.0.0.1] dtpFactory.stopFactory
09:53 [-] (Port 37298 Closed)
09:53 [-] Stopping factory <twisted.protocols.ftp.DTPFactory instance at 0x8a792ec>
09:53 [-] dtpFactory.stopFactory
10:31 [-] timed out waiting for DTP connection
10:31 [-] Unexpected FTP error
10:31 [-] Unhandled Error
        Traceback (most recent call last):
        Failure: twisted.protocols.ftp.PortConnectionError: DTPFactory timeout

10:31 [TrafficLoggingProtocol,2,127.0.0.1] Restarting at 1024

ftp_PASV命令返回DTPFactory.deferred,它被描述为“在连接实例时触发的延迟”。RETR命令很好(否则ftp.FTP将毫无价值)。

这使我相信,这里有某种阻塞操作,在DTP连接完成之前不会发生任何其他事情;然后,只有这样,我们才能接受进一步的命令。不幸的是,它看起来像是一些(全部?)客户端(特别是,我正在用FileZilla进行测试)在尝试恢复下载时,在连接之前发送REST命令。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-01-19 15:42:08

在深入挖掘源代码和篡改想法之后,我确定了这一解决方案:

代码语言:javascript
复制
class MyFTP(ftp.FTP):
  dtpTimeout = 30

  def ftp_PASV(self):
    # FTP.lineReceived calls pauseProducing(), and doesn't allow
    # resuming until the Deferred that the called function returns
    # is called or errored.  If the client sends a REST command
    # after PASV, they will not connect to our DTP connection
    # (and fire our Deferred) until they receive a response.
    # Therefore, we will turn on producing again before returning
    # our DTP's deferred response, allowing the REST to come
    # through, our response to the REST to go out, the client to
    # connect, and everyone to be happy.
    resumer = reactor.callLater(0.25, self.resumeProducing)
    def cancel_resume(_):
      if not resumer.called:
        resumer.cancel()
      return _
    return ftp.FTP.ftp_PASV(self).addBoth(cancel_resume)
  def ftp_REST(self, pos):
    # Of course, allowing a REST command to come in does us no
    # good if we can't handle it.
    try:
      pos = int(pos)
    except ValueError:
      return defer.fail(CmdSyntaxError('Bad argument for REST'))

    def all_ok(result):
      return ftp.REQ_FILE_ACTN_PENDING_FURTHER_INFO

    return self.shell.restart(pos).addCallback(all_ok)

class MyFTPShell(ftp.FTPShell):
  def __init__(self, host, auth):
    self.position = 0

  def restart(self, pos):
    self.position = pos
    return defer.succeed(pos)

callLater方法有时可能会变小,但它在大多数情况下都能工作。显然,这是你自己承担的风险。

票数 1
EN

Stack Overflow用户

发布于 2010-11-29 17:15:18

验证客户端的行为是否与您预期的一样。使用tcpdump或wireshark捕获所有相关通信量是一种很好的方法,尽管您也可以通过多种方式(例如,通过使用工厂包装器twisted.protocols.policies.TrafficLoggingFactory)在基于Twisted的FTP服务器中启用日志记录。

从超时错误到“重新启动.”日志消息,我想是客户端发送了一个RETR‘第一个’,然后是一个REST。RETR超时是因为客户端直到收到对其余部分的响应后才尝试连接到数据通道,而Twisted服务器甚至在客户端连接到数据通道(并下载整个文件)之后才会处理其余部分。解决这个问题可能需要改变ftp.FTP从客户端处理命令的方式,这样就可以正确地解释REST (或者您正在使用的FTP客户端仅仅是错误的,根据我可以找到的协议文档,RETR应该遵循REST,而不是相反)。

不过,这只是猜测,您应该查看流量捕获来确认或拒绝它。

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

https://stackoverflow.com/questions/4305127

复制
相关文章

相似问题

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