Qt 网络模块为我们提供了编写TCP/IP客户端和服务器的类。它提供了较低级别的类,例如代表低级网络概念的 QTcpSocket,QTcpServer 和 QUdpSocket,以及诸如 QNetworkRequest, QNetworkReply 和 QNetworkAccessManager 之类的高级类来执行使用通用协议的网络操作。它 还提供了诸如QNetworkConfiguration,QNetworkConfigurationManager和QNetworkSession等类, 实现承载管理。
想要在程序中使用 Qt 网络模块,我们需要在 pro 项目配置文件里增加下面的一条语句。
QT += network
获取本机的网络信息
为什么先获取本机网络信息呢?在建立网络通信之前我们至少得获取对方的 IP 地址。在网络应用中,经常需要用到本机的主机名、IP 地址、MAC 地址等网络信息,通常通在 Windows 通过调出命令行 cmd 窗口输入ipconfig或者在 Linux 系统中使用ifconfig命令就可以查看相关信息了,在这里我们利用Qt做出一个可以查询的界面和功能出来,为了后面的网络编程打下一个简单的基础。
Qt 提供了 QHostInfo 和 QNetworkInterface 类可以用于此类信息查询。更多关于 QHostInfo 和 QNetworkInterface 的相关函数可以在 Qt 的帮助文档中找到。下面我们写代码时会使用到相关的函数,有清楚的注释。
应用实例
项目目的:了解如何通过QHostInfo和QNetworkInterface类获取本地网络所有接口的信息。
项目名称:networkhostinfo ,获取本机网络接口信息。
获取本机的网络接口信息,打印在文本浏览框上,点击按钮可直接获取,为了清楚看见是重新获取的过程,本例点击获取本机信息按钮后延时 1s 去刷新获取的信息。点击另一个清空文本信息按钮可以清空文本浏览框上的文本内容。
项目文件 networkhostinfo.pro 文件第一行添加的代码部分如下。
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
在头文件“mainwindow.h”具体代码如下。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QTextBrowser>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTimer>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
/* 点击获取和清空文本按钮 */
QPushButton *pushButton[2];
/* 文本浏览框用于显示本机的信息 */
QTextBrowser *textBrowser;
/* 水平Widget容器和垂直Widget容器*/
QWidget *hWidget;
QWidget *vWidget;
/* 水平布局和垂直布局 */
QHBoxLayout *hBoxLayout;
QVBoxLayout *vBoxLayout;
/* 定时器 */
QTimer *timer;
/* 获取本机的网络的信息,返回类型是QString */
QString getHostInfo();
private slots:
/* 定时器槽函数,点击按钮后定时触发 */
void timerTimeOut();
/* 显示本机信息 */
void showHostInfo();
/* 启动定时器 */
void timerStart();
/* 清空textBrowser的信息 */
void clearHostInfo();
};
#endif // MAINWINDOW_H
头文件里主要是声明两个按钮和一个文本浏览框。另外还有一个定时器,声明一些槽函数, 比较简单。 在源文件“mainwindow.cpp”具体代码如下。
#include "mainwindow.h"
#include <QNetworkInterface>
#include <QHostInfo>
#include <QThread>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
/* 设置位置与大小 */
this->setGeometry(0, 0, 800, 480);
/* 点击获取本地信息按钮和清空文本按钮 */
pushButton[0] = new QPushButton();
pushButton[1] = new QPushButton();
pushButton[0]->setText("获取本机信息");
pushButton[1]->setText("清空文本信息");
/* 按钮的大小根据文本自适应,
* 注意setSizePolicy需要在布局中使用 */
pushButton[0]->setSizePolicy(QSizePolicy::Fixed,
QSizePolicy::Fixed);
pushButton[1]->setSizePolicy(QSizePolicy::Fixed,
QSizePolicy::Fixed);
/* 水平Widget和垂直Widget用于添加布局 */
hWidget = new QWidget();
vWidget = new QWidget();
/* 水平布局和垂直布局 */
hBoxLayout = new QHBoxLayout();
vBoxLayout = new QVBoxLayout();
/* 文本浏览框 */
textBrowser = new QTextBrowser();
/* 添加到水平布局 */
hBoxLayout->addWidget(pushButton[0]);
hBoxLayout->addWidget(pushButton[1]);
/* 将水平布局设置为hWidget的布局 */
hWidget->setLayout(hBoxLayout);
/* 将文本浏览框和hWidget添加到垂直布局 */
vBoxLayout->addWidget(textBrowser);
vBoxLayout->addWidget(hWidget);
/* 将垂直布局设置为vWidget的布局 */
vWidget->setLayout(vBoxLayout);
/* 设置vWidget为中心部件 */
setCentralWidget(vWidget);
/* 定时器初始化 */
timer = new QTimer();
/* 信号槽连接 */
connect(pushButton[0], SIGNAL(clicked()),
this, SLOT(timerStart()));
connect(pushButton[1], SIGNAL(clicked()),
this, SLOT(clearHostInfo()));
connect(timer, SIGNAL(timeout()),
this, SLOT(timerTimeOut()));
}
MainWindow::~MainWindow()
{
}
void MainWindow::timerStart()
{
/* 清空文本 */
textBrowser->clear();
/* 定时1s */
timer->start(1000);
}
void MainWindow::timerTimeOut()
{
/* 显示本机信息 */
showHostInfo();
/* 停止定时器 */
timer->stop();
}
QString MainWindow::getHostInfo()
{
/* 通过QHostInfo的localHostName函数获取主机名称 */
QString str = "主机名称:" + QHostInfo::localHostName() + "\n";
/* 获取所有的网络接口,
* QNetworkInterface类提供主机的IP地址和网络接口的列表 */
QList<QNetworkInterface> list
= QNetworkInterface::allInterfaces();
/* 遍历list */
foreach (QNetworkInterface interface, list) {
str+= "网卡设备:" + interface.name() + "\n";
str+= "MAC地址:" + interface.hardwareAddress() + "\n";
/* QNetworkAddressEntry类存储IP地址子网掩码和广播地址 */
QList<QNetworkAddressEntry> entryList
= interface.addressEntries();
/* 遍历entryList */
foreach (QNetworkAddressEntry entry, entryList) {
/* 过滤IPv6地址,只留下IPv4 */
if (entry.ip().protocol() ==
QAbstractSocket::IPv4Protocol) {
str+= "IP 地址:" + entry.ip().toString() + "\n";
str+= "子网掩码:" + entry.netmask().toString() + "\n";
str+= "广播地址:" + entry.broadcast().toString() + "\n\n";
}
}
}
/* 返回网络信息 */
return str;
}
void MainWindow::showHostInfo()
{
/* 获取本机信息后显示到textBrowser */
textBrowser->insertPlainText(getHostInfo());
}
void MainWindow::clearHostInfo()
{
/* 判断textBrowser是否为空,如果不为空则清空文本 */
if (!textBrowser->toPlainText().isEmpty())
/* 清空文本 */
textBrowser->clear();
}
首先,通过 QHostInfo 的 localHostName 函数获取主机名称。
然后通过 QNetworkInterface::allInterfaces()获取网络接口列表 list 类存储 IP 地址子网掩码和广播地址。如果我们用 qDebug()函数打印出 list,可以发现获取了所有的网络信息。 而我们要提取网络里面的网络信息使用 QNetworkAddressEntry。
再用QNetworkAddressEntry 从 interface 接口里使用函数 addressEntries(), 获取所有的条目。就可以使用 QNetworkAddressEntry 的对象 entry 获取 IP 地址子网掩码和广播地址。
因为获取的entries在一个 QNetworkInterface下可能有两个IP,分别是ipv4 和 ipv6。这里使用ip().protocol()来判断协议的类型,只留下 ipv4 类型的信息。筛选信息在我们写程序常常需要的。
程序运行效果
点击获取本机信息,在文本浏览框内就打印出本机的网络信息(包括了主机名,网卡名, ip 地址等)。这里因为过滤掉了 IPv6 的信息。通常一个网卡有两个 ip 地址,一个是 ipv4,另一 个是 ipv6 的地址。下面的网卡设备 lo,是本地回环网卡。另一个 ens33 是虚拟机的网卡,由 VMware 虚拟出来的。点击清空文本信息会清空文本浏览框里的网络信息。