ftplib python:NOOP命令工作在ASCII而非二进制

时间:2013-11-12 11:34:17

标签: python multithreading sockets ftp noop

我有一个线程化的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)调用强制二进制模式)。

如果我 DONT 调用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格式,因此已损坏。如果我 DO 调用ftp.voidcmd('TYPE I),则NOOP命令仅发送一次,并且控制套接字不响应,直到传输完成。如果文件很大,控制套接字就会超时,就像从未发送过NOOP一样......

很奇怪,但我确信它很简单。似乎transfercmd()没有按照它应该分割控件和数据套接字......因此ftp var不会与数据流分离......或者其他东西。奇怪。

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

1 个答案:

答案 0 :(得分:2)

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

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

事实上,请查看retrbinary中的ftplib.py代码:

    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