简述:
Qt 中提供了几个用于获取主机网络信息的类,包括QHostInfo、QHostAddress、QNetworkInterface以及QNetworkAddressEntry。
通过这几个类获得本机的主机名、IP地址和硬件地址等网络信息。
QHostInfo 类:查询与特定主机名相关联的主机的IP地址,或者与一个IP地址相关联的主机名。
QHostAddress 类:提供一个IP地址,可提供独立于平台和协议的方式来保存 IPv4和IPv6 地址。
QNetworkInterface 类:负责提供主机IP地址和网络接口的列表,表示了当前程序正在运行时与主机绑定的一个网络接口。
QNetworkAddressEntry 类:存储了一个网络接口所支持的一个IP地址,同时还有与之相关的子网掩码和广播地址。
系统:Windows 7
Qt 环境: qt-opensource-windows-x86-mingw530-5.7.0.exe
1 > 修改工程文件 .pro
本机网络信息是属于网络模块。获取本机网络信息,那就要使用Qt 提供的网络模块 QtNetwork,即在工程文件 .pro 中加入:
QT += network
2 > #include 头文件 .h
只需要 #include 两个头文件即可
#include
#include
3 > 范例
void NetworkInformation::getHostInformation() { /***********************************************************/ //QHostInfo 提供一系列有关网络信息的静态函数,可获取主机名、IP地址 QString localHostName = QHostInfo::localHostName(); // 获取本机主机名 qDebug() << "主机名: " << localHostName; qDebug() << endl; /***********************************************************/ //根据主机名获取相关主机信息,包括IP地址。 QHostInfo hostInfo = QHostInfo::fromName(localHostName); QList
addrList = hostInfo.addresses(); // 获取本主机上的IP地址列表 qDebug() << "本主机上的IP地址列表,总计: " << addrList.count() ; /***********************************************************/ foreach (QHostAddress var, addrList) { qDebug() << var.toString(); //本机IP地址列表 } qDebug() << endl; /***********************************************************/ if(!addrList.isEmpty()) //获得的主机IP地址列表可能为空。 { // 在不为空情况下使用第一个IP地址,可能IPv6,也可能IPv4 qDebug() << "first ip addr:" << addrList.first().toString(); } qDebug() << endl; /***********************************************************/ QString ipAddress; //QList addrList = QNetworkInterface::allAddresses(); //仅仅获取IP地址列表 for (int i = 0; i < addrList.size(); ++i) { if (addrList.at(i) != QHostAddress::LocalHost && addrList.at(i).toIPv4Address()) { //是IPv4地址且非 QHostAddress::LocalHost ipAddress = addrList.at(i).toString(); qDebug() << "first ipv4 addr:" << ipAddress;// 在不为空情况下使用第一个IPv4地址 break; } } qDebug() << endl; /***********************************************************/ // 获取本机的网络接口列表 QList ifaceList = QNetworkInterface::allInterfaces(); for (int i = 0; i < ifaceList.count(); i++){ QNetworkInterface var = ifaceList.at(i); qDebug() << tr("########## 设备%1 ############").arg(i); qDebug() << tr("接口名称:") << var.humanReadableName(); qDebug() << tr("设备名称:") << var.name(); qDebug() << tr("硬件地址:") << var.hardwareAddress(); /***********************************************************/ // 读取一个IP地址的关联信息列表 QList entryList = var.addressEntries(); //qDebug() << "IP地址的关联信息列表: "; //foreach(QNetworkAddressEntry entry, entryList){ //qDebug() << "IP: " << entry.ip().toString(); //qDebug() << "子网掩码:" << entry.netmask().toString(); //qDebug() << "广播地址:" << entry.broadcast().toString(); //} /***********************************************************/ // 读取一个IPv4地址的关联信息列表 //qDebug() << "IPv4地址的关联信息列表: "; foreach(QNetworkAddressEntry ipv4entry, entryList){ if (ipv4entry.ip().toIPv4Address()) { qDebug() << "IP: " << ipv4entry.ip().toString(); qDebug() << "子网掩码:" << ipv4entry.netmask().toString(); qDebug() << "广播地址:" << ipv4entry.broadcast().toString(); } } } /***********************************************************/ }
输出:
1 > QHostInfo类 :查询与特定主机名相关联的主机的IP地址,或者与一个IP地址相关联的主机名。
2 > 有两种查询方式:
A. 异步方式,找到主机就发射信号。
此方式调用的 lookupHost() ,此函数有3个参数,分别是主机名或IP地址、接收对象和接收槽函数,并且返回一个查询ID。
若要中止查询,则可调用abortHostLookup() 函数,参数是查询ID。
static int lookupHost(const QString &name, QObject *receiver, const char *member);//异步方式查询 static void abortHostLookup(int lookupId); //中止查询
若查询成功,则调用接收槽函数。查询结果被存储到 QHostInfo对象中;可使用以下方式查看查询结果:
QString hostName() const; //获取查询的主机名 QList
addresses() const; //获取主机的IP地址列表 HostInfoError error() const; //返回错误的类型 QString errorString() const; //返回查询错误描述
例如:
NetworkInformation::NetworkInformation(QWidget *parent) : QWidget(parent) { QHostInfo::lookupHost("www.baidu.com", this, SLOT(printResult(QHostInfo))); } void NetworkInformation::printResult(QHostInfo result) { qDebug() << result.hostName(); //获取查询的主机名 QList
addrList = result.addresses(); //获取主机的IP地址列表 if (!addrList.isEmpty()) { for (int i = 0; i < addrList.size(); i++) { qDebug() << addrList.at(i); } } }
QHostInfo::HostInfoError 常量 值 描述 QHostInfo::NoError 0 查找成功 QHostInfo::HostNotFound 1 没有发现主机对应的IP地址 QHostInfo::UnknownError 2 未知错误
B. 阻塞方式,调用的是 QHostInfo::fromName() 函数,查询给定主机名对应的IP地址。此函数查询期间将阻塞,这意味着程序执行期间将挂起直到返回查询结果。
返回的查询结果存储在 QHostInfo 对象中。
static QHostInfo fromName(const QString &name); //阻塞方式查询
例如:
NetworkInformation::NetworkInformation(QWidget *parent) : QWidget(parent) { QHostInfo info = QHostInfo::fromName("www.baidu.com"); //阻塞方式查询 qDebug() << info.addresses(); }
1 > QHostAddress 类:提供一个IP地址,可提供独立于平台和协议的方式来保存 IPv4 和 IPv6 地址,故可用于地址过滤。
QHostAddress 通常与QTcpSocket、QTcpServer、QUdpSocket 一起使用,来连接到主机或建立一个服务器 。
注意: QHostAddress不做DNS查询,而QHostInfo是有必要的。
这个类还支持通用的预定义地址:Null、LocalHost、LocalHostIPv6、Broadcast和Any。
//setAddress()设置主机地址 void setAddress(quint32 ip4Addr); void setAddress(quint8 *ip6Addr); // ### Qt 6: remove me void setAddress(const quint8 *ip6Addr); void setAddress(const Q_IPV6ADDR &ip6Addr); void setAddress(const sockaddr *address); bool setAddress(const QString &address); //protocol()检查协议类型 QAbstractSocket::NetworkLayerProtocol protocol() const; //toIPv4Address()、toIPv6Address()或toString()来检索主机地址 quint32 toIPv4Address() const; // ### Qt6: merge with next overload quint32 toIPv4Address(bool *ok) const; Q_IPV6ADDR toIPv6Address() const; QString toString() const;
2 > QHostAddress:: SpecialAddress
QHostAddress::SpecialAddress 常量 值 描述 QHostAddress::Null 0 空地址对象,相当于QHostAddress() QHostAddress::LocalHost 2 IPv4本地主机地址,相当于QHostAddress(“127.0.0.1”) QHostAddress::LocalHostIPv6 3 IPv6本地主机地址,相当于 QHostAddress(“::1”) QHostAddress::Broadcast 1 Pv4广播地址,相当于QHostAddress(“255.255.255.255”) QHostAddress::AnyIPv4 6 相当于QHostAddress(“0.0.0.0”)。与该地址绑定的socket将只监听IPv4接口 QHostAddress::AnyIPv6 5 相当于QHostAddress(“::”)。与该地址绑定的socket将只监听IPv6接口 QHostAddress::Any 4 双any-address栈,与该地址绑定的socket将侦听IPv4和IPv6接口
3 > 常用函数
//返回主机地址的网络层协议 QAbstractSocket::NetworkLayerProtocol protocol() const; //返回IPv4地址为一个数字 //例如地址是127.0.0.1,返回值为2130706433(即0x7f000001) quint32 toIPv4Address() const; // ### Qt6: merge with next overload quint32 toIPv4Address(bool *ok) const; //返回的IPv6地址为Q_IPV6ADDR结构。该结构由16位无符号字符组成 Q_IPV6ADDR toIPv6Address() const; //返回地址为一个字符串 //例如地址是IPv4地址127.0.0.1,返回的字符串为“127.0.0.1” QString toString() const; //返回IPv6地址的范围ID。对于IPv4地址,如果该地址不包含范围ID,则返回一个空字符串 QString scopeId() const; //若主机地址为空(INADDR_ANY 或 in6addr_any),返回true bool isNull() const; //若地址是IPv6的环回地址,或任何IPv4的环回地址,则返回true bool isLoopback() const;
4 > IPv6 的范围 ID
IPv6 的范围 ID 指定非全球 IPv6 地址范围的可达性,限制地址可以被使用的区域。
所有 IPv6 地址与这种可达范围相关联。范围 ID 用于消除那些不能保证是全局唯一性的地址。
IPv6 指定以下四个层次的可达性:
A . 节点本地(Node-local):地址仅用于和在相同的接口(例如:环回接口是“::1”)上的服务进行通信。
B . 链路-本地(Link-local):地址是本地网络接口(链接),每个IPv6接口上总有一个链路-本地地址在你的主机上。链路-本地地址(“fe80…”)由本地网络适配器的MAC地址生成,不保证是唯一的。
C . 本地-站点(Site-local):地址是本地的网站/私有网络(例如,公司内网)地址。本地-站点地址(“fec0…”)通常是由网站路由器分布,本地站点之外不能保证是唯一的。
D . 全球(Global):用于全球可路由地址,例如:Internet上的公共服务器。
当使用链路-本地或本地-站点地址的IPv6连接,必须指定范围ID。对链路-本地地址来说,范围ID通常与接口名称(例如,“eth0”、“en1”)或数目(例如,“1”、“2”)相同
1 > QNetworkInterface 类:负责提供主机IP地址和网络接口的列表,表示了当前程序正在运行时与主机绑定的一个网络接口。
每个网络接口可能包含0个或者多个IP地址,每个IP地址都可选择性地与一个子网掩码和(或)一个广播地址相关联。
只有 IPv4 地址可以保证在所有平台上都能列举所有这些特性,而 IPv6 地址,目前只支持Windows XP及相关版本、Linux、MacOS 和 BSDs 可列举所有。
2 > 常用函数
/********************************************* * 返回网络接口的名称; * 在Unix系统中,这是一个包含接口的类型和任选的序列号的字符串,例如:“eth0”、“lo”或者“pcn0”; * 在Windows中,这是一个内部ID,用户不能更改 **********************************************/ QString name() const; /********************************************* * 如果名称可确定,在Windows上,返回网络接口的人类可读的名称,例如:“本地连接”; * 如果不能,这个函数返回值与name()相同。 * 用户可以在Windows控制面板中修改人类可读的名称,因此它可以在程序的执行过程中变化的名称。 * 在Unix上,此函数目前返回值总是和name()相同,因为Unix系统不存储人类可读的名称的配置。 **********************************************/ QString humanReadableName() const; //返回与此网络接口关联的标志 InterfaceFlags flags() const; //返回网络接口的底层硬件地址。如以太网接口,表示MAC地址的字符串,用冒号分隔。其他接口类型可能使用其他类型的硬件地址 QString hardwareAddress() const; //返回IP地址列表及其相关的网络掩码和广播地址 QList
addressEntries() const; //返回的主机上找到的所有的网络接口的列表;在失败情况下,它会返回一个空列表 static QList allInterfaces(); //仅返回IP地址列表 static QList allAddresses();
3 > 网络接口相关的标识
QNetworkInterface::InterfaceFlags 常量 值 描述 QNetworkInterface::IsUp 0x1 网络接口处于活动状态 QNetworkInterface::IsRunning 0x2 网络接口已分配资源 QNetworkInterface::CanBroadcast 0x4 网络接口工作在广播模式 QNetworkInterface::IsLoopBack 0x8 网络接口是环回接口:也就是说,它是一个虚拟接口,其目的是主机本身 QNetworkInterface::IsPointToPoint 0x10 网络接口是一个点对点接口:也就是说,有一个,单一的其他地址可以直接由它到达 QNetworkInterface::CanMulticast 0x20 网络接口支持多播
注意:一个网络接口不能既是broadcast-based又是point-to-point。
1 > QNetworkAddressEntry 类:存储了一个网络接口所支持的一个IP地址,同时还有与之相关的子网掩码和广播地址。
每个网络接口可以包含0个或多个IP地址,这些IP地址可以分别关联一个子网掩码和(或)一个广播地址(取决于操作系统的支持)
2 > 常用函数
//返回一个网络接口中存在的IPv4或IPv6地址; QHostAddress ip() const; /************************************** *返回与IP地址相关联的子网掩码。 * 子网掩码是一个IP地址的形式表示,如255.255.0.0。 * 对于IPv6地址,前缀长度被转换成一个地址,其中设置为1的位数等于前缀长度。 * 前缀长度为64位(最常见的值),子网掩码将被表示为一个地址为FFFF:FFFF:FFFF:FFFF::的QHostAddress ****************************************/ QHostAddress netmask() const; /************************************** *返回此IP地址的前缀长度。前缀长度和子网掩码中设置为1的位数相匹配。 * IPv4地址的值在0 - 32之间。IPv6地址的值在0 - 128之间,是表示数据的首选。 * 如果前缀长度不能确定,则返回0(即:netmask()返回一个空的QHostAddress()); * 例如:255.255.240.0 转换为二进制:11111111 11111111 11110000 00000000, * 那么前缀长度就是8*2 + 4 = 20(1的个数) ****************************************/ int prefixLength() const; //返回IPv4地址和子网掩码相关联的广播地址; //对于IPv6地址来说,返回的总是空,因为广播的概念已被抛弃,为了系统支持多播; QHostAddress broadcast() const;
3 > 例子
QList
list = QNetworkInterface::allInterfaces(); foreach (QNetworkInterface netInterface, list) { QList entryList = netInterface.addressEntries(); foreach(QNetworkAddressEntry entry, entryList) { // 遍历每一个IP地址 qDebug() << "********************"; qDebug() << "IP Address:" << entry.ip().toString(); // IP地址 qDebug() << "Netmask:" << entry.netmask().toString(); // 子网掩码 qDebug() << "Broadcast:" << entry.broadcast().toString(); // 广播地址 qDebug() << "Prefix Length:" << entry.prefixLength(); // 前缀长度 } }