1

我目前面临一个关于 QFtp 的奇怪问题。我想从 FTP 服务器下载一堆文件,但是当我到达某个点时,在 y 上下载 x 文件后,ftp->get()命令完成,文件被填充,但没有发射,SIGNAL commandFinished()因此它不下载其他文件。

这是我的代码:

void Ftp::commandFinished(int i, bool error)
{

    if(ftp->currentCommand() == QFtp::Get)
    {
        if(error)
        {
            //blablabla-ERROR-blablabla
        }
        currentFile->close();
        filesToDownload.pop_front();
        processFileList();
    }

    /**Gestion de la commande Login (authentification de l'utilisateur)
    */
    if(ftp->currentCommand() == QFtp::Login)
    {//not utile here}

    /**Gestion de la commande ConnectToHost (connexion au serveur)
    */
    if (ftp->currentCommand() == QFtp::ConnectToHost) 
    {//not utile here}

    /**Gestion de la commande List (téléchargement d'un fichier)
    */
    if(ftp->currentCommand() == QFtp::List)
    {
        if(error)
        {
            //Nananana-FAIL-nanana
        }

        //!Tri des fichiers à télécharger en fonction de leur dernière date de modification
        if (!filesToDownload.isEmpty())
        {
            currentPeripheral->setLastDownloadDate(newLastModifiedDate) ;
            std::sort(filesToDownload.begin(),filesToDownload.end(),compareQUrlInfos);
            processFileList();
        }



    }
}

void Ftp::processFileList()
{

QUrlInfo info;

if (filesToDownload.isEmpty())
{
    //!Suicide de l'instance de Ftp
    ftp->close();
    disconnect(this,0,0,0);
    this->deleteLater();
    return ;
}

info = filesToDownload.first();
QDir dlDir(QString::number(currentPeripheral->getId()));

//!Si un fichier a été téléchargé, on déclenche son traitement
if (currentFile != nullptr)
{
    emit(oneDownloadFinished(currentFile->fileName(),currentPeripheral));
    delete currentFile;
    currentFile = nullptr;
}

//!On crée un répertoire de téléchargement si nécessaire
if (!dlDir.exists())
{
    dlDir.mkdir(".");
}

//!on crée le fichier qui contiendra le téléchargement
currentFile = new QFile(dlDir.filePath(info.name()));

if(!currentFile->open(QIODevice::WriteOnly))
{
    delete currentFile;
    currentFile = nullptr;
    emit(writeToMonitoringConsole(QString("Erreur lors de la creation du fichier "+info.name()),"Error"));
    return;
}


//Here I start (sometimes) a never ending fail
ftp->get(info.name(), currentFile);
}

起初我以为是因为我提出了太多要求,因此我被拒绝了,但即使有一个Sleep(2000)it 块。阻塞出现得更快。我通常可以下载大约 30 个文件(幸运的是 70 个,一旦我设法拥有 200 个!)。我Sleep(2000)几乎没有成功下载2-3个文件。

这是我的错吗?我没有发现 QFtp 有限制吗?或者是其他东西 ?

编辑:自从我发布它以来,我测试了一些东西,当监控 dataTransferProgress() 信号时,引人注目的是有问题的文件已完全下载(qDebug 说“88928/88928”),但我从未输入 commandFinished()。

我的插槽 commandFinished() 以这种方式链接到我的 QFtp::commandFinished SIGNAL :

connect(ftp, SIGNAL(commandFinished(int,bool)), this, SLOT(commandFinished(int,bool)));
4

2 回答 2

3

我看到几乎相同的东西,FTPWidget我使用的一个类从不接收commandFinishedGET 请求。dataTransferProgress() 信号可靠地报告 100% 已下载,并且全部都在那里。

我已经使用设置超时进行黑客攻击,如下所示:

// Set up a single shot QTimer and connect it to a function to fix things

connect(m_lostFinishedTimer, SIGNAL(timeout()), this, SLOT(lostFinishedHack()));

// Start the timeout when the download data progress hits 100%

void FtpWidget::updateXferProgress(qint64 readBytes, qint64 totalBytes)
{
    m_progressBar->setValue(progress_value(readBytes, totalBytes));

    if (m_downloading && readBytes == totalBytes)
        m_lostFinishedTimer->start();
}

// And don't forget to stop the timer if you do get a finish:

void FtpWidget::commandFinished(int id, bool error)
{
    QFtp::Command cmd = m_ftp->currentCommand();
    // ...
    if (cmd == QFtp::Get) 
    {
        m_lostFinishedTimer->stop();
        //....
    }
    // ...
}

计时器连接到修复例程的地方基本上关闭下载文件,重新连接服务器,然后继续下一个文件

void FtpWidget::lostFinishedHack()
{
    if (!m_downloading)
        return;

    if (m_downloadFile)
    {
        DOUT("FtpWidget::lostFinshedHack() -- file: " << DS(m_downloadFile->fileName()) << "\n");
        m_downloadFile->close();
        delete m_downloadFile;
        m_downloadFile = 0;
    }

    // just reconnect the thing
    Connect(m_ftpServerName->text());

    downloadNextFile();
}

这似乎工作得很好,虽然我使用了一个相当大的超时。

因此,在我完成这项工作后的一段时间,我回过头来查看 QFtp 本身内部发生了什么。使用调试器在断点上添加打印命令,我可以看到原始回复。似乎正在发生的事情是我正在使用的 ftp 服务器有时会以不同的顺序发送其 ftp 回复。

当它起作用时,我的跟踪看起来像:

FtpWidget::commandStarted(id: 265) --  Get
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 200, text "Operation successful"
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 213, text "135980"
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 200, text "Operation successful"
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 150, text "Opening BINARY connection for 000-23Sep2014_103527.jpg (135980 bytes)"
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 226, text "Operation successful"
FtpWidget::commandFinished(id: 265, error: 0) -- Get

FtpWidget::commandStarted和是我的插槽,而_q_piFtpReply commandFinished() 是 QFtp 对象的私有部分,我在其中挂钩了我的跟踪断点。

当它失败时,我得到:

FtpWidget::commandStarted(id: 256) --  Get
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 200, text "Operation successful"
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 213, text "135896"
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 200, text "Operation successful"
Function: QFtpPrivate::_q_piFtpReply(int, const QString &), code: 150, text "Opening BINARY connection for 000-23Sep2014_103525.jpg (135896 bytes)"
FtpWidget::lostFinshedHack()
FtpWidget::lostFinshedHack() -- file: C:/Users/sean/Temp/Snapshots5/000-23Sep2014_103525.jpg
FtpWidget::connect("ftp://root@169.254.1.180/")

在 200 回复代码之后获取 150 回复代码似乎是问题所在。因此,如果您查找 FTP 回复代码并查看 qftp.cpp,它看起来在 150 之后到达 150 导致 qftp 实现状态机进入永久等待。据我所知,我的 ftp 服务器搞砸了,而不是 qftp.cpp(也许我应该尝试使用 Wire Shark 来确定)。

现在我坚持使用我的超时解决方法来解决这个问题。

于 2014-09-23T22:44:34.900 回答
2

我来不及回复,但它仍然可以帮助其他人。

void Ftp::commandFinished(int i, bool error)最好也检查选项,因为如果QFtp::None您的最后一个命令是get并且当commandFinished()slot 被调用时,那么 if (ftp->currentCommand() == QFtp::Get)将无法识别最后一个命令,因为您当前的命令可能不是get因为它已经完成。

您也可以使用 id 进行检查if(ftp->currentCommand() == QFtp::Get || 1 == id)

于 2016-07-06T10:50:42.537 回答