Qt 는 QNetworkAssessManager 를 사용 하여 파일 을 다운로드 합 니 다.

13433 단어 QtC++
기능 디 렉 터 리:
  • QNetworkAccessManager 인터페이스 소개
  • 진도 조 전 시 를 다운로드 하고 일시 정지, 정지 기능 지원
  • 다운로드 / 남 은 크기, 남 은 시간, 다운로드 속도 표시
  • 다 중 스 레 드 다운로드, 인터페이스 스 레 드 차단 하지 않 음
  • 파일 정지점 전송 다운로드
  • 다운로드 요청 시간 초과 처리
  • 데모 주소 구현 기능
  • 1. QNetworkAccessManager 인터페이스 소개
        공식 문서:http://doc.qt.io/archives/qt-5.8/qnetworkaccessmanager.html
        어 휘 를 잘 아 는 api: post, get, put, head 를 한눈 에 볼 수 있 습 니 다. 물론 쿠키 와 관련 된 방법 도 몇 가지 있 습 니 다.
        manager 를 사용 하려 면 몇 가지 종류 가 필요 합 니 다. QNetworkRequest 는 요청 에 사용 되 는 QNetworkReply 가 요청 한 응답 을 받 습 니 다.
         예 를 들 어 1. 웹 서버 에서 만 데 이 터 를 요청 하고 get 방법 을 사용 합 니 다.         
            QNetworkAccessManager *manager = new QNetworkAccessManager(this);
            connect(manager, SIGNAL(finished(QNetworkReply*)),
                    this, SLOT(replyFinished(QNetworkReply*)));
            QNetworkRequest request;
            request.setUrl(QUrl("http://qt-project.org"));
           
            reply = manager->get(request);
            connect(reply, &QNetworkReply::finished, this, &MainWindow::finished);
    
            // finished   
            QByteArray bytes = reply->readAll();//      

          2. 서버 에 데 이 터 를 되 돌려 달라 고 요청 하고 post 를 사용 합 니 다. post 에 json 데 이 터 를 추가 할 때:
        QNetworkAccessManager *manager = new QNetworkAccessManager(this);
        QNetworkRequest request;
    
        //  json  
        QJsonObject jsonObject;
        jsonObject.insert("dcode", "code");
        jsonObject.insert("ver", "version");
    
        //json QByteArray
        QString strJson = QString(QJsonDocument(jsonObject).toJson(QJsonDocument::Compact));
        QByteArray byte_json = strJson.toLocal8Bit();
        
        request.setUrl(QUrl("http://qt-project.org"));//      
        //    json  ,  header      
        request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
        
        if (m_Reply != Q_NULLPTR) {
    		m_Reply->deleteLater();
    	}
    	m_Reply = manager->post(request, byte_json);
        QEventLoop loop;//     ,      
    	QTimer timer;
    	connect(m_Reply, SIGNAL(finished()), &loop, SLOT(quit()));
    	QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
    	timer.start(5000);//    5s
    	loop.exec(QEventLoop::ExcludeUserInputEvents);
    
    	if (m_Reply->error() == QNetworkReply::NoError){
            QByteArray  strJsonText = m_Reply->readAll();//      
        }

        1.1. QNetworkRequest
        도움말 문서 보기:http://doc.qt.io/qt-5/qnetworkrequest.html
        주로 이 몇 가지 쓰기 방법 으로 각각 요청 한 종류 에 대해 설정 합 니 다.
                클 라 이언 트 가 서버 에 HTTP 요청 메 시 지 를 보 내 는 것 은 다음 과 같은 형식 을 포함 합 니 다. 요청 줄 (request line), 요청 머리 (header), 빈 줄 과 요청 입 니 다.    데이터 네 부분 으로 구성 되 어 있 으 며, 아래 그림 은 요청 메시지 의 일반적인 형식 을 보 여 줍 니 다.요청 줄 구성: 요청 방법 + 스페이스 바 + url + 스페이스 바 + 프로 토 콜 버 전 + 리 턴 문자 + 줄 바 꿈 문자.      자세 한 내용 은 HTTP 메시지 구조 참조     header 에 대해 qt 는 매 거 진 형식 Known Headers 를 제공 하여 각각 다른 항목 을 표시 합 니 다.
    Constant
    Value
    Description
    QNetworkRequest::ContentDispositionHeader
    6
    Corresponds to the HTTP Content-Disposition header and contains a string containing the disposition type (for instance, attachment) and a parameter (for instance, filename).
    QNetworkRequest::ContentTypeHeader
    0
    Corresponds to the HTTP Content-Type header and contains a string containing the media (MIME) type and any auxiliary data (for instance, charset).
    QNetworkRequest::ContentLengthHeader
    1
    Corresponds to the HTTP Content-Length header and contains the length in bytes of the data transmitted.
    QNetworkRequest::LocationHeader
    2
    Corresponds to the HTTP Location header and contains a URL representing the actual location of the data, including the destination URL in case of redirections.
    QNetworkRequest::LastModifiedHeader
    3
    Corresponds to the HTTP Last-Modified header and contains a QDateTime representing the last modification date of the contents.
    QNetworkRequest::CookieHeader
    4
    Corresponds to the HTTP Cookie header and contains a QList representing the cookies to be sent back to the server.
    QNetworkRequest::SetCookieHeader
    5
    Corresponds to the HTTP Set-Cookie header and contains a QList representing the cookies sent by the server to be stored locally.
    QNetworkRequest::UserAgentHeader
    7
    The User-Agent header sent by HTTP clients.
    QNetworkRequest::ServerHeader
    8
    The Server header received by HTTP clients.
    1.2. QNetworkReply
        도움말 문서:http://doc.qt.io/qt-5/qnetworkreply.html
        이러한 계승 은 QIODevice 에서 이 루어 집 니 다. 받 은 모든 정 보 를 읽 는 것 을 포함 하여 QIODevice 의 모든 인 터 페 이 스 를 사용 할 수 있 습 니 다.
        이 동시에 finished 신 호 를 제공 합 니 다. 응답 완료 척후 에서 이 신 호 를 보 내 면 사용자 정의 슬롯 함수 와 관련 하여 응답 처 리 를 할 수 있 습 니 다.
        attribute 속성 함 수 를 제공 하여 응답 유형 을 판단 할 수 있 습 니 다. 예 를 들 어 Redirection TargetAttribute 는 목표 url 알림 으로 방향 을 바 꿀 수 있 습 니 다.
        QNetworkReply 는 자동 으로 공간 을 방출 하지 않 습 니 다. 메모리 방출 을 주동 적 으로 처리 해 야 합 니 다. QObject 를 호출 할 수 있 습 니 다.: deleteLater 는 자동 으로 공간 을 방출 하도록 합 니 다.
    connect(m_reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(onDownloadProgress(qint64, qint64)));
    connect(m_reply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
    connect(m_reply, SIGNAL(finished()), this, SLOT(onFinished()));
    connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));

    다운로드 요청 시:
    onDownloadProgress(qint64, qint64);다운로드 진 도 를 표시 합 니 다. 매개 변수 1 과 2 는 각각 이번 다운로드 바이트 수 와 파일 총 바이트 크기 를 대표 합 니 다.
    onReadyRead();다운로드 과정 에서 서버 에서 데 이 터 를 읽 기 시 작 했 습 니 다. 데 이 터 를 읽 고 로 컬 파일 에 기록 하 는 데 사용 되 며 데이터 추가 방식 으로 정지점 의 전송 을 편리 하 게 합 니 다.          
        void xx::onReadyRead()
        {
            if (m_reply == NULL) return;
            QFile file(m_fileName);//     
            if (file.open(QIODevice::WriteOnly | QIODevice::Append))
            {
                file.write(m_reply->readAll());
            }
            file.close();
        }

    onFinished (): 다운로드 완료 이벤트.
    onError (): 오류 이벤트 다운로드
    2. 진행 표시 줄 다운로드, 일시 정지 지원, 정지 기능         QNetworkAccessManager 는 get 방법 으로 요청 을 보 내 고 QNetworkReply 로 되 돌려 받 습 니 다.QNetworkReply 는 다운로드 할 때마다 데이터 의 크기 와 파일 의 총 크기 를 피드백 하기 위해 다운로드 프로 세 스 신 호 를 사용 합 니 다.    2.1    readyRead()         QNetworkReply 의 부모 클래스 QIODevice 가 제공 하 는 다운로드 과정 에서 의 신호 로, 이 신호 에 다운로드 파일 크기 를 기록 할 수 있 습 니 다.    2.2 downloadProgress(qint64 bytesReceived, qint64 bytesTotal)          bytes Received 는 매번 파일 을 다운로드 할 때마다 바이트 크기 를 나타 내 고 bytes Total 은 다운로드 파일 바이트 의 총 크기 를 나타 낸다.                    
    //     ;  
    QString sValue = QString("%1").arg(bytesReceived * 100 / (bytesTotal));//   ,    100
    ui.progressBar->setValue(sValue.toInt());
            

        2.3 일시 정지 및 정지 기능 요점: QNetworkReply 의 신호 와 슬롯 을 풀 고 QNetworkReply 의 abort 방법 과 DeleteLater () 방법 을 호출 해 야 합 니 다.
     disconnect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onDownloadProgress(qint64, qint64)));
     disconnect(m_reply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
     disconnect(m_reply, SIGNAL(finished()), this, SLOT(onFinished()));
     disconnect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
     m_reply->abort();
     m_reply->deleteLater();
     m_reply = NULL;

        
    3. 다운로드 / 남 은 크기, 남 은 시간, 다운로드 속도 표시        남 은 크기, 남 은 시간, 다운로드 속 도 를 계산 하려 면 다운로드 과정 에서 매번 다운로드 바이트 수 와 총 다운로드 바이트 수 에 따라 계산 해 야 하기 때문에 download Progress (qint 64 bytes Received, qint 64 bytes Total)        응답 하 는 슬롯 함수 에서 계산 합 니 다.
            //     MB/   MB
            QString strDownCurrent = QStringLiteral("    :%1/%2").arg(transformUnit(m_currentDownload)).arg(transformUnit(bytesTotal));
            ui.lb_size->setText(strDownCurrent);
    
            //    
            qint64 ispeed		= m_intervalDownload * 1000 / (timeNow - m_timeInterval);
            qint64 timeRemain	= (bytesTotal - bytesReceived) / ispeed;
            QString strRemaind	= QStringLiteral("    :%1").arg(transformTime(timeRemain));
            ui.lb_remaind->setText(strRemaind);
    
            //    
            QString strSpeed	= QStringLiteral("    :%1").arg(transformUnit(ispeed, true));
            ui.lb_rate->setText(strSpeed);

    4. 다 중 스 레 드 다운로드, 인터페이스 스 레 드 차단 없 음                 여기 에는 두 가지 방법 이 있 습 니 다. 하 나 는 MoveToThread 방법 을 통 해 하나의 계승 과 QObject 의 기능 류 를 통 해 이 루어 집 니 다.        두 번 째 는 QThread 를 계승 하고 QThread 를 통 해 다 중 스 레 드 를 실현 하 는 것 입 니 다. 저 는 두 번 째 를 사용 하여 계승 과 QThread 의 중간 류 를 제공 한 적 이 있 습 니 다.        다운로드 단 추 를 누 르 면 다운로드 스 레 드 를 시작 합 니 다:
            m_strTargetAddress  = "d:/Qt_Download.zip";//         
            QString strUrl	    = ui.lineEdit->text();//       
    
            if (m_pDownloadThread != NULL )
            {
                m_pDownloadThread->start();
            }

    5. 파일 정지점 리 셋 다운로드        5.1 정지점 전송 과 관련 하여 QNetworkRequest 는 요청 한 바이트 크기 와 너 비 를 설정 하 는 방법 SetRawHeader 와 "Range" 필드 를 제공 합 니 다.        HTTP 프로 토 콜 요청 에서 파일 의 한 위치 에서 데 이 터 를 받 아들 이려 면 Range 머리 를 더 해 야 합 니 다. Range 머리의 형식 은 다음 과 같 습 니 다.        첫 500 바이트: bytes = 0 - 499          두 번 째 500 바이트: bytes = 500 - 999          마지막 500 바이트 표시: bytes = - 500          500 바이트 이후 의 범 위 를 나타 낸다: bytes = 500 -          첫 번 째 와 마지막 바이트: bytes = 0 - 0, - 1          동시에 몇 가지 범 위 를 지정 합 니 다: bytes = 500 - 600, 601 - 999
            Range 요청 을 보 낸 후 서버 는 Content - Range 머리 에서 현재 받 은 범위 와 파일 의 총 크기 를 되 돌려 줍 니 다. 예 를 들 어:
            Content-Range: 0-499/22400
            여기 서 0 - 499 는 현재 보 낸 데이터 의 범 위 를 말 하 는데 22400 은 파일 의 총 크기 이다.
            5.2 정지점 전송 을 실현 하려 면 클 라 이언 트 만 이 안 되 고 서버 에 있 는 파일 도 정지점 전송 을 지원 해 야 한다. 즉, 정지점 다운로드 전송 을 진행 할 때 먼저 다운로드 파일 이 정지점 다운 로드 를 지원 하 는 지 판단 해 야 한다.            windows 에서 파일 다운로드 지원 정지점 다운로드 지원 을 어떻게 판단 합 니까?            5.2.1 cmd 에서 curl 명령 에 - i 인자 와 요청 할 바이트 크기 를 추가 합 니 다.
                    eg: curl -i --range 0-9 http://sqdownb.onlinedown.net/down/55412_20161201034403.zip                 반환 데이터 에 Content - Range 와 HTTP / 1.1 206 Partial Content 바이트 가 포함 되 어 있 습 니 다. 예 를 들 어 상기 명령 을 수행 할 때 반환 결 과 는 다음 과 같 습 니 다.
        HTTP/1.1 206 Partial Content
        Date: Wed, 01 Aug 2018 03:12:14 GMT
        Content-Type: application/zip
        Content-Length: 10
        Last-Modified: Wed, 07 Dec 2016 10:13:32 GMT
        Connection: keep-alive
        ETag: "5847e0cc-78ac98"
        Content-Range: bytes 0-9/7908504

               Content - Range: bytes 0 - 9 / 7908504 에서 돌아 오 는 바이트 수 7908504 는 파일 의 총 바이트 크기 입 니 다.
                HTTP/1.1 206 Partial Content     대표 상태 값 206 대표 정지점 다운로드 지원           그래서 이 링크 는 정지점 다운 로드 를 지원 하 는 Content - Range 와 HTTP / 1.1 206 Partial Content 바이트 가 있 는 곳 으로 되 돌아 갑 니 다.
              5.2.2 Qt 코드 에 서 는 QNetworkRequest 를 통 해 'Range' 를 요청 하고, 반환 값 QNetworkReply 의 rawHeader ('Content - Range') 를 통 해 반환 값 이 있 는 지 확인 합 니 다.
    bool xx::bSupportBreak(const QUrl &url)
    {
    	QNetworkAccessManager manager;
    	QEventLoop loop;
    	QTimer timer;
    
    	QNetworkRequest request;
    	request.setUrl(url);
    	request.setRawHeader("Range", "bytes=0-9");
    
    	//    ,           ;
    	QNetworkReply *reply = manager.get(request);
    	if (!reply)		return false;
    
    	connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    	connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
    
    	timer.start(2000);
    	loop.exec(QEventLoop::ExcludeUserInputEvents);
    
    	if (reply->error() != QNetworkReply::NoError)
    	{
    		//       ;
    		qDebug() << reply->errorString();
    		return false;
    	}
    	else if (!timer.isActive())
    	{
    		//       ,        ;
    		qDebug() << "Request Timeout";
    		return false;
    	}
    	timer.stop();
    
    	QByteArray range = reply->rawHeader("Content-Range");
    	if (!QString::fromLocal8Bit(range).isEmpty())
    		return true;
    
    	return false;
    }

    6. 다운로드 요청 시간 초과 처리                      Qt 5.8 에 서 는 QNetworkAccessManager 클래스 든 QNetworkRequest 클래스 든 시간 초과 메커니즘 을 제공 하지 않 기 때문에 스스로 계산 할 수 밖 에 없습니다.        다운 로드 를 시작 할 때 타 이 머 를 통 해 5s 마다 다운로드 바이트 의 변화 값 을 측정 합 니 다.        
    _timeOut->start(5000);

            5s 내 에 변화 가 없 으 면 기본적으로 시간 초과, 시간 초과 의 원인 이 많다 는 것 을 설명 한다. 다운로드 과정 에서 네트워크 가 끊 기거 나 네트워크 연결 이 불안정 하고 네트워크 카드 가 비활성화 되 는 등 이다.타이머 시간 초과 이 벤트 를 통 해 네트워크 링크 가 있 는 지 순환 적 으로 확인 하고 네트워크 연결 이 있 으 면 계속 다운로드 하 며 반대로 다운로드 가 중단 되 었 습 니 다.이러한 장점 은 다운로드 가 완료 되 기 전에 네트워크 에 파동 이 발생 하면 전체 파일 의 다운로드 에 영향 을 주지 않 고 폴 링 을 통 해 다운로드 가 완 료 될 때 까지 하 는 것 이다.                 그러나 여기 서 저 는 프로그램 이 무절제 하 게 연결 을 요청 하지 않도록 30 분 이 넘 으 면 프로그램 이 요청 을 끊 고 다운로드 하지 않 습 니 다.        
    void xx::handleTimeOut()
    {
    	if (m_bytesDown != m_bytesReceived) {
    		m_bytesDown = m_bytesReceived;
    	}
    	else if (!m_bClickPause) {
    
    		//         
    		if (m_reply != NULL)
    		{
    			stopDownload();
    			m_timeElapsed.start();
    		}
    
    		//30      (30              )
    		int nElapsed = m_timeElapsed.elapsed();
    		if (nElapsed >= 1 * 30 * 60 * 1000)
    		{
    			_timeOut->stop();
    			return;
    		}
    
    		//    
    		bool bConnect = this->bSupportBreak(m_qStrUrl);
    		if (bConnect)
    		{
    			_timeOut->stop();
    			this->downloadFile(m_qStrUrl, m_qStrFilePath);
    		}
    
    	}
    }

    7. 데모 주소 기능 구현
            환경 은 VS 2015 + win 10 64 위.
            원본 코드 와 실행 가능 한 프로그램 다운로드 주 소 를 추가 하 는 동시에 컴 파일 에 성공 한 OpenSsl 의 32 비트 와 64 비트 파일 도 있 습 니 다.
            https://download.csdn.net/download/whanjim19/10576909

    좋은 웹페이지 즐겨찾기