【问题标题】:ftplib python: NOOP command works in ASCII not Binaryftplib python:NOOP 命令在 ASCII 而不是二进制中工作
【发布时间】:2013-11-24 12:51:59
【问题描述】:

我有一个线程化的 FTP 脚本。在数据套接字接收数据时,线程循环会向控制套接字发送 NOOP 命令,以在大传输期间保持控制连接处于活动状态。

我无法使用FTP.retrbinary() 命令,因为如果我想保持控制连接处于活动状态,我必须将retrbinary 不做的数据和控制套接字分开。

代码如下:

def downloadFile(filename, folder):
    myhost = 'HOST'
    myuser = 'USER'
    passw = 'PASS'
    #login
    ftp = FTP(myhost,myuser,passw)

    ftp.set_debuglevel(2)
    ftp.voidcmd('TYPE I')
    sock = ftp.transfercmd('RETR ' + filename)
    def background():
        f = open(folder + filename, 'wb')
        while True:
            block = sock.recv(1024*1024)
            if not block:
                break
            f.write(block)
        sock.close()
    t = threading.Thread(target=background)
    t.start()
    while t.is_alive():
        t.join(120)
        ftp.voidcmd('NOOP')
    ftp.quit();


我的问题:FTP.transfercmd("RETR " + filename) 默认为 ASCII 传输,而我传输视频,所以它必须是二进制(因此 ftp.voidcmd('TYPE I) 调用强制二进制模式)。

如果我不要调用ftp.voidcmd('TYPE I),则NOOP命令发送成功,输出如下:

*cmd* 'NOOP'
*put* 'NOOP\r\n'
*get* '200 NOOP: data transfer in progress\n'
*resp* '200 NOOP: data transfer in progress'
*cmd* 'NOOP'
*put* 'NOOP\r\n'
*get* '200 NOOP: data transfer in progress\n'
*resp* '200 NOOP: data transfer in progress'
*cmd* 'NOOP'
*put* 'NOOP\r\n'
*get* '200 NOOP: data transfer in progress\n'
*resp* '200 NOOP: data transfer in progress'

等等。但该文件是 ASCII 格式,因此已损坏。如果我做 调用ftp.voidcmd('TYPE I),NOOP 命令只发送一次,并且控制套接字直到传输完成才响应。如果文件很大,则控制套接字会超时,就好像从未发送过 NOOP...

很奇怪,但我相信它很简单。似乎transfercmd() 没有按照它应该的那样拆分控制和数据套接字......因此 ftp var 没有与数据流分离......或其他东西。奇怪的。

提前感谢您提供的任何建议。

【问题讨论】:

  • 您是否尝试过使用FTP.retrbinary(),而不是同时使用FTP.voidcmd(TYPE I) 和FTP.transfercmd()?
  • @uselpa - 感谢您的回复。是的 retrbinary 不是一个选项,因为它不返回数据套接字,这是向控制套接字发送单独的命令所必需的。
  • 请尝试tcpdump 和/或strace 来缩小问题范围。看到回复 NOOP 的“数据传输正在进行中”,我有点惊讶,也许那是 ftplib 人工制品。
  • 在一个不相关的注释上,为什么你仍然需要保持控制连接?这是一个最小的测试用例,还是你的整个代码?如果它是一个简单的下载,还有很多其他的库,例如pycurl.

标签: python multithreading sockets ftp noop


【解决方案1】:

tcpdump 确认服务器仅在服务器发送整个文件后才发送226 Transfer complete.。

我怀疑这是 FTP 规范的一部分。

其实看ftplib.py中的retrbinary代码:

    self.voidcmd('TYPE I')
    conn = self.transfercmd(cmd, rest)
    while 1:
        data = conn.recv(blocksize)
        if not data:
            break
        callback(data)
    conn.close()
    return self.voidresp()

最后一行预计只有在传输完成后才能获得传输结果(服务器已知)。

事实上,您的代码似乎缺少voidresp() 位。

我对 ftp 不是很熟悉,据我所知,lftp 这样的后台下载器实际上会为每个并行下载打开新的控制连接。

如果你的文件真的很大,你有一个合理的担忧。

FTP 有很多扩展,总有一些可以满足你的需求。

您也可以像这样创建一个循环:

pos = 0
while not full file:
    command REST
    download for a while in separate thread
    command ABRT
    wait for separate thread to abort
    pos += length of downloaded chunk

【讨论】:

  • 谢谢,赏金,我会坚持你的伪代码解决方案。感谢您的宝贵时间。
  • 我认为问题在于控制通道关闭一段时间后,226 Transfer complete 没有发送...
猜你喜欢
  • 1970-01-01
  • 2013-12-28
  • 2022-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-11
  • 2020-05-26
  • 2018-01-31
相关资源
最近更新 更多