QT_网络编程体系

QT 网络编程体系

Qt 网络编程基础

Qt 内置网络编程模块(Qt Network),基于 TCP/IP 协议提供客户端 / 服务端相关类:

  • TCP 通信QTcpSocket(客户端)、QTcpServer / QTcpServerSocket(服务端)
  • UDP 通信QUdpSocket
  • 高级协议 :还提供 HTTP、FTP 等常用网络协议的高层封装类,如 QNetworkRequestQNetworkAccessManagerQNetworkReply

Qt Network 模块除了提供基础网络访问能力,还提供网络承载管理,以及基于 SSL/TLS 协议的安全网络通信类(如 QSslSocketQSslServer)。

在开发中使用 UDP、TCP、HTTP 等通信类时,必须在项目中引入 Qt Network 模块。项目配置文件中的一条配置语句:

复制代码
QT += network

对应 CMake 写法:

cmake 复制代码
find_package(Qt6 REQUIRED COMPONENTS Network)
target_link_libraries(myapp PRIVATE Qt6::Network)

QHostInfo 类

QHostInfo 类提供 主机名查找(DNS 解析) 的静态函数,主要用于查询主机信息,包括主机名、IP 地址、DNS 域名等。支持国际化域名(IDN),并内置约 60 秒的 DNS 查询结果缓存。

常用静态函数

函数 说明
QHostInfo::fromName(name) 阻塞式 查询,直接返回一个 QHostInfo 对象(含查询结果)
QHostInfo::lookupHost(name, receiver, slot) 异步查询,完成时触发槽函数,返回一个查询 ID
QHostInfo::localHostName() 获取本机主机名
QHostInfo::localDomainName() 获取本机所在域名
QHostInfo::abortHostLookup(id) 根据查询 ID 取消一次异步查询

常用成员函数

函数 说明
addresses() 返回查询到的 IP 地址列表(QList<QHostAddress>
hostName() 返回查询的主机名
error() 返回错误类型(NoError / HostNotFound / UnknownError
errorString() 返回错误的可读描述
lookupId() 返回本次查询的 ID

用法示例

cpp 复制代码
// 异步查询:解析域名得到 IP 地址列表
QHostInfo::lookupHost("qt-project.org", this, &MyWidget::printResults);

// 阻塞查询
QHostInfo info = QHostInfo::fromName("www.example.com");
if (info.error() == QHostInfo::NoError) {
    foreach (const QHostAddress &addr, info.addresses())
        qDebug() << addr.toString();
}

QNetworkInterface 类

QNetworkInterface 类主要用于获取主机所有 IP 地址和网络接口列表信息。每个网络接口可包含多个 IP 地址及其子网掩码、广播地址。

常用静态函数

函数 说明
QNetworkInterface::allInterfaces() 返回主机上所有网络接口的列表(QList<QNetworkInterface>
QNetworkInterface::allAddresses() 返回所有活动接口的 IP 地址列表(QList<QHostAddress>
QNetworkInterface::interfaceFromName(name) 按名称查找网络接口
QNetworkInterface::interfaceFromIndex(index) 按索引号查找网络接口
QNetworkInterface::interfaceIndexFromName(name) 由接口名称获取索引号
QNetworkInterface::interfaceNameFromIndex(index) 由索引号获取接口名称

常用成员函数

函数 说明
name() 接口名称(如 "eth0")
humanReadableName() 接口的友好可读名称
hardwareAddress() 硬件地址(MAC 地址)
addressEntries() 返回该接口的 IP 地址条目列表(QList<QNetworkAddressEntry>
flags() 接口标志(如 IsUpIsRunningCanBroadcastIsLoopBackCanMulticast 等)
type() 接口类型(EthernetWifiLoopbackVirtual 等)
isValid() 判断接口是否有效
index() 接口索引号
maximumTransmissionUnit() 最大传输单元(MTU)

用法示例

cpp 复制代码
// 遍历所有网络接口,输出名称、硬件地址及 IP 地址
const QList<QNetworkInterface> nets = QNetworkInterface::allInterfaces();
for (const QNetworkInterface &netIf : nets) {
    qDebug() << "Interface:" << netIf.name()
             << "MAC:" << netIf.hardwareAddress();

    const QList<QNetworkAddressEntry> entries = netIf.addressEntries();
    for (const QNetworkAddressEntry &entry : entries)
        qDebug() << "  IP:" << entry.ip().toString();
}

案例

案例一、获取本地机器信息

dialog.h

cpp 复制代码
#ifndef DIALOG_H
#define DIALOG_H

#include <QTextEdit>
#include <QDialog>
#include <QHostInfo>
#include <QNetworkInterface>
#include <QMessageBox>


QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACE

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();

    void GetHostNameAndIpAddress(); // 获取主机名称和IP地址


private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

private:
    Ui::Dialog *ui;
};
#endif // DIALOG_H

dialog.cpp

cpp 复制代码
#include "dialog.h"
#include "ui_dialog.h"

#include <QVBoxLayout>
#include <QPushButton>

// 构造函数:初始化界面
Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this); // 加载 .ui 文件生成的界面
}

// 析构函数:释放 ui 对象
Dialog::~Dialog()
{
    delete ui;
}

// 功能:获取主机名称和 IP 地址,并显示在对应的输入框中
void Dialog::GetHostNameAndIpAddress()
{
    // 1. 获取本机主机名称
    QString strLocalHostName = QHostInfo::localHostName();
    // 将主机名称显示到 "主机名称" 输入框中
    ui->lineEdit_hostName->setText(strLocalHostName);

    // 2. 根据主机名称解析出对应的 IP 地址
    QString strLocalIpAddress = "";
    // 通过主机名查询主机信息(可能解析出多个地址)
    QHostInfo hostInfo = QHostInfo::fromName(strLocalHostName);
    // 取出所有解析到的 IP 地址
    QList<QHostAddress> ipAddressList = hostInfo.addresses();

    if (!ipAddressList.isEmpty()) {
        // 遍历地址列表,优先取第一个 IPv4 协议的地址
        for (int i = 0; i < ipAddressList.size(); i++) {
            QHostAddress address = ipAddressList.at(i);
            // 只保留 IPv4 协议地址(过滤掉 IPv6 等)
            if (QAbstractSocket::IPv4Protocol == address.protocol()) {
                strLocalIpAddress = address.toString();
                break; // 找到即停止
            }
        }
    }
    // 将 IP 地址显示到 "主机IP地址" 输入框中
    ui->lineEdit_hostIP->setText(strLocalIpAddress);
}

// 槽函数:点击 "获取主机名称和IP地址" 按钮时调用
void Dialog::on_pushButton_clicked()
{
    GetHostNameAndIpAddress();
}

// 槽函数:点击 "获取主机所有信息" 按钮时,枚举所有网络接口并弹出详情窗口
void Dialog::on_pushButton_2_clicked()
{
    QString strTemp = "";

    // 1. 获取本机主机名称
    QString hostName = QHostInfo::localHostName();
    strTemp += "主机名称:" + hostName + "\n\n";

    // 2. 获取本机所有网络接口(网卡)列表
    QList<QNetworkInterface> netList = QNetworkInterface::allInterfaces();

    for (int i = 0; i < netList.size(); i++) {
        QNetworkInterface interface = netList.at(i);

        // 跳过无效接口(例如未初始化或已移除的网卡)
        if (!interface.isValid())
            continue;

        strTemp += "设备名称:" + interface.humanReadableName() + "\n"; // 用户可读的设备名称
        strTemp += "接口标识:" + interface.name() + "\n";              // 系统接口标识
        strTemp += "硬件地址:" + interface.hardwareAddress() + "\n";   // MAC 地址

        // 接口状态:是否处于启用(UP)状态
        strTemp += "接口状态:" + QString(interface.flags().testFlag(QNetworkInterface::IsUp) ? "已启用" : "已禁用") + "\n";

        // 3. 获取该接口上配置的所有 IP 地址条目
        QList<QNetworkAddressEntry> entryList = interface.addressEntries();

        if (entryList.isEmpty()) {
            strTemp += "(无 IP 地址)\n";
        } else {
            // 遍历每个 IP 条目,输出 IP、子网掩码和广播地址
            for (int j = 0; j < entryList.size(); j++) {
                QNetworkAddressEntry entry = entryList.at(j);
                strTemp += "  IP 地址:" + entry.ip().toString() + "\n";                // IP 地址
                strTemp += "  子网掩码:" + entry.netmask().toString() + "\n";          // 子网掩码
                strTemp += "  广播地址:" + entry.broadcast().toString() + "\n";        // 广播地址
            }
        }

        strTemp += "--------------------------------\n"; // 分隔线,便于区分不同网卡
    }

    // 4. 将整理好的文本信息显示在弹出的对话框中(只读)
    QDialog dialog(this);
    dialog.setWindowTitle("主机网络信息");
    dialog.resize(500, 400);

    QVBoxLayout *layout = new QVBoxLayout(&dialog);      // 垂直布局
    QTextEdit *textEdit = new QTextEdit(&dialog);        // 文本显示控件
    textEdit->setReadOnly(true);                         // 设为只读,禁止编辑
    textEdit->setText(strTemp);                          // 填充网络信息内容
    textEdit->setTextInteractionFlags(Qt::TextSelectableByMouse); // 允许鼠标选中复制文本

    layout->addWidget(textEdit);                         // 添加文本控件

    QPushButton *closeBtn = new QPushButton("关闭", &dialog); // 关闭按钮
    connect(closeBtn, &QPushButton::clicked, &dialog, &QDialog::accept); // 点击后关闭窗口
    layout->addWidget(closeBtn);                         // 添加按钮控件

    dialog.exec(); // 以模态方式显示窗口
}

案例二、查询域名或 IP 地址

getdomainips.h

cpp 复制代码
#ifndef GETDOMAINIPS_H
#define GETDOMAINIPS_H

#include <QDialog>
#include <QHostInfo>
QT_BEGIN_NAMESPACE
namespace Ui { class GetDomainIps; }
QT_END_NAMESPACE

class GetDomainIps : public QDialog
{
    Q_OBJECT

public:
    GetDomainIps(QWidget *parent = nullptr);
    ~GetDomainIps();

    // 将网络层协议类型转换为可读字符串
    QString ProtocolTypeName(QAbstractSocket::NetworkLayerProtocol pro);

private slots:
    // DNS 查询完成后的回调,解析并展示主机名、IP 地址等详细信息
    void LookupHostInfofunc(const QHostInfo &host);

private slots:
    // 点击"清除数据信息"按钮:清空显示框
    void on_clearBtn_clicked();

    // 点击"查询域名或IP地址"按钮:发起 DNS 查询
    void on_getDomainIp_clicked();

private:
    Ui::GetDomainIps *ui;
};
#endif // GETDOMAINIPS_H

getdomainips.cpp

cpp 复制代码
#include "getdomainips.h"
#include "ui_getdomainips.h"

// 构造函数:初始化界面并设置默认查询域名
GetDomainIps::GetDomainIps(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::GetDomainIps)
{
    ui->setupUi(this);
    // 在输入框中预填一个默认的域名,方便测试
    ui->inputUrl->setText("www.baidu.com");
}

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


// 将网络层协议类型枚举值转换为可读的字符串名称
QString GetDomainIps::ProtocolTypeName(QAbstractSocket::NetworkLayerProtocol protocoltype){
    switch (protocoltype) {
    case QAbstractSocket::IPv4Protocol:
        return "IPv4 Protocol";        // IPv4 协议
    case QAbstractSocket::IPv6Protocol:
       return "IPv6 Protocol";         // IPv6 协议
    case QAbstractSocket::AnyIPProtocol:
       return "Any IP Protocol";       // 任意 IP 协议
    default:
        return "UnknownNetworkLayerProtocol";  // 未知协议类型
    }

}
// 槽函数:DNS 查询完成后的回调,参数 host 携带查询结果
void GetDomainIps::LookupHostInfofunc(const QHostInfo &host){
    // 先检查查询是否出错
    if (host.error() != QHostInfo::NoError) {
        // 输出错误类型和错误描述
        ui->domainIp->appendPlainText("查询出错(错误码:" + QString::number(host.error()) + "):" + host.errorString());
        return;
    }

    // 获取规范化后的主机名(可能与输入名称不同)
    ui->domainIp->appendPlainText("主机名称:" + host.hostName());

    // 获取该主机解析出的所有 IP 地址列表
    QList<QHostAddress> addresslist = host.addresses();
    ui->domainIp->appendPlainText("共解析到 " + QString::number(addresslist.count()) + " 个 IP 地址:");

    // 遍历每一个地址,输出更详细的信息
    for (int i = 0; i < addresslist.count(); i++) {
        QHostAddress address = addresslist.at(i);

        ui->domainIp->appendPlainText("  [" + QString::number(i + 1) + "] 协议类型:" + ProtocolTypeName(address.protocol()));
        ui->domainIp->appendPlainText("      IP 地址:" + address.toString());
        ui->domainIp->appendPlainText("      是否回环地址:" + QString(address.isLoopback() ? "是" : "否"));
        ui->domainIp->appendPlainText("      是否组播地址:" + QString(address.isMulticast() ? "是" : "否"));
        ui->domainIp->appendPlainText("      是否链路本地地址:" + QString(address.isLinkLocal() ? "是" : "否"));
        ui->domainIp->appendPlainText("      是否全局地址:" + QString(address.isGlobal() ? "是" : "否"));

        // scopeId(作用域 ID)通常只在 IPv6 下有意义
        if (address.protocol() == QAbstractSocket::IPv6Protocol) {
            ui->domainIp->appendPlainText("      IPv6 作用域 ID:" + address.scopeId());
        }
    }
}
// 槽函数:点击"清除数据信息"按钮,清空结果显示框
void GetDomainIps::on_clearBtn_clicked()
{
    ui->domainIp->clear();
}

// 槽函数:点击"查询域名或IP地址"按钮,发起 DNS 查询
void GetDomainIps::on_getDomainIp_clicked()
{
    // 从输入框获取待查询的主机名称
    QString strhostname = ui->inputUrl->text();
    ui->domainIp->appendPlainText("你所查询主机信息:" + strhostname);

    // 异步查询主机信息,查询完成后通过信号/槽回调 LookupHostInfofunc
    QHostInfo::lookupHost(strhostname, this, SLOT(LookupHostInfofunc(QHostInfo)));
}
相关推荐
黄焖鸡能干四碗1 小时前
信息安全保障方案(Word文件)
大数据·网络·人工智能·架构·区块链
我星期八休息1 小时前
网络编程—NAT、代理服务与内网穿透
linux·服务器·网络·网络协议
Quz2 小时前
QML TextArea 实战(下):大文本加载与性能优化
qt
RisunJan2 小时前
Linux命令-sysctl(运行时修改内核参数)
linux·网络·智能路由器
Quz2 小时前
QML TextArea 实战(中):Markdown 渲染与保持滚动
qt
A_humble_scholar2 小时前
Linux 网络基础(三)下的 HTTP 核心详解:从请求响应到状态管
linux·网络·http
Lucis__2 小时前
如何实现长连接通信机制?Websocket的最佳实践
网络·websocket·网络协议
JAVA面经实录9173 小时前
网络编程基础(Java Web/分布式前置·完整版)(十一)
java·前端·网络
記億揺晃着的那天14 小时前
NAS 内网域名访问为什么需要浏览器授权
网络·nginx·js·nas