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

2023-11-04

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();
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • 绝地救生error_30种面向前端开发人员的救生工具

    绝地救生error As the functionalities of web apps keep getting ever more sophisticated and complex web developers need flexib
  • 【2】数据湖架构中 Iceberg 的核心特性

    在业界的数据湖方案中有 Hudi Iceberg 和 Delta 三个关键组件可供选择 一 Iceberg 是什么 Iceberg 官网中是这样定义的 Apache Iceberg is an open table format for h
  • JS封装计算1~100之间所有整数的总和与平均值

    function getSum var sum 0 for i 0 i lt 100 i sum i console log 1 100所有数和为 sum console log 1 100所有数和的平均值为 sum 100 getSum
  • Intellij idea 导入 jdbc

    第一步 去官网https dev mysql com downloads connector j 下载驱动程序 第二步 解压压缩包 记住路径 第三步 打开你的idea工程 打开Project Structure Modules gt gt
  • RabbitMQ - 死信、TTL原理、延迟队列安装和配置

    目录 一 死信交换机 1 1 什么是死信交换机 1 2 TTL 1 2 1 什么是 TTL 1 2 2 通过 TTL 模拟触发死信 二 延迟队列 2 1 什么是延迟队列 2 2 配置延迟队列插件 2 2 1 延迟队列配置 a 下载镜像 b
  • pyhive报错Could not start SASL: b‘Error in sasl_client_start (-4) SASL(-4)

    python3连接hive 1 安装对应依赖 2 连接hive 3 常见报错 1 安装对应依赖 pip install sasl pip install thrift pip install thrift sasl pip install
  • 快速上手Cruisecontrol

    1 Cruisecontrol的概述 CruiseControl是一种持续集成过程的框架 包括了邮件通知 ant和各种源码控制工具的插件 并提供web接口 用于查看当前和以前的build的结果 2 Cruisecontrol的安装 2 1
  • windows下免费本地部署类ChatGpt的国产ChatGLM-6B

    ChatGLM 6B 是一个开源的 支持中英双语的对话语言模型 基于 General Language Model GLM 架构 具有 62 亿参数 结合模型量化技术 用户可以在消费级的显卡上进行本地部署 INT4 量化级别下最低只需 6G
  • 万字长文,SpringSecurity

    思维导图如下 RBAC权限分析 RBAC 全称为基于角色的权限控制 本段将会从什么是RBAC 模型分类 什么是权限 用户组的使用 实例分析等几个方面阐述RBAC 思维导图 绘制思维导图如下 什么是RBAC RBAC 全称为用户角色权限控制
  • javascript算法之数组反转浅谈

    本文主要介绍了javascript算法之数组反转 文章围绕主题展开详细的内容介绍 具有一定的参考价值 需要的小伙伴可以参考一下 1 数组反转 1 1 leecode题目 旋转数组 给你一个数组 将数组中的元素向右轮转 k 个位置 其中 k
  • Servlet是不是线程安全的?

    首先在servlet中的方法 三个重要方法 1 init 进行资源的加载 2 service 处理请求 根据请求方式 调用doGet或者doPost 3 destroy 进行资源的释放 servlet是单实例的 假如在处理请求时候 多线程访
  • AcWing 104. 货仓选址

    题目 在一条数轴上有 N 家商店 它们的坐标分别为 A1 AN 现在需要在数轴上建立一家货仓 每天清晨 从货仓到每家商店都要运送一车商品 为了提高效率 求把货仓建在何处 可以使得货仓到每家商店的距离之和最小 输入格式 第一行输入整数N 第二
  • windows下访问linux下的文件,【IT之家学院】如何从Win10访问Linux子系统中的文件 - IT之家...

    在19H1 目前处于Insider Preview阶段 预计4月份正式推送 中 微软为适用于Linux的Windows子系统带来了一项有趣的功能 这项功能允许用户从Windows 10访问Linux子系统中的文件 今天的这期教程 我们来讨论
  • AppScan 漏扫工具-保姆及配置使用说明

    本文章仅供学习使用 严禁在未经网站管理员的允许的条件下扫描任何网站 工具的滥用违反国家安全法后果自负 申明 本文实验环境在内网中进行 网站为自己服务器所搭建的sqli labs DVWA master测试网站 1 AppScan安装和基础配
  • 请分别创建出listA、listB、listC,完成以下各题 (1)将listC中的内容添加到listB中: (2)输出listA与listB的交集listD; (3)输出listA与listB的并集...

    答 1 将listC中的内容添加到listB中 将listC中的每一项元素都添加到listB尾部 2 输出listA与listB的交集listD 定义一个空listD 遍历listA中的每个元素 如果listB中有相同的元素 则将该元素加入
  • 爬虫碰到状态码412的解决办法

    爬虫碰到状态码412 近期在使用python的requests库爬取网页时 碰到返回状态码为412的情况 状态码412含义为 Precondition Failed 服务器在验证在请求的头字段中给出先决条件时 没能满足其中的一个或多个 这个
  • Arthas 使用实践

    文章目录 1 Arthas 2 学习总结 2 1 所有环境都在线上 学习时不用自己搭环境 2 2 官方文档 2 3 相关参考博文 2 4 idea arthas 插件 3 各种捣腾 3 1 Arthas 下载使用 3 2 支持管道操作 3
  • 物联网智能病床项目

    目录 第一部分 系统架构 第二部分 MCU工作过程 第三部分 嵌入式操作系统 第一部分 系统架构 总体采用设备端 MCU 医用传感器 通信模组 WiFi 蓝牙 4G 通信端 MQTT协议 应用层服务器组成构建一整套物联网系统 第二部分 MC
  • pytest框架之fixture测试夹具详解

    一 fixture的优势 pytest框架的fixture测试夹具就相当于unittest框架的setup teardown 但相对之下它的功能更加强大和灵活 命名方式灵活 不限于unittest的setup teardown 可以实现数据
  • 14-1_Qt 5.9 C++开发指南_网络编程及主机信息查询_HostInfo

    Qt 网络模块提供了用于编写 TCP IP 客户端和服务器端程序的各种类 如用于 TCP 通信的QTcpSocket 和 QTcpServer 用于 UDP 通信的 QUdpSocket 还有用于实现 HTTP FTP 等普通网络协议的高级