Qt之QHostAddress 類的使用

最近在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

更多參考


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章