2013-07-28 32 views
4

我的问题是关于下面的代码(在this link):Linux下C:获取默认接口的IP地址

#include <stdio.h> 
#include <sys/types.h> 
#include <ifaddrs.h> 
#include <netinet/in.h> 
#include <string.h> 
#include <arpa/inet.h> 

int main (int argc, const char * argv[]) { 
    struct ifaddrs * ifAddrStruct = NULL; 
    struct ifaddrs * ifa = NULL; 
    void * tmpAddrPtr = NULL; 

    getifaddrs(&ifAddrStruct); 

    for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { 
     if (ifa ->ifa_addr->sa_family==AF_INET) { // Check it is 
      // a valid IPv4 address 
      tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; 
      char addressBuffer[INET_ADDRSTRLEN]; 
      inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); 
      printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); 
     } 
     else if (ifa->ifa_addr->sa_family==AF_INET6) { // Check it is 
      // a valid IPv6 address 
      tmpAddrPtr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; 
      char addressBuffer[INET6_ADDRSTRLEN]; 
      inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); 
      printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); 
     } 
    } 
    if (ifAddrStruct != NULL) 
     freeifaddrs(ifAddrStruct); 
    return 0; 
} 

这段代码的输出是这样的:

lo IP Address 127.0.0.1 
wlan0 IP Address 172.28.1.89 (I want to only this) 
lo IP Address ::1 
wlan0 IP Address fe80::6e71:d9ff:fe1d:b0 

我怎样才能得到默认接口的IP地址? (你可以给另一个代码块的答案。)

+1

确实没有默认IP这样的东西。最接近“默认”可能是本地主机名和相关地址,看看'gethostname' – Anycorn

+0

如果我得到的主机名与gethostname,然后用这个主机名得到IP,是不是这个IP 127.0.0.1?但我想默认的接口IP地址 – Musher

+0

如果你的主机名被设置为localhost,你会得到127.0.0.1。 cf'/ etc/hosts'。你可以迭代通过接口并找到第一个不是127.0.0.1的并使用它。 – Anycorn

回答

2

此代码将做的事:

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> /* For strncpy */ 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/ioctl.h> 
#include <netinet/in.h> 
#include <net/if.h> 
#include <arpa/inet.h> 

int 
main() 
{ 
    int fd; 
    struct ifreq ifr; 

    fd = socket(AF_INET, SOCK_DGRAM, 0); 

    /* I want to get an IPv4 IP address */ 
    ifr.ifr_addr.sa_family = AF_INET; 

    /* I want an IP address attached to "eth0" */ 
    strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1); 

    ioctl(fd, SIOCGIFADDR, &ifr); 

    close(fd); 

    /* Display result */ 
    printf("%s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr)); 

    return 0; 
} 

结果:

192.168.5.27 

RUN SUCCESSFUL (total time: 52ms) 

或者,你也可以使用一个IP地址掩码。例如,如果面膜从255.0.0.0是不同的(回送面膜),这将只打印

#include <stdio.h> 
#include <sys/types.h> 
#include <ifaddrs.h> 
#include <netinet/in.h> 
#include <string.h> 
#include <arpa/inet.h> 

int main(int argc, const char * argv[]) { 
    struct ifaddrs * ifAddrStruct = NULL, * ifa = NULL; 
    void * tmpAddrPtr = NULL; 

    getifaddrs(&ifAddrStruct); 
    for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { 
     if (ifa ->ifa_addr->sa_family == AF_INET) { // Check it is IPv4 
      char mask[INET_ADDRSTRLEN]; 
      void* mask_ptr = &((struct sockaddr_in*) ifa->ifa_netmask)->sin_addr; 
      inet_ntop(AF_INET, mask_ptr, mask, INET_ADDRSTRLEN); 
      if (strcmp(mask, "255.0.0.0") != 0) { 
       printf("mask:%s\n", mask); 
       // Is a valid IPv4 Address 
       tmpAddrPtr = &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr; 
       char addressBuffer[INET_ADDRSTRLEN]; 
       inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); 
       printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); 
      } 
      else if (ifa->ifa_addr->sa_family == AF_INET6) { // Check it is 
       // a valid IPv6 Address. 

       // Do something 
      } 
     } 
    } 
    if (ifAddrStruct != NULL) 
     freeifaddrs(ifAddrStruct); 
    return 0; 
} 

结果:

mask:255.255.255.0 

eth0 IP Address 192.168.5.27 

RUN SUCCESSFUL (total time: 53ms) 
+0

可能不适用于具有多个IP地址和多个以太网端口的少数服务器(因为在这种情况下,没有单个默认IP地址)。 –

+0

我并不是说要覆盖所有的可能性。只是想给任何方向 – 4pie0

0

覆盖更多的情况下会涉及像这样的方法:

  • 解析/ proc/net/route文件以查看哪个接口是“默认”接口;
  • 使用第一篇文章中的代码段(使用​​)计算出该接口的IP地址。

路线文件解析可能是这样的(为简便起见C++代码):

std::string defaultInterface; 

std::ifstream routeFile(NET_ROUTE_FILEPATH, std::ios_base::in); 
if (!routeFile.good()) 
{ 
    return; 
} 

std::string line; 
std::vector<std::string> tokens; 
while(std::getline(routeFile, line)) 
{ 
    std::istringstream stream(line); 
    std::copy(std::istream_iterator<std::string>(stream), 
       std::istream_iterator<std::string>(), 
       std::back_inserter<std::vector<std::string> >(tokens)); 

    // the default interface is the one having the second 
    // field, Destination, set to "00000000" 
    if ((tokens.size() >= 2) && (tokens[1] == std::string("00000000"))) 
    { 
     defaultInterface = tokens[0]; 
     break; 
    } 

    tokens.clear(); 
} 

routeFile.close(); 

然后,在你的代码,在for循环遍历ifAddrStruct结构,你可以添加一个测试ifa->ifa_name为以上确定的defaultInterface