Qt项目:网络1

文章目录

项目:网路


项目1:主机信息查询

使用QHostInfo类和QNetworkInterface类可以获取主机的一些网络信息,如IP地址^1^和MAC地址^2^。

在Qt项目里使用Qt Network模块,需要在项目配置文件(.pro 文件)中增加一条配置语句:
QT += network


1.1 QHostInfo类和QNetworkInterface类

QHostInfo类常用函数

QHostInfo类可以根据主机名获取主机的IP地址,或者通过IP地址获取主机名。

  • [static] QString QHostInfo::localHostName():返回本机主机名;
  • [static] QString QHostInfo::localDomainName():返回本机域名系统(domain name system,DNS)域名;
  • [static] QHostInfo QHostInfo::fromName(const QString &name):返回指定主机名的IP地址;
  • [static] int QHostInfo::lookupHost(const QString &name, QObject *receiver, const char *member):以异步的方式根据主机名查找主机的IP地址,并返回一个表示本次查找的ID,可用作abortHostLookup()函数的参数;
  • [static] void QHostInfo::abortHostLookup(int id):使用 lookupHost() 返回的 ID 终止主机查找。
  • QList<QHostAddress> QHostInfo::addresses() const:返回与hostName()对应主机关联的IP地址列表;
  • QString QHostInfo::hostName() const:返回通过IP地址查找到的主机名;

QNetworkInterface类常用的函数

QNetworkInterface类可以获得运行程序的主机名的所用IP地址和网络接口列表。

  • [static] QList QNetworkInterface::allAddresses():返回主机上所有IP地址的列表(如果不需要知道子网掩码和广播地址);
  • [static] QList QNetworkInterface::allInterfaces():返回主机上所有网络接口列表(一个网络接口可能包含多个IP地址,每个IP地址与掩码或广播地址关联);
  • QList QNetworkInterface::addressEntries() const:返回网络接口的IP地址列表,包括子网掩码和广播地址;
  • QString QNetworkInterface::hardwareAddress() const:返回接口的低级硬件地址,以太网里就是MAC地址;
  • bool QNetworkInterface::isValid() const:如果接口信息有效就返回true;
  • QNetworkInterface::InterfaceType QNetworkInterface::type() const:返回网络接口的类型;

1.2 主机信息查询项目实现

  1. 显示本机地址信息
c 复制代码
//获取本机主机名和IP地址按钮
void Widget::on_btnGetHostInfo_clicked()
{
    ui->plainTextEdit->clear();
    QString hostName = QHostInfo::localHostName();  //本机主机名
    qDebug()<<hostName;
    ui->plainTextEdit->appendPlainText("HostName:"+hostName+"\n");

    QHostInfo hostInfo = QHostInfo::fromName(hostName); //本机IP地址
    QList<QHostAddress> addrList = hostInfo.addresses();//IP地址列表
    if(addrList.isEmpty()) return;
    foreach(QHostAddress host, addrList){
        bool show = ui->checkBox_OnlyIPV4->isChecked(); //只显示ipv4
        //Returns the network layer protocol of the host address.
        show = show ? (host.protocol() == QAbstractSocket::IPv4Protocol):true;
        if(show){
            ui->plainTextEdit->appendPlainText("protool:"+protocolName(host.protocol()));//协议
            ui->plainTextEdit->appendPlainText("HostIPAdddress:"+host.toString());
            ui->plainTextEdit->appendPlainText(QString("isGolbal() = %1\n").arg(host.isGlobal()));
        }
    }
}

protocol()函数:返回主机地址的网络层协议

QAbstractSocket::NetworkLayerProtocol QHostAddress::protocol() const
Returns the network layer protocol of the host address.

isGlobal()函数:如果地址是 IPv4 或 IPv6 全局地址,则返回 true,否则返回 false。全局地址是不为特殊目的(如环回或多播)或未来目的保留的地址。

bool QHostAddress::isGlobal() const
Returns true if the address is an IPv4 or IPv6 global address, false otherwise. A global address is an address that is not reserved for special purposes (like loopback or multicast) or future purposes.

自定义函数protocolName(),通过协议类型返回协议名称字符串。

c 复制代码
//通过协议类型返回协议名称字符串
QString Widget::protocolName(QAbstractSocket::NetworkLayerProtocol protocol)
{
    switch (protocol) {
    case QAbstractSocket::IPv4Protocol:
        return "IPV4";
    case QAbstractSocket::IPv6Protocol:
        return "IPV6";
    case QAbstractSocket::AnyIPProtocol:
        return "Any Internet Protocol";
    default:
        return "Unknown NetWork Layer Protocol";
    }
}
  1. 查找主机地址信息

[static] int QHostInfo::lookupHost(const QString &name, QObject *receiver, const char *member): name表示主机名的字符串,可以是主机名、域名或IP地址;receive和member指定接收者和槽函数名称。

c 复制代码
//查找域名的IP地址
void Widget::on_btnLookkup_clicked()
{
    ui->plainTextEdit->clear();
    QString hostName = ui->comboBox->currentText(); //读取主机名
    ui->plainTextEdit->appendPlainText("Searching for host information:"+hostName+"\n");
    QHostInfo::lookupHost(hostName, this,SLOT(do_lookedUpHostInfo(QHostInfo)));
}

//查找主机信息的槽函数
void Widget::do_lookedUpHostInfo(const QHostInfo &host)
{
    QList<QHostAddress> addrList = host.addresses();    //获取主机地址列表
    if(addrList.isEmpty())return;
    foreach(QHostAddress host, addrList)
    {
        bool show = ui->checkBox_OnlyIPV4->isChecked(); //只显示ipv4
        //Returns the network layer protocol of the host address.
        show = show ? (host.protocol() == QAbstractSocket::IPv4Protocol):true;
        if(show){
            ui->plainTextEdit->appendPlainText("protool:"+protocolName(host.protocol()));//协议
            ui->plainTextEdit->appendPlainText(host.toString());
            ui->plainTextEdit->appendPlainText(QString("isGolbal() = %1\n").arg(host.isGlobal()));
        }
    }
}
  1. QNetworkInterface类的使用
c 复制代码
//根据枚举值返回字符串
QString Widget::interfaceType(QNetworkInterface::InterfaceType type)
{
    switch(type){
    case QNetworkInterface::Unknown:
        return "Unkown";
    case QNetworkInterface::Loopback:
        return "Loopback";
    case QNetworkInterface::Ethernet:
        return "Etherent";
    case QNetworkInterface::Wifi:
        return "Wifi";
    default:
        return "Other type";
    }
}

//allInterfaces()
void Widget::on_btnAllInterface_2_clicked()
{
    ui->plainTextEdit->clear();
    QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();//网络接口列表
    foreach(QNetworkInterface interface,list){
        if(!interface.isValid())
            continue;
//        The name of the device
//        Hardware devices
//        Interface type
//        Subnet mask
//        broadcast address
        ui->plainTextEdit->appendPlainText("The name of the device:"+interface.humanReadableName());
        ui->plainTextEdit->appendPlainText("Hardware devices:"+interface.hardwareAddress());
        ui->plainTextEdit->appendPlainText("Interface type:"+interfaceType(interface.type()));
        QList<QNetworkAddressEntry> entryList = interface.addressEntries();//地址列表
        foreach(QNetworkAddressEntry entry, entryList){
            ui->plainTextEdit->appendPlainText("    IP Address:"+entry.ip().toString());
            ui->plainTextEdit->appendPlainText("    Subnet mask:"+entry.netmask().toString());
            ui->plainTextEdit->appendPlainText("    broadcast address:"+entry.broadcast().toString()+"\n");
        }
    }
}

//alladdress
void Widget::on_btnAllAddress_clicked()
{
    ui->plainTextEdit->clear();
    QList<QHostAddress> addrelist = QNetworkInterface::allAddresses();//IP地址列表
    if(addrelist.isEmpty()) return;
    foreach(QHostAddress host, addrelist){
        bool show = ui->checkBox_OnlyIPV4->isChecked();
        show = show ? (host.protocol() == QAbstractSocket::IPv4Protocol):true;
        if(show){
            ui->plainTextEdit->appendPlainText("protocol:"+protocolName(host.protocol()));
            ui->plainTextEdit->appendPlainText("IP Address:"+host.toString());
            ui->plainTextEdit->appendPlainText(QString("isGrobal() = %1\n").arg(host.isGlobal()));
        }
    }
}
Loopback:
回送地址(Loopback Address)是本机回送地址(127.X.X.X),即主机IP堆栈内部的IP地址,主要用于网络软件测试以及本地机进程间通信。因此,无论什么程序,一旦使用回送地址发送数据,协议软件会立即将其返回,不进行任何网络传输。

127.0.0.1是回送地址,又指本地机,一般用来测试使用。

项目2:基于HTTP的网络应用程序

QNetworkRequest 类通过 URL 发起网络协议请求,其也保存网络请求的信息,目前支持 HTTP、

FTP 和本地文件 URL 的下载或上传。

QNetworkAccessManager 类用于协调网络操作,在 QNetworkRequest 发起网络请求后,

QNetworkAccessManager 负责发送网络请求,以及创建网络响应。

QNetworkReply 类表示网络请求的响应,由 QNetworkAccessManager 在发送网络请求后创建网

络响应。QNetworkReply 提供的信号 finished()、readyRead()、downloadProgress()可用于监测网络响

应的执行情况,从而进行相应的操作。
发起网络协议请求 发送网络请求,以及创建网络响应 监测网络响应

2.1 项目中用到的函数详解

  1. clearButtonEnabled : bool

    此属性用于保存行编辑在不为空时是否显示清除按钮。

    如果启用,行编辑在包含一些文本时会显示一个尾随清除按钮,否则,行编辑不会显示清除按钮(默认值)。

  2. 默认路径按钮功能:

  • [static] QString QDir::currentPath()
    返回应用进程当前目录的绝对路径。当前目录是使用 QDir::setCurrent() 设置的最后一个目录,或者,如果从未调用过,则为父进程启动此应用进程的目录。
  • bool QDir::mkdir(const QString &dirName) const
    创建一个名为 dirName 的子目录。
  1. 下载按钮功能:
  • QString QString::trimmed() const
    返回一个字符串,该字符串删除了开头和结尾的空格。
  • [static] QUrl QUrl::fromUserInput(const QString &userInput)
    从用户提供的 userInput 字符串返回有效的 URL(如果可以扣除)。如果不可能,则返回无效的 QUrl()。
  • QString QUrl::errorString() const
    如果修改此 QUrl 对象的最后一个操作遇到解析错误,则返回错误消息。如果未检测到错误,则此函数返回一个空字符串,isValid() 返回 true。
  • QString QUrl::fileName(QUrl::ComponentFormattingOptions options = FullyDecoded) const
    返回文档名,不包括目录路径。
  • bool QFile::remove()
    删除 fileName() 指定的文档。如果成功,则返回 true;否则返回 false。文档在删除之前已关闭。
  • QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
    发布一个请求以获取目标请求的内容,并返回一个新的 QNetworkReply 对象,该对象打开以供读取,每当新数据到达时,该对象都会发出 readyRead() 信号。将下载内容以及相关的标题。
  • [signal] void QIODevice::readyRead()
    每当有新数据可用时,此信号就会发出一次从设备的当前读取信道读取。只有当有新数据可用时,它才会再次发出,例如,当新的网络数据有效负载到达您的网络套接字时,或者当新的数据块附加到您的设备时。
  • [signal] void QNetworkReply::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
    发出此信号以指示此网络请求的下载部分的进度(如果有)。如果没有与此请求关联的下载,则此信号将发出一次,其中 0 作为 bytesReceived 和 bytesTotal 的值。
  • [signal] void QNetworkReply::finished()
    当回复完成处理时,将发出此信号。发出此信号后,回复的数据或元数据将不再更新。
  1. 读取下载数据
  • qint64 QIODevice::write(const char *data, qint64 maxSize)

    将数据中最多 maxSize 字节的数据写入设备。返回实际写入的字节数,如果发生错误,则返回 -1。

  • QByteArray QIODevice::readAll()

    从设备读取所有剩余数据,并将其作为字节数组返回。

2.2 主要源码

头文件

c 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QNetworkAccessManager>
#include <QFile>
#include <QMessageBox>
#include <QIODevice>
#include <QNetworkReply>
#include <QDesktopServices>
#include <QFileInfo>
#include <QUrl>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT
private:
    QNetworkAccessManager networkManager;   //网络管理
    QNetworkReply *reply;                   //网络响应
    QFile *downloadedFile;                  //下载保存的临时文件
public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void do_finished();
    void do_readyRead();
    void do_downloadProgress(qint64 bytesRead, qint64 totalBytes);
    void on_btnDownload_clicked();

    void on_btnDefaultPath_clicked();

    void on_editURL_textChanged(const QString &arg1);

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

源文件

c 复制代码
#include "widget.h"
#include "ui_widget.h"

#include <QDir>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
//clearButtonEnabled : bool
//This property holds whether the line edit displays a clear button when it is not empty.
//If enabled, the line edit displays a trailing clear button when it contains some text,
//            otherwise the line edit does not show a clear button (the default).
    ui->editURL->setClearButtonEnabled(true);
    this->setLayout(ui->verticalLayout);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::do_finished()
{//网络响应结束
    QFileInfo fileInfo(downloadedFile->fileName()); //获取下载文件的文件名
    downloadedFile->close();
    delete downloadedFile;  //删除临时文件
    reply->deleteLater();   //由主事件循环删除此文件对象
    if(ui->checkBoxOpen->isChecked()){
        QDesktopServices::openUrl(QUrl::fromLocalFile(fileInfo.absoluteFilePath()));
    }
    ui->btnDownload->setEnabled(true);
}

void Widget::do_readyRead()
{
    //读取下载数据
    downloadedFile->write(reply->readAll());
//    qint64 QIODevice::write(const char *data, qint64 maxSize)
//    Writes at most maxSize bytes of data from data to the device.
//            Returns the number of bytes that were actually written,
//            or -1 if an error occurred.
//    QByteArray QIODevice::readAll()
//    Reads all remaining data from the device, and returns it as a byte array.

}

void Widget::do_downloadProgress(qint64 bytesRead, qint64 totalBytes)
{//下载进度
    ui->progressBar->setMaximum(totalBytes);
    //Holds the total amount of data to download in bytes.
    ui->progressBar->setValue(bytesRead);
}


//默认了路径 按钮
void Widget::on_btnDefaultPath_clicked()
{
//    [static] QString QDir::currentPath()
//    Returns the absolute path of the application's current directory.
//            The current directory is the last directory set with QDir::setCurrent() or,
//            if that was never called,
//            the directory at which this application was started at by the parent process.
    QString curPath = QDir::currentPath();  //返回当前绝对路径给QString变量
    QDir dir(curPath);                      //定义QDir变量
    QString sub = "temp";
//    bool QDir::mkdir(const QString &dirName) const
//    Creates a sub-directory called dirName.
    dir.mkdir(sub);                         //当前路径下创立名为sub的文件夹
    ui->editPath->setText(curPath+"/"+sub+"/"); //设置lineedit的文字
}

//下载按钮,开始下载
void Widget::on_btnDownload_clicked()
{
//    QString QString::trimmed() const
//    Returns a string that has whitespace removed from the start and the end.
    QString urlSpec = ui->editURL->text().trimmed();    //将editURL中的文字给QString变量赋值
    //urlspec判空
    if(urlSpec.isEmpty()){
        QMessageBox::information(this,"error","Please specify the download address");
        return;
    }
//    [static] QUrl QUrl::fromUserInput(const QString &userInput)
//    Returns a valid URL from a user supplied userInput string if one can be deducted.
//    In the case that is not possible, an invalid QUrl() is returned.
    QUrl newUrl = QUrl::fromUserInput(urlSpec); //从urlSpaec里获取url
    //newurl判有效
    if(!newUrl.isValid()){
//        QString QUrl::errorString() const
//        Returns an error message if the last operation that modified this QUrl object ran into a parsing error.
//                If no error was detected,
//                this function returns an empty string and isValid() returns true.
        QString info = "The URL is invalid:"+urlSpec+"\n error:"+newUrl.errorString();
        QMessageBox::information(this,"error",info);
        return;
    }

    QString tempDir = ui->editPath->text().trimmed();   //临时目录
    if(tempDir.isEmpty()){
        QMessageBox::information(this,"error","Please specify the download address");
        return;
    }

    QString fullFileName = tempDir + newUrl.fileName(); //文件名
//    QString QUrl::fileName(QUrl::ComponentFormattingOptions options = FullyDecoded) const
//    Returns the name of the file, excluding the directory path.
    if(QFile::exists(fullFileName)){ //如果文件存在
        QFile::remove(fullFileName);    //删除文件
//        bool QFile::remove()
//        Removes the file specified by fileName(). Returns true if successful; otherwise returns false.
//        The file is closed before it is removed.
    }

    downloadedFile = new QFile(fullFileName);   //创建临时文件
    if(!downloadedFile->open(QIODevice::WriteOnly)){
        QMessageBox::information(this,"error","Temporary file open error");
    }
    ui->btnDownload->setEnabled(false);
    //发送网络请求,创建网络相应
    reply = networkManager.get(QNetworkRequest(newUrl));    //网络响应从网络管理里面获取网络请求
//    QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
//            Posts a request to obtain the contents of the target request and
//            returns a new QNetworkReply object opened for reading
//            which emits the readyRead() signal whenever new data arrives.
//            The contents as well as associated headers will be downloaded.
//    QObject *QObject::parent() const
//    Returns a pointer to the parent object.

    connect(reply, SIGNAL(readyRead()), this, SLOT(do_readyRead()));
    connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
            this, SLOT(do_downloadProgress(qint64,qint64)));
    connect(reply, SIGNAL(finished()), this, SLOT(do_finished()));
//    [signal] void QIODevice::readyRead()
//    This signal is emitted once every time new data is available for
//    reading from the device's current read channel.
//    It will only be emitted again once new data is available,
//    such as when a new payload of network data has arrived on your network socket,
//    or when a new block of data has been appended to your device.
//    [signal] void QNetworkReply::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
//    This signal is emitted to indicate the progress of the download part of
//    this network request, if there's any. If there's no download associated with this request,
//    this signal will be emitted once with 0 as the value of both bytesReceived and bytesTotal.
//    [signal] void QNetworkReply::finished()
//    This signal is emitted when the reply has finished processing.
//    After this signal is emitted, there will be no more updates to the reply's data or metadata.
}

void Widget::on_editURL_textChanged(const QString &arg1)
{
    Q_UNUSED(arg1);
    ui->progressBar->setMaximum(100);
    ui->progressBar->setValue(0);
}

  1. IP地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。 ↩︎

  2. MAC地址(英语:Media Access Control Address),直译为媒体存取控制位址,也称为局域网地址(LAN Address),MAC位址,以太网地址(Ethernet Address)或物理地址(Physical Address),它是一个用来确认网络设备位置的位址。在OSI模型中,第三层网络层负责IP地址,第二层数据链路层则负责MAC位址。MAC地址用于在网络中唯一标示一个网卡,一台设备若有一或多个网卡,则每个网卡都需要并会有一个唯一的MAC地址。 ↩︎

相关推荐
速盾cdn24 分钟前
速盾:CDN是否支持屏蔽IP?
网络·网络协议·tcp/ip
yaoxin52112324 分钟前
第二十七章 TCP 客户端 服务器通信 - 连接管理
服务器·网络·tcp/ip
内核程序员kevin26 分钟前
TCP Listen 队列详解与优化指南
linux·网络·tcp/ip
Theodore_10221 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
PersistJiao2 小时前
Spark 分布式计算中网络传输和序列化的关系(一)
大数据·网络·spark
----云烟----3 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024063 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic4 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it4 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康4 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud