QT 网络编程体系
Qt 网络编程基础
Qt 内置网络编程模块(Qt Network),基于 TCP/IP 协议提供客户端 / 服务端相关类:
- TCP 通信 :
QTcpSocket(客户端)、QTcpServer/QTcpServerSocket(服务端) - UDP 通信 :
QUdpSocket - 高级协议 :还提供 HTTP、FTP 等常用网络协议的高层封装类,如
QNetworkRequest、QNetworkAccessManager、QNetworkReply等
Qt Network 模块除了提供基础网络访问能力,还提供网络承载管理,以及基于 SSL/TLS 协议的安全网络通信类(如 QSslSocket、QSslServer)。
在开发中使用 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() |
接口标志(如 IsUp、IsRunning、CanBroadcast、IsLoopBack、CanMulticast 等) |
type() |
接口类型(Ethernet、Wifi、Loopback、Virtual 等) |
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)));
}
