Qt之QHostAddress 类的使用

本文介绍Qt中如何使用QHostAddress类获取和处理IPv4和IPv6地址,包括获取本机IP地址、过滤本地链路地址及私有IPV4地址的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在qt上做一些应用时,用到Qt获取本机IP地址的相关接口,看到网友写的一篇文章很有参考价值,故转载过来方便以后查找参考。

简述

QHostAddress类提供一个IP地址。

这个类提供一种独立于平台和协议的方式来保存IPv4和IPv6地址。

QHostAddress通常与QTcpSocket、QTcpServer、QUdpSocket一起使用,来连接到主机或建立一个服务器。

可以通过setAddress()来设置一个主机地址,使用toIPv4Address()、toIPv6Address()或toString()来检索主机地址。你可以通过protocol()来检查协议类型。

注意: QHostAddress不做DNS查询,而QHostInfo是有必要的。

这个类还支持通用的预定义地址:Null、LocalHost、LocalHostIPv6、Broadcast和Any。

常用接口

枚举 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 IPv4 any-address,相当于QHostAddress(“0.0.0.0”)。与该地址绑定的socket将只监听IPv4接口。
QHostAddress::AnyIPv6 5 IPv6 any-address,相当于QHostAddress(“::”)。与该地址绑定的socket将只监听IPv4接口。
QHostAddress::Any 4 双any-address栈,与该地址绑定的socket将侦听IPv4和IPv6接口。


bool isLoopback() const

如果地址是IPv6的环回地址,或任何IPv4的环回地址,则返回true。

bool isNull() const

如果主机地址为空(INADDR_ANY 或 in6addr_any),返回true。默认的构造函数创建一个空的地址,这个地址对于任何主机或接口是无效的。

QAbstractSocket::NetworkLayerProtocol protocol() const

返回主机地址的网络层协议。

QString scopeId() const

返回IPv6地址的范围ID。对于IPv4地址,如果该地址不包含范围ID,则返回一个空字符串。

IPv6的范围ID指定非全球IPv6地址范围的可达性,限制地址可以被使用的区域。所有IPv6地址与这种可达范围相关联。范围ID用于消除那些不能保证是全局唯一性的地址。

IPv6指定以下四个层次的可达性:

  • 节点本地(Node-local):地址仅用于和在相同的接口(例如:环回接口是”::1”)上的服务进行通信。
  • 链路-本地(Link-local):地址是本地网络接口(链接),每个IPv6接口上总有一个链路-本地地址在你的主机上。链路-本地地址(”fe80…”)由本地网络适配器的MAC地址生成,不保证是唯一的。
  • 本地-站点(Site-local):地址是本地的网站/私有网络(例如,公司内网)地址。本地-站点地址(”fec0…”)通常是由网站路由器分布,本地站点之外不能保证是唯一的。
  • 全球(Global):用于全球可路由地址,例如:Internet上的公共服务器。

    当使用链路-本地或本地-站点地址的IPv6连接,必须指定范围ID。对链路-本地地址来说,范围ID通常与接口名称(例如,”eth0”、”en1”)或数目(例如,”1”、”2”)相同​​。

quint32 toIPv4Address() const 
quint32 toIPv4Address(bool * ok) const

返回IPv4地址为一个数字。

例如,如果地址是127.0.0.1,返回值为2130706433(即0x7f000001)。

如果protocol()是IPv4Protocol,该值是有效的;如果是IPv6Protocol,并且IPv6地址是一个IPv4映射的地址,(RFC4291)。在这种情况下,ok将被设置为true;否则,它将被设置为false。

Q_IPV6ADDR toIPv6Address() const

返回的IPv6地址为Q_IPV6ADDR结构。该结构由16位无符号字符组成。

Q_IPV6ADDR addr = hostAddr.toIPv6Address();
// 地址包含16位无符号字符

for (int i = 0; i < 16; ++i) {
    // 处理 addr[i]
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果protocol()是IPv6Protocol,该值是有效的;如果是IPv4Protocol,返回地址将是IPv4地址映射的IPv6地址,(RFC4291)。

QString toString() const

返回地址为一个字符串。

例如,如果地址是IPv4地址127.0.0.1,返回的字符串为“127.0.0.1”。对于IPv6字符串格式将按照RFC5952建议。对于QHostAddress::Any,IPv4地址将返回(“0.0.0.0”)

使用

简单应用

构造一个QHostAddress,通过toString()来获取对应的IP地址:

QHostAddress address = QHostAddress(QHostAddress::LocalHost);
QString strIPAddress = address.toString();
 
  • 1
  • 2
  • 1
  • 2

显然,如上所述,IP地址为:“127.0.0.1”。

获取所有主机地址

QNetworkInterface类中提供了一个便利的静态函数allAddresses(),用于返回一个QHostAddress主机地址列表。

QList<QHostAddress> list = QNetworkInterface::allAddresses();
foreach (QHostAddress address, list) {
    // 主机地址为空
    if (address.isNull())
        continue;

    qDebug() << "********************";
    QAbstractSocket::NetworkLayerProtocol nProtocol = address.protocol();
    QString strScopeId = address.scopeId();
    QString strAddress = address.toString();
    bool bLoopback = address.isLoopback();

    // 如果是IPv4
    if (nProtocol == QAbstractSocket::IPv4Protocol) {
        bool bOk = false;
        quint32 nIPV4 = address.toIPv4Address(&bOk);
        if (bOk)
            qDebug() << "IPV4 : " << nIPV4;
    }
    // 如果是IPv6
    else if (nProtocol == QAbstractSocket::IPv6Protocol) {
        QStringList IPV6List("");
        Q_IPV6ADDR IPV6 = address.toIPv6Address();
        for (int i = 0; i < 16; ++i) {
            quint8 nC = IPV6[i];
            IPV6List << QString::number(nC);
        }
        qDebug() << "IPV6 : " << IPV6List.join(" ");
    }

    qDebug() << "Protocol : " << nProtocol;
    qDebug() << "ScopeId : " << strScopeId;
    qDebug() << "Address : " << strAddress;
    qDebug() << "IsLoopback  : " << bLoopback;
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

输出如下:


IPV6 : ” 254 128 0 0 0 0 0 0 85 12 171 25 251 72 1 201” 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv6Protocol) 
ScopeId : “15” 
Address : “fe80::550c:ab19:fb48:1c9%15” 
IsLoopback : false


IPV4 : 2851996105 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv4Protocol) 
ScopeId : “” 
Address : “169.254.1.201” 
IsLoopback : false


IPV6 : ” 254 128 0 0 0 0 0 0 208 134 133 102 96 101 137 84” 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv6Protocol) 
ScopeId : “11” 
Address : “fe80::d086:8566:6065:8954%11” 
IsLoopback : false


IPV4 : 2886861989 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv4Protocol) 
ScopeId : “” 
Address : “172.18.4.165” 
IsLoopback : false


IPV6 : ” 254 128 0 0 0 0 0 0 248 100 169 98 114 25 249 142” 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv6Protocol) 
ScopeId : “16” 
Address : “fe80::f864:a962:7219:f98e%16” 
IsLoopback : false


IPV4 : 3232239873 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv4Protocol) 
ScopeId : “” 
Address : “192.168.17.1” 
IsLoopback : false


IPV6 : ” 254 128 0 0 0 0 0 0 129 105 105 31 20 142 211 203” 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv6Protocol) 
ScopeId : “17” 
Address : “fe80::8169:691f:148e:d3cb%17” 
IsLoopback : false


IPV4 : 3232281089 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv4Protocol) 
ScopeId : “” 
Address : “192.168.178.1” 
IsLoopback : false


IPV6 : ” 254 128 0 0 0 0 0 0 89 150 39 163 131 181 42 231” 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv6Protocol) 
ScopeId : “18” 
Address : “fe80::5996:27a3:83b5:2ae7%18” 
IsLoopback : false


IPV4 : 3232249857 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv4Protocol) 
ScopeId : “” 
Address : “192.168.56.1” 
IsLoopback : false


IPV6 : ” 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1” 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv6Protocol) 
ScopeId : “” 
Address : “::1” 
IsLoopback : true


IPV4 : 2130706433 
Protocol : QAbstractSocket::NetworkLayerProtocol(IPv4Protocol) 
ScopeId : “” 
Address : “127.0.0.1” 
IsLoopback : true

我们可以获取到很多地址,有可能包含:本例链路地址、私有的IPV4地址等,但是在应用过程中大部分需要进行过滤。

过滤

  • 本地链路地址

本地链路地址范围:169.254.1.0 - 169.254.254.255 
参考:http://en.wikipedia.org/wiki/Private_network

bool isLinkLocalAddress(QHostAddress addr){
    quint32 nIPv4 = addr.toIPv4Address();
    quint32 nMinRange = QHostAddress("169.254.1.0").toIPv4Address();
    quint32 nMaxRange = QHostAddress("169.254.254.255").toIPv4Address();
    if ((nIPv4 >= nMinRange) && (nIPv4 <= nMaxRange)) {
        return true;
    } else {
        return false;
    }
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 私有IPV4地址

私有IPV4地址范围:

  1. 10.0.0.0 - 10.255.255.255
  2. 172.16.0.0 - 172.31.255.255
  3. 192.168.0.0 - 192.168.255.255

参考:http://en.wikipedia.org/wiki/Private_network

bool isLocalIP(QHostAddress addr){
    quint32 nIPv4 = addr.toIPv4Address();
    quint32 nMinRange1 = QHostAddress("10.0.0.0").toIPv4Address();
    quint32 nMaxRange1 = QHostAddress("10.255.255.255").toIPv4Address();

    quint32 nMinRange2 = QHostAddress("172.16.0.0").toIPv4Address();
    quint32 nMaxRange2 = QHostAddress("172.31.255.255").toIPv4Address();

    quint32 nMinRange3 = QHostAddress("192.168.0.0").toIPv4Address();
    quint32 nMaxRange3 = QHostAddress("192.168.255.255").toIPv4Address();

    if ((nIPv4 >= nMinRange1 && nIPv4 <= nMaxRange1)
            || (nIPv4 >= nMinRange2 && nIPv4 <= nMaxRange2)
            || (nIPv4 >= nMinRange3 && nIPv4 <= nMaxRange3)) {
        return true;
    } else {
        return false;
    }
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

更多参考


<think>我们正在讨论Qt中的QHostAddressQHostAddress用于处理IP地址(IPv4和IPv6)。以下是一个关于QHostAddress的详细说明和示例。###QHostAddress概述`QHostAddress`是Qt中用于表示一个IP地址的,支持IPv4和IPv6地址。它可以用于网络编程中,如QTcpSocket、QUdpSocket等。####主要功能1.**构造IP地址**:可以从字符串、数值等构造。2.**地址型判断**:如判断是否为IPv4、IPv6、空地址等。3.**转换功能**:转换为字符串或数值(IPv4地址)。4.**特殊地址**:如本地主机地址(127.0.0.1)、广播地址等。###构造函数示例```cpp//默认构造,空地址QHostAddressaddress1;//从字符串构造(IPv4)QHostAddressaddress2("192.168.1.1");//从字符串构造(IPv6)QHostAddressaddress3("2001:0db8:85a3:0000:0000:8a2e:0370:7334");//使用IPv4地址的数值构造QHostAddressaddress4(0x7F000001);//127.0.0.1```###常用方法-`setAddress(constQString&address)`:设置字符串表示的IP地址。-`toString()`:将IP地址转换为字符串。-`protocol()`:返回协议版本(`QAbstractSocket::IPv4Protocol`或`QAbstractSocket::IPv6Protocol`)。-`toIPv4Address()`:将IPv4地址转换为32位无符号整数(如果地址是IPv4)。-`isNull()`:判断地址是否为空。-`clear()`:清空地址。###示例1:将字符串转换为IP地址```cppQStringipString="192.168.1.100";QHostAddressaddr;if(addr.setAddress(ipString)){qDebug()<< "Theaddressisvalid:"<< addr.toString();}else{qDebug()<< "Invalidaddress";}```###示例2:本地主机地址```cppQHostAddresslocalhost=QHostAddress::LocalHost;//127.0.0.1(IPv4)qDebug()<< "LocalHostIPv4:"<< localhost.toString();QHostAddresslocalhost6=QHostAddress::LocalHostIPv6;//::1(IPv6)qDebug()<< "LocalHostIPv6:"<< localhost6.toString();```###示例3:与QUdpSocket结合使用(基于引用[1]的UDP示例)修改引用[1]中的发送端代码,使其更灵活地使用QHostAddress:```cpp#include<QCoreApplication>#include<QUdpSocket>#include<QDebug>#include<QHostAddress>intmain(intargc,char*argv[]){QCoreApplicationa(argc,argv);//创建UDP套接字QUdpSocketudpSocket;//目标地址和端口QHostAddressdestAddress;if(!destAddress.setAddress("192.168.1.100")){qDebug()<< "Invalidaddress!";return-1;}quint16destPort=54321;//发送数据QByteArraydata="Hello,UDPfromsender!";qint64bytesSent=udpSocket.writeDatagram(data,destAddress,destPort);if(bytesSent==-1){qDebug()<< "Failedtosenddata:"<< udpSocket.errorString();}else{qDebug()<< "Datasentsuccessfullyto"<< destAddress.toString()<< ":"<< destPort;}returna.exec();}```###示例4:接收端处理数据报并获取发送方地址UDP接收端使用`QUdpSocket`接收数据,并获取发送方的地址:```cpp#include<QCoreApplication>#include<QUdpSocket>#include<QDebug>#include<QHostAddress>intmain(intargc,char*argv[]){QCoreApplicationa(argc,argv);QUdpSocketudpSocket;quint16port=54321;//绑定本机端口//绑定端口if(!udpSocket.bind(port)){qDebug()<< "Bindfailed:"<< udpSocket.errorString();return-1;}//连接readyRead信号处理接收QObject::connect(&udpSocket,&QUdpSocket::readyRead,[&](){while(udpSocket.hasPendingDatagrams()){QByteArraydatagram;datagram.resize(udpSocket.pendingDatagramSize());QHostAddresssenderAddr;quint16senderPort;//读取数据报,同时获取发送方的地址和端口qint64bytesRead=udpSocket.readDatagram(datagram.data(),datagram.size(),&senderAddr,&senderPort);if(bytesRead==-1){qDebug()<< "Errorreadingdatagram:"<< udpSocket.errorString();continue;}qDebug()<< "Receivedfrom:"<< senderAddr.toString()<< ":"<< senderPort<< "data:"<< datagram;}});returna.exec();}```###特殊地址和广播-广播地址:IPv4的广播地址通常是`255.255.255.255`,也可以使用特定子网的广播地址(如`192.168.1.255`)。发送广播数据报需要先设置套接字选项:```cpp//在发送广播之前设置udpSocket.setSocketOption(QAbstractSocket::BroadcastSocketOption,1);```然后使用广播地址发送。-多播:使用`QHostAddress`表示多播组地址(如IPv4的组播地址范围是224.0.0.0到239.255.255.255)。###注意事项1.使用字符串构造时,确保字符串是有效的IP地址格式,否则`setAddress`会返回false。2.IPv6地址的字符串表示需要注意压缩格式(例如可以用`::`省略连续的0)。3.在跨平台时,IPv6的支持需要测试(尽管Qt在主流平台都支持)。###相关问题§§相关问题§§1.如何用QTcpServer和QTcpSocket建立TCP连接?2.QUdpSocket如何实现组播(多播)?3.如何获取本机的所有IP地址?4.如何用QHostAddress和QNetworkInterface管理网络接口?</think> ### QT QHostAddress 使用指南 QHostAddressQt 网络编程中处理 IP 地址的核心,支持 IPv4 和 IPv6 地址格式。以下从基础到进阶的完整说明: #### 一、核心功能概述 1. **地址型支持**:同时处理 IPv4(如 `192.168.1.1`)和 IPv6(如 `2001:db8::1`) 2. **特殊地址常量**: ```cpp QHostAddress::LocalHost; // IPv4: 127.0.0.1 QHostAddress::LocalHostIPv6; // IPv6: ::1 QHostAddress::Broadcast; // 255.255.255.255 QHostAddress::Any; // 0.0.0.0 ``` 3. **协议标识**: ```cpp QAbstractSocket::IPv4Protocol QAbstractSocket::IPv6Protocol ``` #### 二、基础使用方法 ##### 1. 地址构造与转换 ```cpp // 从字符串构造 QHostAddress ipv4Addr("192.168.1.100"); QHostAddress ipv6Addr("2001:db8:85a3::8a2e:370:7334"); // 从数值构造 (仅IPv4) quint32 numericIP = 0xC0A80164; // 192.168.1.100 QHostAddress addrFromNum(numericIP); // 转换为字符串 qDebug() << ipv4Addr.toString(); // "192.168.1.100" ``` ##### 2. 地址验证 ```cpp QString input = "192.168.1.256"; QHostAddress testAddr; if(testAddr.setAddress(input)) { qDebug() << "Valid IP:" << testAddr.toString(); } else { qDebug() << "Invalid IP Address"; } ``` #### 三、实战应用示例 ##### 示例1:UDP 通信 (基于引用[1]) ```cpp // UDP发送端 QUdpSocket udpSocket; QHostAddress destAddr("192.168.1.100"); QByteArray data = "Hello from Qt!"; // 验证地址有效性 if(destAddr.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) { qWarning() << "Invalid destination address"; return; } udpSocket.writeDatagram(data, destAddr, 54321); ``` ##### 示例2:TCP 服务器绑定 ```cpp // TCP服务器监听 QTcpServer server; QHostAddress serverAddr = QHostAddress::Any; // 监听所有接口 if(server.listen(serverAddr, 8080)) { qDebug() << "Server listening on port 8080"; } else { qDebug() << "Error:" << server.errorString(); } ``` ##### 示例3:IP地址比较与筛选 ```cpp QList<QHostAddress> addresses { QHostAddress("192.168.1.1"), QHostAddress("2001:db8::1"), QHostAddress("10.0.0.1") }; // 过滤IPv4地址 for (const auto &addr : addresses) { if (addr.protocol() == QAbstractSocket::IPv4Protocol) { qDebug() << "IPv4 Address:" << addr.toString(); } } ``` #### 四、高级技巧 1. **子网匹配**: ```cpp QHostAddress clientAddr("192.168.1.50"); QPair<QHostAddress, int> subnet = QHostAddress::parseSubnet("192.168.1.0/24"); if (clientAddr.isInSubnet(subnet)) { qDebug() << "Client in local subnet"; } ``` 2. **特殊地址检测**: ```cpp addr.isLoopback(); // 是否为回环地址 addr.isMulticast(); // 是否为组播地址 addr.isNull(); // 是否为空地址 ``` 3. **协议转换兼容**: ```cpp // IPv4转IPv6兼容格式 if (addr.protocol() == QAbstractSocket::IPv4Protocol) { QHostAddress ipv6CompatibleAddr("::ffff:" + addr.toString()); } ``` #### 五、常见问题解决 1. **无效地址处理**: ```cpp // 带错误处理的地址设置 if (!addr.setAddress(userInput)) { qDebug() << "Invalid IP:" << userInput; addr = QHostAddress::Null; // 设为空地址 } ``` 2. **跨协议比较**: ```cpp QHostAddress addr1("192.168.1.1"); QHostAddress addr2("::ffff:192.168.1.1"); // 使用QHostAddress::isEqual()替代==操作符 if (addr1.isEqual(addr2, QHostAddress::ConvertV4MappedToIPv4)) { qDebug() << "Equivalent IPv4 addresses"; } ``` ### 最佳实践建议 1. **网络接口绑定**:在多网卡环境中使用 `QNetworkInterface` 获取有效 IP 2. **地址重用**:创建 `QHostAddress` 对象后尽量复用,避免重复解析 3. **安全验证**:外部输入IP必须经过 `setAddress()` 验证
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值