获取网络上的活动IP列表(Linux)

时间:2013-12-06 11:12:49

标签: c++ linux

我有一个很好的小程序,它给我一个系统所连接的网络上所有活动ip的向量...但仅适用于Windows

std::vector<std::string> resultIPList;
PMIB_IPNET_TABLE2 pipTable = NULL;
unsigned long status = GetIpNetTable2(AF_INET, &pipTable);
if(status != NO_ERROR)
{
    LOG_ERROR("Error in getting ip Table")
    return resultIPList;
}
for(unsigned i = 0; i < pipTable->NumEntries; i++)
{
    char* ip = inet_ntoa(pipTable->Table[i].Address.Ipv4.sin_addr);
    std::string str = std::string(ip);
    resultIPList.push_back(str);
}
FreeMibTable(pipTable);
pipTable = NULL;
return resultIPList;  

有什么方法可以在Linux中做同样的事情(替换GetIpNetTable函数)。我正在使用RHEL

2 个答案:

答案 0 :(得分:0)

我会看一下RHEL上的rtnetlinkgetifaddrs还有NetworkManager所有三个应该允许你想要的但是我不认为这三个中的任何一个是Windows特定API的直接替代品。您还必须有一些方法来编写代码,以便编译相关的函数。我通常使用`#ifndef'来分割代码,这样你可以使用相同的代码返回相同的东西,但使用不同的代码体依赖于你正在编译的目标操作系统。

我最近回答了另一个问题,其中windows / linux编译是一个问题(用于查找boost的运行时版本)here,原则保持不变,可以根据您的需要轻松定制。

另外,我怀疑Boost.Asio可以帮助你在Windows和Linux中进行单点呼叫。您也可以将其设为integrated-with-Boost版本或standalone,以缩小占用空间。

请告诉我您的情况,或者您是否需要更多信息:)

附录

在Linux上你可以使用以下内容:

#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdio.h>

void
print_sockaddr(struct sockaddr* addr,const char *name)
{
    char addrbuf[128] ;

    addrbuf[0] = 0;
    if(addr->sa_family == AF_UNSPEC)
        return;
    switch(addr->sa_family) {
        case AF_INET:
            inet_ntop(addr->sa_family,&((struct sockaddr_in*)addr)->sin_addr,addrbuf,sizeof(addrbuf));
            break;
        case AF_INET6:
            inet_ntop(addr->sa_family,&((struct sockaddr_in6*)addr)->sin6_addr,addrbuf,sizeof(addrbuf));
            break;
        default:
            sprintf(addrbuf,"Unknown (%d)",(int)addr->sa_family);
            break;

    }
    printf("%-16s %s\n",name,addrbuf);
}

void
print_ifaddr(struct ifaddrs *addr)
{
    char addrbuf[128] ;

    addrbuf[0] = 0;
    printf("%-24s %s\n","Interface Name:",addr->ifa_name);
    if(addr->ifa_addr != NULL)
        print_sockaddr(addr->ifa_addr,"Interface Address:");
    if(addr->ifa_netmask != NULL)
        print_sockaddr(addr->ifa_netmask,"Netmask:");
    if(addr->ifa_broadaddr != NULL)
        print_sockaddr(addr->ifa_broadaddr,"Broadcast address:");
    if(addr->ifa_dstaddr != NULL)
        print_sockaddr(addr->ifa_dstaddr,"Peer address:");
    puts("");
}

int main(int argc,char *argv[])
{
    struct ifaddrs *addrs,*tmp;

    if(getifaddrs(&addrs) != 0) {
        perror("getifaddrs");
        return 1;
    }
    for(tmp = addrs; tmp ; tmp = tmp->ifa_next) {
        print_ifaddr(tmp);
    }

    freeifaddrs(addrs);

    return 0;
}

对于其他衍生产品(Unix,BSD等),这个更基本的代码集可能更有用,虽然我依稀记得BSD下的一些问题(抱歉无法记住目前究竟是什么,认为它与某些确定的失败场景有关)条件将使其无法运作)

#include <stdio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>

#define INT_TO_ADDR(_addr) \
(_addr & 0xFF), \
(_addr >> 8 & 0xFF), \
(_addr >> 16 & 0xFF), \
(_addr >> 24 & 0xFF)

int main()
{
    struct ifconf ifc;
    struct ifreq ifr[10];
    int sd, ifc_num, addr, bcast, mask, network, i;

    // Create a socket then use ioctl on the file descriptor to retrieve the interface information.

    sd = socket(PF_INET, SOCK_DGRAM, 0);
    if (sd > 0)
    {
        ifc.ifc_len = sizeof(ifr);
        ifc.ifc_ifcu.ifcu_buf = (caddr_t)ifr;

        if (ioctl(sd, SIOCGIFCONF, &ifc) == 0)
        {
            ifc_num = ifc.ifc_len / sizeof(struct ifreq);
            printf("%d interfaces found.\n", ifc_num);

            for (i = 0; i < ifc_num; ++i)
            {
                if (ifr[i].ifr_addr.sa_family != AF_INET)
                {
                    continue;
                }

                /* display the interface name */
                printf("%d) Interface Name: %s\n", i+1, ifr[i].ifr_name);

                /* Retrieve the IP address, broadcast address, and subnet mask. */
                if (ioctl(sd, SIOCGIFADDR, &ifr[i]) == 0)
                {
                    addr = ((struct sockaddr_in *)(&ifr[i].ifr_addr))->sin_addr.s_addr;
                    printf("%d) Interface address: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(addr));
                }
                if (ioctl(sd, SIOCGIFBRDADDR, &ifr[i]) == 0)
                {
                    bcast = ((struct sockaddr_in *)(&ifr[i].ifr_broadaddr))->sin_addr.s_addr;
                    printf("%d) Broadcast: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(bcast));
                }
                if (ioctl(sd, SIOCGIFNETMASK, &ifr[i]) == 0)
                {
                    mask = ((struct sockaddr_in *)(&ifr[i].ifr_netmask))->sin_addr.s_addr;
                    printf("%d) Netmask: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(mask));
                }                

                /* Compute the current network value from the address and netmask. */
                network = addr & mask;
                printf("%d) Current Network: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(network));
            }                      
        }

        close(sd);
    }

    return 0;
}

显然你需要根据自己的需要定制代码,但也许这会有所帮助:)

答案 1 :(得分:0)

getifaddrs FTW

#include <ifaddrs.h>
#include <net/if.h>
#include <netinet/in.h>
#include <cstdlib>

ifaddrs* pAdapter = NULL;
ifaddrs* pList = NULL;

int result = getifaddrs(&pList);

if (result == -1)
   return;

pAdapter = pList;
while (pAdapter)
{
    if ((pAdapter->ifa_addr != NULL) && (pAdapter->ifa_flags & IFF_UP))
    {
        if (pAdapter->ifa_addr->sa_family == AF_INET)
        {
            sockaddr_in* addr = (sockaddr_in*)(pAdapter->ifa_addr);
        }
        else if (pAdapter->ifa_addr->sa_family == AF_INET6)
        {
            sockaddr_in6* addr6 = (sockaddr_in6*)(pAdapter->ifa_addr);
        }
    }
    pAdapter = pAdapter->ifa_next;
}
freeifaddrs(pList);
pList = NULL;