Qt 5.7 获取本机IP地址

简介: 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
相关文章
|
2月前
|
域名解析 C++
C++ Qt开发:QHostInfo主机地址查询组件
在Qt网络编程中,QHostInfo是一个强大而灵活的组件,用于获取有关主机的信息,包括主机名、IP地址和域名解析等。通过支持异步查询的机制,它能够在后台获取主机信息,避免阻塞主线程,同时通过信号-槽机制提供查询结果。其多主机查询、可靠的错误处理和与网络环境的适应性,使其成为处理网络应用中主机信息获取的理想选择。
45 6
C++ Qt开发:QHostInfo主机地址查询组件
Qt实用技巧:QLineEdit限制只能输入Ip地址,且一直显示ip地址分段的“.”
Qt实用技巧:QLineEdit限制只能输入Ip地址,且一直显示ip地址分段的“.”
Qt实用技巧:QLineEdit限制只能输入Ip地址,且一直显示ip地址分段的“.”
|
JSON Java API
基于Qt的音乐播放器(三)通过酷狗音乐的api接口,返回json格式歌曲信息(播放地址,歌词,图片)
基于Qt的音乐播放器(三)通过酷狗音乐的api接口,返回json格式歌曲信息(播放地址,歌词,图片)
基于Qt的音乐播放器(三)通过酷狗音乐的api接口,返回json格式歌曲信息(播放地址,歌词,图片)
|
程序员 开发工具 C语言
Qt编写自定义控件68-IP地址输入框
一、前言 这个IP地址输入框控件,估计写烂了,网上随便一搜索,保证一大堆,估计也是因为这个控件太容易了,非常适合新手练手,一般的思路都是用4个qlineedit控件拼起来,然后每个输入框设置正则表达式过滤只能输入3位数字,然后安装事件过滤器识别回车自动跳到下一个输入框。
1429 0
qt 例子地址
http://blog.sina.com.cn/s/articlelist_2801495241_0_2.html   qt打包http://blog.chinaunix.net/uid-24641004-id-3412254.
671 0
|
2月前
|
算法 编译器 Linux
【Qt4 部署】ARM系统上使用Qt 4 进行开发的QWS 等环境变量部署
【Qt4 部署】ARM系统上使用Qt 4 进行开发的QWS 等环境变量部署
25 0
|
2月前
|
网络协议 C++
C++ Qt开发:QTcpSocket网络通信组件
`QTcpSocket`和`QTcpServer`是Qt中用于实现基于TCP(Transmission Control Protocol)通信的两个关键类。TCP是一种面向连接的协议,它提供可靠的、双向的、面向字节流的通信。这两个类允许Qt应用程序在网络上建立客户端和服务器之间的连接。Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用`QTcpSocket`组件实现基于TCP的网络通信功能。
44 8
C++ Qt开发:QTcpSocket网络通信组件
|
13天前
|
开发框架 编译器 C++
Qt:一个强大的跨平台C++应用程序开发框架
Qt:一个强大的跨平台C++应用程序开发框架
30 1