Qt 노트19

33801 단어 Qt
네트워크 프로그래밍
Qt의 Qt 네트워크 모듈은 TCP/IP 기반 네트워크 프로그램을 작성하는 데 사용됩니다.
  • QTcpSocket, QTcpServer와QUdpSocket 등
  • 고차원 클래스를 제공하고 통용되는 프로토콜로 네트워크 조작을 수행한다.예를 들어 QNetworkRequest, QNetworkReply, QNetworkAccessManager
  • QNetworkConfiguration, QNetworkConfiguration Manager와 QNetworkSession 등 부하 관리를 실현한다
  • 프로젝트 파일에 추가 필요 QT+=network도움말 키워드 Network Programming with Qt
    네트워크 액세스 인터페이스
    HTTP, FTP 및 로컬 파일의 URL 업로드 및 다운로드를 지원하는 QNetworkRequest 네트워크 요청네트워크 작업 QNetworkAccessManager 클래스 조정네트워크 요청에 대한 응답 QNetworkReply입니다.
    HTTP
    하이퍼텍스트 전송 프로토콜(HyperText Transfer Protocol)은 클라이언트와 서버 측 간에 요청과 응답을 하는 표준이다.
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include 
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        manager = new QNetworkAccessManager(this);
        connect(manager, &QNetworkAccessManager::finished,
                this, &MainWindow::replyFinished);
        manager->get(QNetworkRequest(QUrl("http://www.qter.org")));
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::replyFinished(QNetworkReply *reply)
    {
        QString all = reply->readAll();
        ui->textBrowser->setText(all);
        reply->deleteLater();
    }
    

    일반 파일 다운로드 예:
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include 
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        manager = new QNetworkAccessManager(this);
        ui->progressBar->hide();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::startRequest(QUrl url)
    {
        reply = manager->get(QNetworkRequest(url));
        connect(reply, &QNetworkReply::readyRead, this, &MainWindow::httpReadyRead);
        connect(reply, &QNetworkReply::downloadProgress,
                this, &MainWindow::updateDataReadProgress);
        connect(reply, &QNetworkReply::finished, this, &MainWindow::httpFinished);
    }
    
    void MainWindow::httpReadyRead()
    {
        if (file) file->write(reply->readAll());
    }
    
    void MainWindow::updateDataReadProgress(qint64 bytesRead, qint64 totalBytes)
    {
        ui->progressBar->setMaximum(totalBytes);
        ui->progressBar->setValue(bytesRead);
    }
    
    void MainWindow::httpFinished()
    {
        ui->progressBar->hide();
        if(file) {
            file->close();
            delete file;
            file = 0;
        }
        reply->deleteLater();
        reply = 0;
    }
    
    void MainWindow::on_pushButton_clicked()
    {
        url = ui->lineEdit->text();
        QFileInfo info(url.path());
        QString fileName(info.fileName());
        if (fileName.isEmpty()) fileName = "index.html";
        file = new QFile(fileName);
        if(!file->open(QIODevice::WriteOnly))
        {
            delete file;
            file = 0;
            return;
        }
        startRequest(url);
        ui->progressBar->setValue(0);
        ui->progressBar->show();
    }
    

    FTP
    파일 전송 프로토콜(File Transfer Protocol)은 원격 디렉토리를 탐색하고 파일을 전송하는 데 주로 사용되는 프로토콜입니다.Qt 5에서 QFtp 클래스가 폐기되었으나 호환 확장 모듈에서 QFtp 클래스를 찾을 수 있습니다.간단한 예:
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "qftp.h"
    #include 
    #include 
    #include 
    
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        ui->progressBar->setValue(0);
        connect(ui->fileList, &QTreeWidget::itemActivated,
                this, &MainWindow::processItem);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::ftpCommandStarted(int)
    {
        int id = ftp->currentCommand();
        switch (id)
        {
        case QFtp::ConnectToHost :
            ui->label->setText(tr("        …"));
            break;
        case QFtp::Login :
            ui->label->setText(tr("    …"));
            break;
        case QFtp::Get :
            ui->label->setText(tr("    …"));
            break;
        case QFtp::Close :
            ui->label->setText(tr("      …"));
        }
    }
    
    void MainWindow::ftpCommandFinished(int, bool error)
    {
        if(ftp->currentCommand() == QFtp::ConnectToHost) {
            if (error)
                ui->label->setText(tr("         :%1").arg(ftp->errorString()));
            else ui->label->setText(tr("        "));
        } else if (ftp->currentCommand() == QFtp::Login) {
            if (error)
                ui->label->setText(tr("      :%1").arg(ftp->errorString()));
            else {
                ui->label->setText(tr("    "));
                ftp->list();
            }
        } else if (ftp->currentCommand() == QFtp::Get) {
            if(error)
                ui->label->setText(tr("      :%1").arg(ftp->errorString()));
            else {
                ui->label->setText(tr("      "));
                file->close();
            }
            ui->downloadButton->setEnabled(true);
        } else if (ftp->currentCommand() == QFtp::List) {
            if (isDirectory.isEmpty())
            {
                ui->fileList->addTopLevelItem(
                            new QTreeWidgetItem(QStringList()<< tr("")));
                ui->fileList->setEnabled(false);
                ui->label->setText(tr("     "));
            }
        } else if (ftp->currentCommand() == QFtp::Close) {
            ui->label->setText(tr("      "));
        }
    }
    
    //     
    void MainWindow::on_connectButton_clicked()
    {
        ui->fileList->clear();
        currentPath.clear();
        isDirectory.clear();
        ui->progressBar->setValue(0);
        ftp = new QFtp(this);
        connect(ftp, &QFtp::commandStarted, this,
                &MainWindow::ftpCommandStarted);
        connect(ftp, &QFtp::commandFinished,
                this, &MainWindow::ftpCommandFinished);
        connect(ftp, &QFtp::listInfo, this, &MainWindow::addToList);
        connect(ftp, &QFtp::dataTransferProgress,
                this, &MainWindow::updateDataTransferProgress);
        QString ftpServer = ui->ftpServerLineEdit->text();
        QString userName = ui->userNameLineEdit->text();
        QString passWord = ui->passWordLineEdit->text();
        ftp->connectToHost(ftpServer, 21);
        ftp->login(userName, passWord);
    }
    
    void MainWindow::addToList(const QUrlInfo &urlInfo)
    {
        //   :          UTF-8  ,         ,           
        QString name = QString::fromUtf8(urlInfo.name().toLatin1());
        QString owner = QString::fromUtf8(urlInfo.owner().toLatin1());
        QString group = QString::fromUtf8(urlInfo.group().toLatin1());
        QTreeWidgetItem *item = new QTreeWidgetItem;
        item->setText(0, name);
        item->setText(1, QString::number(urlInfo.size()));
        item->setText(2, owner);
        item->setText(3, group);
        item->setText(4, urlInfo.lastModified().toString("yyyy-MM-dd"));
        QPixmap pixmap(urlInfo.isDir() ? "../myFTP/dir.png" : "../myFTP/file.png");
        item->setIcon(0, pixmap);
        isDirectory[name] = urlInfo.isDir();
        ui->fileList->addTopLevelItem(item);
        if (!ui->fileList->currentItem()) {
            ui->fileList->setCurrentItem(ui->fileList->topLevelItem(0));
            ui->fileList->setEnabled(true);
        }
    }
    
    void MainWindow::processItem(QTreeWidgetItem *item, int)
    {
        //           ,   
        if (isDirectory.value(item->text(0))) {
            //   :           ,   ftp  cd()          
            QString name = QLatin1String(item->text(0).toUtf8());
            ui->fileList->clear();
            isDirectory.clear();
            currentPath += "/";
            currentPath += name;
            ftp->cd(name);
            ftp->list();
            ui->cdToParentButton->setEnabled(true);
        }
    }
    
    //         
    void MainWindow::on_cdToParentButton_clicked()
    {
        ui->fileList->clear();
        isDirectory.clear();
        currentPath = currentPath.left(currentPath.lastIndexOf('/'));
        if (currentPath.isEmpty()) {
            ui->cdToParentButton->setEnabled(false);
            ftp->cd("/");
        } else {
            ftp->cd(currentPath);
        }
        ftp->list();
    }
    
    //     
    void MainWindow::on_downloadButton_clicked()
    {
        //   :           ,     get()           
        QString fileName = ui->fileList->currentItem()->text(0);
        QString name = QLatin1String(fileName.toUtf8());
        file = new QFile(fileName);
        if (!file->open(QIODevice::WriteOnly)) {
            delete file;
            return;
        }
        ui->downloadButton->setEnabled(false);
        ftp->get(name, file);
    }
    
    void MainWindow::updateDataTransferProgress(qint64 readBytes,qint64 totalBytes)
    {
        ui->progressBar->setMaximum(totalBytes);
        ui->progressBar->setValue(readBytes);
    }
    

    네트워크 인터페이스 정보 얻기
    TCP/UDP 프로그래밍을 할 때 먼저 연결된 호스트 이름을 IP(인터넷 프로토콜) 주소로 해석하고 DNS(도메인 이름 서비스) 프로토콜로 실행할 수 있다. IP(인터넷 프로토콜)는 IPV4와 IPV6 두 가지 버전이 있다.QtNetwork 모듈의 QHostInfo 클래스는 호스트 이름을 찾을 수 있는 정적 함수를 제공합니다.
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include 
    #include 
    
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        QString localHostName = QHostInfo::localHostName();
        QHostInfo info = QHostInfo::fromName(localHostName);
        qDebug() << "localHostName: " << localHostName << endl
                 << "IP Address: " << info.addresses();
    
        foreach (QHostAddress address, info.addresses())
        {
            if(address.protocol() == QAbstractSocket::IPv4Protocol)
                qDebug() << address.toString();
        }
    
        QHostInfo::lookupHost("www.baidu.com", this, SLOT(lookedUp(QHostInfo)));
    
        //            
        QList list = QNetworkInterface::allInterfaces();
    
        //          
        foreach (QNetworkInterface interface, list)
        {
            //     
            qDebug() << "Name: " << interface.name();
    
            //     
            qDebug() << "HardwareAddress: " << interface.hardwareAddress();
    
            //   IP      ,        IP  ,             
            QList entryList = interface.addressEntries();
    
            //      IP    
            foreach (QNetworkAddressEntry entry, entryList)
            {
                // IP  
                qDebug() << "IP Address: " << entry.ip().toString();
    
                //     
                qDebug() << "Netmask: " << entry.netmask().toString();
    
                //     
                qDebug() << "Broadcast: " << entry.broadcast().toString();
            }
        }
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::lookedUp(const QHostInfo &host)
    {
        if (host.error() != QHostInfo::NoError) {
            qDebug() << "Lookup failed:" << host.errorString();
            return;
        }
        foreach (const QHostAddress &address, host.addresses())
            qDebug() << "Found address:" << address.toString();
    }
    
    

    UDP
    사용자 데이터 보고 프로토콜(User Datagram Protocol)은 경량급, 신뢰할 수 없는 데이터 보고를 위한 연결이 없는 프로토콜로 신뢰성 요구가 높지 않은 장소에 사용된다.QUdpSocket 클래스는 UDP 데이터 보고서를 보내고 받는 데 사용됩니다.IPV4 브로드캐스트를 지원합니다.Socket은 플러그인이고 간단하게 이해하면 하나의 IP 주소에port 포트 번호를 추가하는 것이다.보내다
    #include "sender.h"
    #include "ui_sender.h"
    #include 
    
    Sender::Sender(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Sender)
    {
        ui->setupUi(this);
        sender = new QUdpSocket(this);
    }
    
    Sender::~Sender()
    {
        delete ui;
    }
    
    void Sender::on_pushButton_clicked()
    {
        QByteArray datagram = "hello world!";
        sender->writeDatagram(datagram.data(), datagram.size(),
                              QHostAddress::Broadcast, 45454);
    
    }
    

    접수
    #include "receiver.h"
    #include "ui_receiver.h"
    #include 
    
    Receiver::Receiver(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Receiver)
    {
        ui->setupUi(this);
    
        receiver = new QUdpSocket(this);
        receiver->bind(45454, QUdpSocket::ShareAddress);
        connect(receiver, &QUdpSocket::readyRead, this, &Receiver::processPendingDatagram);
    
    }
    
    Receiver::~Receiver()
    {
        delete ui;
    }
    
    void Receiver::processPendingDatagram()
    {
        //         
        while(receiver->hasPendingDatagrams())
        {
            QByteArray datagram;
    
            //  datagram               ,            
            datagram.resize(receiver->pendingDatagramSize());
    
            //      ,     datagram 
            receiver->readDatagram(datagram.data(), datagram.size());
            ui->label->setText(datagram);
        }
    }
    

    TCP
    전송 제어 프로토콜(Transmission Control Protocol)은 데이터 전송에 사용되는 하부 네트워크 프로토콜로 여러 개의 네트워크 프로토콜은 TCP 프로토콜을 바탕으로 하고 데이터 흐름과 연결을 위한 신뢰할 수 있는 전송 프로토콜이다.QTcpSocket류는 TCP에 인터페이스를 제공하여 POP3, SMTP와 NNTP 등 표준적인 네트워크 프로토콜을 실현할 수 있고 사용자 정의 네트워크 프로토콜을 실현할 수 있다.서버측:
    #include "server.h"
    #include "ui_server.h"
    #include 
    
    Server::Server(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Server)
    {
        ui->setupUi(this);
    
        connect(&tcpServer, SIGNAL(newConnection()),
                this, SLOT(acceptConnection()));
    
    }
    
    Server::~Server()
    {
        delete ui;
    }
    
    void Server::start()
    {
        if (!tcpServer.listen(QHostAddress::LocalHost, 6666)) {
            qDebug() << tcpServer.errorString();
            close();
            return;
        }
        ui->startButton->setEnabled(false);
        totalBytes = 0;
        bytesReceived = 0;
        fileNameSize = 0;
        ui->serverStatusLabel->setText(tr("  "));
        ui->serverProgressBar->reset();
    }
    
    void Server::acceptConnection()
    {
        tcpServerConnection = tcpServer.nextPendingConnection();
        connect(tcpServerConnection, SIGNAL(readyRead()),
                this, SLOT(updateServerProgress()));
        connect(tcpServerConnection, SIGNAL(error(QAbstractSocket::SocketError)),
                this, SLOT(displayError(QAbstractSocket::SocketError)));
        ui->serverStatusLabel->setText(tr("    "));
        //      ,      
        tcpServer.close();
    }
    
    
    void Server::updateServerProgress()
    {
        QDataStream in(tcpServerConnection);
        in.setVersion(QDataStream::Qt_4_0);
    
        //           16if (bytesReceived <= sizeof(qint64)*2) {
            if((tcpServerConnection->bytesAvailable() >= sizeof(qint64)*2)
                    && (fileNameSize == 0)) {
                //                  
                in >> totalBytes >> fileNameSize;
                bytesReceived += sizeof(qint64) * 2;
            }
            if((tcpServerConnection->bytesAvailable() >= fileNameSize)
                    && (fileNameSize != 0)) {
                //      ,     
                in >> fileName;
                ui->serverStatusLabel->setText(tr("     %1 …")
                                               .arg(fileName));
                bytesReceived += fileNameSize;
                localFile = new QFile(fileName);
                if (!localFile->open(QFile::WriteOnly)) {
                    qDebug() << "server: open file error!";
                    return;
                }
            } else {
                return;
            }
        }
        //             ,      
        if (bytesReceived < totalBytes) {
            bytesReceived += tcpServerConnection->bytesAvailable();
            inBlock = tcpServerConnection->readAll();
            localFile->write(inBlock);
            inBlock.resize(0);
        }
        ui->serverProgressBar->setMaximum(totalBytes);
        ui->serverProgressBar->setValue(bytesReceived);
    
        //        
        if (bytesReceived == totalBytes) {
            tcpServerConnection->close();
            localFile->close();
            ui->startButton->setEnabled(true);
            ui->serverStatusLabel->setText(tr("     %1   !")
                                           .arg(fileName));
        }
    }
    
    void Server::displayError(QAbstractSocket::SocketError socketError)
    {
        qDebug() << tcpServerConnection->errorString();
        tcpServerConnection->close();
        ui->serverProgressBar->reset();
        ui->serverStatusLabel->setText(tr("     "));
        ui->startButton->setEnabled(true);
    }
    
    //       
    void Server::on_startButton_clicked()
    {
        start();
    }
    

    클라이언트:
    #include "client.h"
    #include "ui_client.h"
    #include 
    #include 
    
    Client::Client(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Client)
    {
        ui->setupUi(this);
    
        payloadSize = 64*1024; // 64KB
        totalBytes = 0;
        bytesWritten = 0;
        bytesToWrite = 0;
        tcpClient = new QTcpSocket(this);
    
        //          ,  connected()  ,      
        connect(tcpClient, SIGNAL(connected()), this, SLOT(startTransfer()));
        connect(tcpClient, SIGNAL(bytesWritten(qint64)),
                this, SLOT(updateClientProgress(qint64)));
        connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)),
                this, SLOT(displayError(QAbstractSocket::SocketError)));
        ui->sendButton->setEnabled(false);
    }
    
    Client::~Client()
    {
        delete ui;
    }
    
    void Client::openFile()
    {
        fileName = QFileDialog::getOpenFileName(this);
        if (!fileName.isEmpty()) {
            ui->sendButton->setEnabled(true);
            ui->clientStatusLabel->setText(tr("     %1   !").arg(fileName));
        }
    }
    
    void Client::send()
    {
        ui->sendButton->setEnabled(false);
    
        //          0
        bytesWritten = 0;
        ui->clientStatusLabel->setText(tr("   …"));
        tcpClient->connectToHost(ui->hostLineEdit->text(),
                                 ui->portLineEdit->text().toInt());
    }
    
    
    void Client::startTransfer()
    {
        localFile = new QFile(fileName);
        if (!localFile->open(QFile::ReadOnly)) {
            qDebug() << "client: open file error!";
            return;
        }
        //       
        totalBytes = localFile->size();
    
        QDataStream sendOut(&outBlock, QIODevice::WriteOnly);
        sendOut.setVersion(QDataStream::Qt_4_0);
        QString currentFileName = fileName.right(fileName.size()
                                                 - fileName.lastIndexOf('/')-1);
        //          、         ,       
        sendOut << qint64(0) << qint64(0) << currentFileName;
    
        //             、       、             
        totalBytes += outBlock.size();
        sendOut.device()->seek(0);
    
        //   outBolock   ,            qint64(0)  
        sendOut << totalBytes << qint64((outBlock.size() - sizeof(qint64)*2));
    
        //                 
        bytesToWrite = totalBytes - tcpClient->write(outBlock);
    
        ui->clientStatusLabel->setText(tr("   "));
        outBlock.resize(0);
    }
    
    void Client::updateClientProgress(qint64 numBytes)
    {
        //          
        bytesWritten += (int)numBytes;
    
        //          
        if (bytesToWrite > 0) {
            //     payloadSize     ,     64KB,         64KB,
            //           
            outBlock = localFile->read(qMin(bytesToWrite, payloadSize));
    
            //                 
            bytesToWrite -= (int)tcpClient->write(outBlock);
    
            //        
            outBlock.resize(0);
        } else { //           ,     
            localFile->close();
        }
        //      
        ui->clientProgressBar->setMaximum(totalBytes);
        ui->clientProgressBar->setValue(bytesWritten);
        //       
        if(bytesWritten == totalBytes) {
            ui->clientStatusLabel->setText(tr("     %1   ").arg(fileName));
            localFile->close();
            tcpClient->close();
        }
    }
    
    void Client::displayError(QAbstractSocket::SocketError)
    {
        qDebug() << tcpClient->errorString();
        tcpClient->close();
        ui->clientProgressBar->reset();
        ui->clientStatusLabel->setText(tr("     "));
        ui->sendButton->setEnabled(true);
    }
    
    
    //     
    void Client::on_openButton_clicked()
    {
        ui->clientProgressBar->reset();
        ui->clientStatusLabel->setText(tr("  :      !"));
        openFile();
    
    }
    
    //     
    void Client::on_sendButton_clicked()
    {
        send();
    }
    

    기타
    네트워크 관련은 네트워크 에이전트 QNetworkProxy 클래스, 마운트 관리 QNetworkConfiguration Manager 클래스, QNetworkSession 클래스와 통신 안전의 QSsl 관련 클래스 등이 있다.

    좋은 웹페이지 즐겨찾기