2013-07-28 36 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