14-1_Qt 5.9 C++开发指南_网络编程及主机信息查询_HostInfo

Qt 网络模块提供了用于编写 TCP/IP 客户端和服务器端程序的各种类,如用于 TCP 通信的QTcpSocket 和 QTcpServer,用于 UDP 通信的 QUdpSocket,还有用于实现 HTTP、FTP 等普通网络协议的高级类如 QNetworkRequest,QNetworkReply 和QNetworkAccessManager。Qt 网络模块还提供用于网络代理、网络承载管理的类,提供基于安全套接字层 (Secure Sockets Layer,SSL)协议的安全网络通信的类。

本章主要介绍基本的 TCP 和 UDP 网络通信类的使用,基于 HTTP 的网络下载管理的实现。

要在程序中使用 Qt 网络模块,需要在项目配置文件中增加一条配置语句:
Qt+= network

1. QHostInfo 和 QNetworkInterface 类

查询一个主机的MAC地址或IP 地址是网络应用程序中经常用到的功能,Qt提供了QHostInfo和QNetworkInterface 类可以用于此类信息的查询。

QHostInfo 的静态函数 localHostName()可获取本机的主机名,静态函数 fromName()可以通过主机名获取 IP 地址,静态函数 lookupHost()可以通过一个主机名,以异步方式查找这个主机的 IP地址。表14-1 是QHostInfo 类主要的功能函数(省略了函数中的 const 关键字)。
在这里插入图片描述
QNetworkInterface 可以获得运行应用程序的主机的所有 IP 地址和网络接口列表。静态函数alInterfaces()返回主机上所有的网络接口的列表,一个网络接口可能包括多个的 IP 地址,每个IP地址与掩码或广播地址关联。如果无需知道子网掩码和广播的IP 地址,使用静态函数 allAddresses()可以获得主机上的所有IP 地址列表。表 14-2是 QNetworkInterface 类的主要功能函数。
在这里插入图片描述

为演示这两个类的主要功能,创建一个窗口基于 QDialog 的应用程序 samp14_1,实例运行时界面如图 14-1 所示。对话框界面由 UI设计器设计,主要代码都是各按钮的 clicked()信号的槽函数。

在这里插入图片描述

2.可视化UI设计框架

在这里插入图片描述

3. QHostInfo的使用

3.1 显示本机地址信息

图 14-1 窗口上的“QHostInfo 获取本机主机名和IP 地址”按钮的响应代码如下:

void Dialog::on_btnGetHostInfo_clicked()
{//QHostInfo获取主机信息
//    ui->plainTextEdit->clear();

    QString hostName=QHostInfo::localHostName();//本地主机名
    ui->plainTextEdit->appendPlainText("本机主机名:"+hostName+"\n");

    QHostInfo   hostInfo=QHostInfo::fromName(hostName); //本机IP地址

    QList<QHostAddress> addList=hostInfo.addresses();//IP地址列表
    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i); //每一项是一个QHostAddress
        bool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4
        if (show)
            show=(QAbstractSocket::IPv4Protocol==aHost.protocol()); //协议类型,
        else
            show=true;
        if (show) {
        ui->plainTextEdit->appendPlainText("协 议:"+protocolName(aHost.protocol()));//协议类型
        ui->plainTextEdit->appendPlainText("本机IP地址:"+aHost.toString()); //IP地址
        ui->plainTextEdit->appendPlainText("");
        }
    }
}

这段代码先通过静态函数QHostInfo::localHostName()获取本机主机名hostName,然后再使用主机名作为参数,用静态函数QHostInfo::fromName(hostName)获取主机的信息 hostInfo。

hostInfo 是 QHostInfo 类的实例,通过其函数addresses()获取主机的IP 地址列表。

QList<QHostAddress> addList=hostInfo.addresses();//IP地址列表

返回的addList是QHostAddress 类的列表,QHostAddress 类提供一个IP 地址的信息,包括IPv4地址和IPv6 地址。QHostAddress 有以下两个主要的函数。

  • protocol() 返回 QAbstractSocket::NetworkLayerProtocol类型变量,表示当前IP 地址的协议类型。QAbstractSocket::NetworkLayerProtocol枚举类型的取值见表14-3。
    在这里插入图片描述

  • toString()返回IP 地址的字符串,表示程序中显示了IP 地址列表中每个IP 地址的协议类型和IP 地址字符串,为根据 protocol()返回的 QAbstractSocket::NetworkLayerProtocol 枚举值显示协议名称字符串,自定义了一个函数 protocolName(),代码如下:

QString Dialog::protocolName(QAbstractSocket::NetworkLayerProtocol protocol)
{//通过协议类型返回协议名称
  switch(protocol)
  {
    case QAbstractSocket::IPv4Protocol:
        return "IPv4 Protocol";
    case QAbstractSocket::IPv6Protocol:
      return "IPv6 Protocol";
    case QAbstractSocket::AnyIPProtocol:
      return "Any IP Protocol";
    default:
      return "Unknown Network Layer Protocol";
   }
}

单击“QHostInfo 获取本机主机名和 IP 地址”按钮,如果勾选了“只显示 IPv4 协议地址”复选框,就只显示本机的 IPv4 地址,否则显示所有 IP 地址信息。

3.2 查找主机地址信息

QHostInfo 的静态函数 lookupHost()可以根据主机名、域名或 IP 地址查找主机的地址信息,lookupHost()函数原型如下:

[static] int QHostInfo::lookupHost(const QString &name, QObject *receiver, const char *member)

输入参数 name 是表示主机名的字符串,可以是一个主机名、一个域名,或者是一个IP 地址。

lookupHost()以异步方式查找主机地址,参数 receiver 和 member 指定一个响应槽函数的接收者和槽函数名称。执行 lookupHost()后,程序可能需要花一定时间来查找主机地址,但不会阻塞程序的运行。当查找到主机地址后,通过信号通知设定的槽函数,在槽函数里读取查找的结果。函数返回一个表示查找的 ID。
图14-1 中的“QHostInfo 查找域名的IP 地址”按的槽函数及 lokupHost()函数关联槽函数代码如下:

void Dialog::on_btnLookup_clicked()
{//查找主机信息
    QString hostname=ui->editHost->text(); //主机名
    ui->plainTextEdit->appendPlainText("正在查找查找主机信息:"+hostname);
    QHostInfo::lookupHost(hostname,this,SLOT(lookedUpHostInfo(QHostInfo)));
}

void Dialog::lookedUpHostInfo(const QHostInfo &host)
{//查找主机信息的槽函数
//    ui->plainTextEdit->clear();
    QList<QHostAddress> addList=host.addresses();//
    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i);
        bool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4
        if (show)
            show=QAbstractSocket::IPv4Protocol==aHost.protocol();
        else
            show=true;

        if (show) {
        ui->plainTextEdit->appendPlainText("协 议:"+protocolName(aHost.protocol()));
        ui->plainTextEdit->appendPlainText(aHost.toString());
        }
    }
}

运行结果如下图:
在这里插入图片描述

4. QNetworkInterface 的使用

QNetworkInterface 可以获得应用程序所在主机的所有网络接口,包括其子网掩码和广播地址等。

静态函数QNetworkInterface::allInterfaces()获取所有网络接口的列表,函数原型为:

[static] [QList](../qtcore/qlist.html)<[QNetworkInterface](qnetworkinterface.html#QNetworkInterface)> QNetworkInterface::allInterfaces()

其返回结果是一个QNetworkInterface 类的列表。

界面上“QNetworkInterface::allInterfaces()”按钮的响应代码如下:

void Dialog::on_btnALLInterface_clicked()
{//QNetworkInterface::allInterfaces()函数的使用
//    ui->plainTextEdit->clear();

    QList<QNetworkInterface>    list=QNetworkInterface::allInterfaces();
    for(int i=0;i<list.count();i++)
    {
        QNetworkInterface aInterface=list.at(i);
        if (!aInterface.isValid())
           continue;

        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("设备名称:")+aInterface.humanReadableName());
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("硬件地址:")+aInterface.hardwareAddress());
        QList<QNetworkAddressEntry> entryList=aInterface.addressEntries();
        for(int j=0;j<entryList.count();j++)
        {
            QNetworkAddressEntry aEntry=entryList.at(j);
            ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   IP 地址:")+aEntry.ip().toString());
            ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   子网掩码:")+aEntry.netmask().toString());
            ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   广播地址:")+aEntry.broadcast().toString()+"\n");
        }
        ui->plainTextEdit->appendPlainText("\n");
    }
}

通过QNetworkInterface::allInterfaces()获取网络接口列表 list之后,显示每个接口的 humanReadableName()和 hardwareAddress()。每个接口又有一个 QNetworkAddressEntry 类型的地址列表,通过addressEntries ()获得这个列表。
QNetworkAddressEntry 包含了一个网络接口的 IP 地址、子网掩码和广播地址,分别用 ip()、netmask()和 broadcast()函数返回。
QNetworkInterface::allInterfaces()返回的网络接口的信息很多,如果无需知道子网掩码和广播地址等信息,可以使用 QNetworkInterface::allAddresses()只获取IP 地址。

界面上“QNetworkInterface ::allAddresses()”按钮的响应代码如下:

void Dialog::on_btnDetail_clicked()
{//QNetworkInterface::allAddresses()的使用
//    ui->plainTextEdit->clear();

    QList<QHostAddress> addList=QNetworkInterface::allAddresses();//
    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i);
        bool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4
        if (show)
            show=QAbstractSocket::IPv4Protocol==aHost.protocol();
        else
            show=true;

        if (show)
        {
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("协  议:")+protocolName(aHost.protocol()));
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("IP地址:")+aHost.toString());
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit(""));
        }
    }
}

QNetworkInterface ::allAddresses()的功能与 QHstInfo:addresses()函数功能相似,都是返回-个QHostAddress 的列表。只是 QNetworkInterface 会返回更多地址,包括表示本机的 127.0.0.1,而QHostInfo 不会返回这个IP 地址。

5. 源码

5.1 dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include    <QDialog>
#include    <QHostInfo>

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private slots:
    void lookedUpHostInfo(const QHostInfo &host);

//===========================
    void on_btnGetHostInfo_clicked();

    void on_btnDetail_clicked();

    void on_btnLookup_clicked();

    void on_btnALLInterface_clicked();

    void on_btnClear_clicked();

private:
    Ui::Dialog *ui;

    QString  protocolName(QAbstractSocket::NetworkLayerProtocol protocol);
};

#endif // DIALOG_H

5.2 dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

#include    <QHostInfo>
#include    <QNetworkInterface>

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
}

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

void Dialog::lookedUpHostInfo(const QHostInfo &host)
{//查找主机信息的槽函数
//    ui->plainTextEdit->clear();
    QList<QHostAddress> addList=host.addresses();//
    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i);
        bool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4
        if (show)
            show=QAbstractSocket::IPv4Protocol==aHost.protocol();
        else
            show=true;

        if (show) {
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("协 议:")+protocolName(aHost.protocol()));
        ui->plainTextEdit->appendPlainText(aHost.toString());
        }
    }
}

void Dialog::on_btnGetHostInfo_clicked()
{//QHostInfo获取主机信息
//    ui->plainTextEdit->clear();

    QString hostName=QHostInfo::localHostName();//本地主机名
    ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("本机主机名:")+hostName+"\n");

    QHostInfo   hostInfo=QHostInfo::fromName(hostName); //本机IP地址

    QList<QHostAddress> addList=hostInfo.addresses();//IP地址列表
    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i); //每一项是一个QHostAddress
        bool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4
        if (show)
            show=(QAbstractSocket::IPv4Protocol==aHost.protocol()); //协议类型,
        else
            show=true;
        if (show) {
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("协 议:")+protocolName(aHost.protocol()));//协议类型
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("本机IP地址:")+aHost.toString()); //IP地址
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit(""));
        }
    }
}

void Dialog::on_btnDetail_clicked()
{//QNetworkInterface::allAddresses()的使用
//    ui->plainTextEdit->clear();

    QList<QHostAddress> addList=QNetworkInterface::allAddresses();//
    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i);
        bool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4
        if (show)
            show=QAbstractSocket::IPv4Protocol==aHost.protocol();
        else
            show=true;

        if (show)
        {
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("协  议:")+protocolName(aHost.protocol()));
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("IP地址:")+aHost.toString());
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit(""));
        }
    }
}

void Dialog::on_btnLookup_clicked()
{//查找主机信息
    QString hostname=ui->editHost->text(); //主机名
    ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("正在查找查找主机信息:")+hostname);
    QHostInfo::lookupHost(hostname,this,SLOT(lookedUpHostInfo(QHostInfo)));
}

void Dialog::on_btnALLInterface_clicked()
{//QNetworkInterface::allInterfaces()函数的使用
//    ui->plainTextEdit->clear();

    QList<QNetworkInterface>    list=QNetworkInterface::allInterfaces();
    for(int i=0;i<list.count();i++)
    {
        QNetworkInterface aInterface=list.at(i);
        if (!aInterface.isValid())
           continue;

        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("设备名称:")+aInterface.humanReadableName());
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("硬件地址:")+aInterface.hardwareAddress());
        QList<QNetworkAddressEntry> entryList=aInterface.addressEntries();
        for(int j=0;j<entryList.count();j++)
        {
            QNetworkAddressEntry aEntry=entryList.at(j);
            ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   IP 地址:")+aEntry.ip().toString());
            ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   子网掩码:")+aEntry.netmask().toString());
            ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   广播地址:")+aEntry.broadcast().toString()+"\n");
        }
        ui->plainTextEdit->appendPlainText("\n");
    }
}

QString Dialog::protocolName(QAbstractSocket::NetworkLayerProtocol protocol)
{//通过协议类型返回协议名称
  switch(protocol)
  {
    case QAbstractSocket::IPv4Protocol:
        return "IPv4 Protocol";
    case QAbstractSocket::IPv6Protocol:
      return "IPv6 Protocol";
    case QAbstractSocket::AnyIPProtocol:
      return "Any IP Protocol";
    default:
      return "Unknown Network Layer Protocol";
   }
}

void Dialog::on_btnClear_clicked()
{
    ui->plainTextEdit->clear();
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十月旧城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值