关于Qt **QNetworkAccessManager**、**QNetworkReply**、**QNetworkRequest**实现ftp下载时,**QNetworkReply**::**downloadProgress**信号的**bytesTotal**一直为-1的原因分析

发布时间 2023-06-13 21:44:51作者: thammer

实现的ftp下载需要反馈下载进度,但是代码得到的bytesTotal始终为-1,直到下载完成那一刻,才变成文件大小。于是分析qt5base的network部分代码:

network/access/qnetworkaccessftpbackend.cpp文件中,有如下片段:

void QNetworkAccessFtpBackend::ftpRawCommandReply(int code, const QString &text)
{
    //qDebug() << "FTP reply:" << code << text;
    int id = ftp->currentId();

    if ((id == helpId) && ((code == 200) || (code == 214))) {     // supported commands
        // the "FEAT" ftp command would be nice here, but it is not part of the
        // initial FTP RFC 959, neither ar "SIZE" nor "MDTM" (they are all specified
        // in RFC 3659)
        if (text.contains(QLatin1String("SIZE"), Qt::CaseSensitive))
            supportsSize = true;
        if (text.contains(QLatin1String("MDTM"), Qt::CaseSensitive))
            supportsMdtm = true;
        if (text.contains(QLatin1String("PWD"), Qt::CaseSensitive))
            supportsPwd = true;
    } else if (id == pwdId && code == 257) {
        QString pwdPath;
        int startIndex = text.indexOf('"');
        int stopIndex = text.lastIndexOf('"');
        if (stopIndex - startIndex) {
            // The working directory is a substring between \" symbols.
            startIndex++; // skip the first \" symbol
            pwdPath = text.mid(startIndex, stopIndex - startIndex);
        } else {
            // If there is no or only one \" symbol, use all the characters of
            // text.
            pwdPath = text;
        }

此处它通过SITE help命令查询ftp server支持的命令,我这边ftp server是pureftpd,实际在终端用ftp命令连接上后,site help查询得到的结果确实没有SIZE的支持,尝试通过配置文件看能否打开此命令的支持,但是每查到,于是阅读pureftpd源码,src/ftp_parser.c中可知,site help得到的返回永远是固定的,

else if (!strcasecmp(arg, "help")) {
                    help_site:

                    addreply_noformat(214, MSG_SITE_HELP CRLF
# ifdef WITH_DIRALIASES
                                      " ALIAS" CRLF
# endif
                                      " CHMOD" CRLF " IDLE" CRLF " UTIME");
                    addreply_noformat(214, "Pure-FTPd - http://pureftpd.org/");
                }

于是只好暴力修改Qt源码,QNetworkAccessFtpBackend构造的初始化列表将

QNetworkAccessFtpBackend::QNetworkAccessFtpBackend()
    : ftp(nullptr), uploadDevice(nullptr), totalBytes(0), helpId(-1), sizeId(-1), mdtmId(-1), pwdId(-1),
    supportsSize(true), supportsMdtm(false), supportsPwd(false), state(Idle)
{
}

supportsSize(false) 改为true.问题解决,不过对应的ftp server那端必须要支持size命令,好在ftp server大多一般都支持size。解决方案不优雅,但是可行。