Qt5.12获取本机IP地址

老子叫甜甜 提交于 2019-12-15 01:03:14

最近在写有关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";
}

首先获取本机所有IP地址信息,包括环回地址如127.0.0.1,以及本机地址如192.168.1.x等等,有安装虚拟机的还有其他地址等等。

/**
 * @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();
        }
    }
}

以上代码能够过滤虚拟机虚拟网卡,并且打印网卡配置上的第一个IPv4地址,为什么说是第一个呢?因为主机可能存在多宿主机,一个网卡配置多个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();
}

其实还有一个问题,在Windows上通过查看接口设备信息,发现每个信息中都包含设备厂商相关的内容,并且只有有线网卡的设备描述中包含“PCI”字样。通过查看Windows相关API,发现发现结构体IP_ADAPTER_INFO中包含了网卡信息,并附带了示例,链接为https://docs.microsoft.com/zh-cn/windows/win32/api/iptypes/ns-iptypes-ip_adapter_info?redirectedfrom=MSDN

进行修改如下。

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();
}

实现这个功能的主要目的是查找IPv4的地址,可能读者的需求不同可以进行更改,也还有其他办法获取IP地址信息,望指出错误。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!