zoukankan      html  css  js  c++  java
  • Qt获取ip地址

    Qt 获取本机IP地址

    最先想到的方案

    QString get_local_ip()
    {
        QHostInfo info = QHostInfo::fromName(QHostInfo::localHostName());
    
        // 找出一个IPv4地址即返回
        foreach(QHostAddress address,info.addresses())
        {
            if(address.protocol() == QAbstractSocket::IPv4Protocol)
            {
                return address.toString();
            }
        }
    
        return "0.0.0.0";
    }

    如果机器上仅有一块以太网卡,且没有安装虚拟机,这段代码似乎可以完成任务。不幸的是,机器上还有无线网卡,VMware和VirtualBox这两个虚拟机软件。因此要过滤掉虚拟网卡的信息。

    修改后的方案

    /**
     * @brief 检测当前网卡是否是虚拟网卡(VMware/VirtualBox)或回环网卡
     * @param str_card_name  网卡的描述信息
     * @return 如果是虚拟网卡或回环网卡,返回true, 否则返回false
     */
    bool is_virtual_network_card_or_loopback(QString str_card_name)
    {
        if (-1 != str_card_name.indexOf("VMware")
                || -1 != str_card_name.indexOf("Loopback")
                || -1 != str_card_name.indexOf("VirtualBox")
                )
            return true;
    
        return false;
    }
    
    /**
     * @brief 获取本机IP地址
     */
    void print_local_ip()
    {
        // 1. 获取所有网络接口
        QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
    
        QList<QNetworkAddressEntry> entry;
        foreach(QNetworkInterface inter, interfaces)
        {
            // 过滤掉不需要的网卡信息
            if (is_virtual_network_card_or_loopback(inter.humanReadableName()))
                continue;
    
            if (inter.flags() & (QNetworkInterface::IsUp | QNetworkInterface::IsRunning))
            {
                entry = inter.addressEntries();
                // entry.at(0) 是IPv6信息
                if (entry.at(1).ip().protocol() == QAbstractSocket::IPv4Protocol)
                {
                    if (-1 != inter.name().indexOf("wireless"))
                        qDebug() << inter.humanReadableName() << inter.name() << " 无线网IP: " << entry.at(1).ip().toString();
                    else if (-1 != inter.name().indexOf("ethernet"))
                        qDebug() << inter.humanReadableName() << inter.name() << " 以太网IP: " << entry.at(1).ip().toString();
                }
                entry.clear();
            }
        }
    }

    这段代码仅能过滤VMware和VirtualBox的虚拟网卡,且只打印出了网卡上配置的第一个IPv4地址。通常,这应该能够满足获取IP地址需求了,但是,有时候一块网卡上配置了多个IP地址,为了能获取所有IP地址,对上述代码作如下修改:

    /**
     * @brief 获取本机IP地址
     * @param map_ip 输出参数  IPv4列表  
     *                  QString  ipv4地址
     *                  int      网卡类型  取值为[0,1],0表示无线,1表示有线
     */
    void get_ip(QMap<QString, int> & map_ip)
    {
        // 1. 获取所有网络接口
        QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
    
        QList<QNetworkAddressEntry> entry;
        foreach(QNetworkInterface inter, interfaces)
        {
            // 过滤掉vmware虚拟网卡和回环网卡
            if (is_virtual_network_card_or_loopback(inter.humanReadableName()))
                continue;
    
            if (inter.flags() & (QNetworkInterface::IsUp | QNetworkInterface::IsRunning))
            {
                entry = inter.addressEntries();
                int cnt = entry.size() - 1;
                for (int i = 1; i <= cnt; ++i)
                {
                    if (entry.at(i).ip().protocol() == QAbstractSocket::IPv4Protocol)
                    {
                        if (-1 != inter.name().indexOf("wireless"))
                        {
                            map_ip.insert(entry.at(i).ip().toString(), 0);
                        }
                        else if (-1 != inter.name().indexOf("ethernet"))
                        {
                            map_ip.insert(entry.at(i).ip().toString(), 1);
                        }
                    }
                }
                entry.clear();
            }
        }
    }
    
    // 测试
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        QMap<QString, int> ipv4;
        get_ip(ipv4);
        
        QMapIterator<QString, int> it(ipv4);
        while(it.hasNext())
        {
            it.next();
            qDebug() << it.key() << " : " << it.value();
        }
        
        return a.exec();
    }

    运行结果如下:

    "172.16.254.51"  :  0
    "192.168.10.30"  :  1
    "192.168.10.31"  :  1

    ipconfig查询结果:
    _

    现在已经解决了一个网卡多个IP的问题,但还有一个问题没有解决,那就是过滤虚拟网卡,以上仅能过滤VMware和VirtualBox的虚拟网卡。
    windows系统,通过查看各个接口的设备描述信息,我们发现,这个信息中包含设备厂商相关内容,并且只有有线网卡的设备描述中含有"PCI"字样,通过查看windows相关API,发现结构体IP_ADAPTER_INFO中包含了网卡信息,并附带了示例,链接为https://msdn.microsoft.com/en-us/library/aa366062(VS.85).aspx
    将示例稍作修改,以满足需求:

    void get_ip_list()
    {
        DWORD dwRetVal = 0;
        PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
        ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
        if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS)
        {
            GlobalFree(pAdapterInfo);
            pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);
        }
    
        if((dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen)) == NO_ERROR)
        {
            while (pAdapterInfo)
            {
                if(strstr(pAdapterInfo->Description,"PCI") > 0 || IF_TYPE_IEEE80211 == pAdapterInfo->Type)
                {
                    qDebug() << "------------------------------------------------------------------------";
                    qDebug() << "Adapter Desc: " << QString::fromLocal8Bit(pAdapterInfo->Description);
                    qDebug() << "Adapter Type: " << pAdapterInfo->Type;
                    // 单个网卡上可能有多个IP
                    PIP_ADDR_STRING addr = &(pAdapterInfo->IpAddressList);
                    do
                    {
                        qDebug() << "IP Address: " << addr->IpAddress.String;
                        addr = addr->Next;
                    }
                    while (addr);
                }
                pAdapterInfo = pAdapterInfo->Next;
            }
        }
        else
        {
            qDebug() << "GetAdaptersInfo failed with error: " << dwRetVal;
        }
    
        if(pAdapterInfo)
        {
            GlobalFree(pAdapterInfo);
        }
    }

    我机器上的输出结果如下:

    ------------------------------------------------------------
    Adapter Desc:  "Microsoft Wi-Fi Direct 虚拟适配器"
    Adapter Type:  71
    IP Address:  0.0.0.0
    ------------------------------------------------------------
    Adapter Desc:  "Broadcom 802.11n 网络适配器"
    Adapter Type:  71
    IP Address:  172.16.254.51
    ------------------------------------------------------------
    Adapter Desc:  "Realtek PCIe GBE Family Controller"
    Adapter Type:  6
    IP Address:  192.168.10.30
    IP Address:  192.168.10.128
    IP Address:  192.168.10.130

    显然,"Realtek PCIe GBE Family Controller"上配置了三个IP,且“Microsoft Wi-Fi Direct 虚拟适配器”不是我所需要的,排除之。

    void get_ip_list(QMap<QString, int> & map_ip)
    {
        DWORD dwRetVal = 0;
        PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
        ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
    
        if(GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS)
        {
            GlobalFree(pAdapterInfo);
            pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);
        }
    
        if((dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen)) == NO_ERROR)
        {
            while (pAdapterInfo)
            {
                if(strstr(pAdapterInfo->Description,"PCI") > 0
                        || (IF_TYPE_IEEE80211 == pAdapterInfo->Type && 0 < strstr(pAdapterInfo->Description, "802")))
                {
                    PIP_ADDR_STRING addr = &(pAdapterInfo->IpAddressList);
                    do
                    {
                        if (IF_TYPE_IEEE80211 == pAdapterInfo->Type)
                            map_ip.insert(addr->IpAddress.String, 0);
                        else
                            map_ip.insert(addr->IpAddress.String, 1);
                        addr = addr->Next;
                    }
                    while (addr);
                }
                pAdapterInfo = pAdapterInfo->Next;
            }
        }
        else
        {
            qDebug() << "GetAdaptersInfo failed with error: " << dwRetVal;
        }
    
        if(pAdapterInfo)
        {
            GlobalFree(pAdapterInfo);
        }
    }
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        
        QMap<QString, int> ipv4;
        
        get_ip_list(ipv4);
        
        QMapIterator<QString, int> it(ipv4);
        while(it.hasNext())
        {
            it.next();
            qDebug() << it.key() << " : " << it.value();
        }
    
        return a.exec();
    }

    输出如下:

    "172.16.254.51"  :  0
    "192.168.10.128"  :  1
    "192.168.10.130"  :  1
    "192.168.10.30"  :  1



    转载于:Qt 5.7 获取本机IP地址-阿里云开发者社区 (aliyun.com)
  • 相关阅读:
    今天在国外网站上做了个测试,结果竟然这样
    中考总算考完了
    [转]从磁芯大战谈汇编
    位运算Pascal相关函数/过程
    本Blog已经迁往Wordpress.com
    PhyTopic测试结果...
    POJ1273 dinic Pascal模板
    C#解析xml文件
    并行和并发
    RI工具库参考
  • 原文地址:https://www.cnblogs.com/tingtaishou/p/15213818.html
Copyright © 2011-2022 走看看