Linux 獲取本機IP、MAC地址用法大全


getifaddrs()和struct ifaddrs的使用,獲取本機IP

    ifaddrs結構體定義如下:

 1 struct ifaddrs   
 2 {   
 3     struct ifaddrs  *ifa_next;    /* Next item in list */   
 4     char            *ifa_name;    /* Name of interface */   
 5     unsigned int     ifa_flags;   /* Flags from SIOCGIFFLAGS */   
 6     struct sockaddr *ifa_addr;    /* Address of interface */   
 7     struct sockaddr *ifa_netmask; /* Netmask of interface */   
 8     union   
 9     {   
10         struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */   
11         struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */   
12     } ifa_ifu;   
13     #define              ifa_broadaddr ifa_ifu.ifu_broadaddr   
14     #define              ifa_dstaddr   ifa_ifu.ifu_dstaddr   
15     void            *ifa_data;    /* Address-specific data */   
16 };   

 ifa_next指向鏈表的下一個成員;ifa_name是接口名稱,以0結尾的字符串,比如eth0,lo;ifa_flags是接口的標識位(比如當IFF_BROADCAST或IFF_POINTOPOINT設置到此標識位時,影響聯合體變量ifu_broadaddr存儲廣播地址或ifu_dstaddr記錄點對點地址);ifa_netmask存儲該接口的子網掩碼;結構體變量存儲廣播地址或點對點地址(見括弧介紹ifa_flags);ifa_data存儲了該接口協議族的特殊信息,它通常是NULL(一般不關注他)。

    函數getifaddrs(int getifaddrs (struct ifaddrs **__ifap))獲取本地網絡接口信息,將之存儲於鏈表中,鏈表頭結點指針存儲於__ifap中帶回,函數執行成功返回0,失敗返回-1,且為errno賦值。
    很顯然,函數getifaddrs用於獲取本機接口信息,比如最典型的獲取本機IP地址。

 

linux編程獲取本機IP地址的三種方法

這 是一項不太清晰而且沒有多大意義的工作。一個原因是網絡地址的設置非常靈活而且都是允許用戶進行個性化設置的,比如一台計算機上可以有多塊物理網卡或者虛 擬網卡,一個網卡上可以綁定多個IP地址,用戶可以為網卡設置別名,可以重命名網卡,用戶計算機所在網絡拓撲結構未知,主機名設置是一個可選項並且同樣可 以為一個計算機綁定多個主機名等,這些信息都會有影響。脫離了網絡連接,單獨的網絡地址沒有任何意義。編程中遇到必須獲取計算機IP的場景,應該考慮將這 一選項放到配置文件中,由用戶自己來選擇。

通過google,編程獲取IP地址大約有以下三種思路:
1. 通過gethostname()和gethostbyname()

#include <stdio.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main() {
    char hname[128];
    struct hostent *hent;
    int i;

    gethostname(hname, sizeof(hname));

    //hent = gethostent();
    hent = gethostbyname(hname);

    printf("hostname: %s/naddress list: ", hent->h_name);
    for(i = 0; hent->h_addr_list[i]; i++) {
        printf("%s/t", inet_ntoa(*(struct in_addr*)(hent->h_addr_list[i])));
    }
    return 0;
}

運行:
[whb@jcwkyl c]$ ./local_ip 
hostname: jcwkyl.jlu.edu.cn
address list: 10.60.56.90       


2. 通過枚舉網卡,API接口可查看man 7 netdevice

/*代碼來自StackOverflow: http://stackoverflow.com/questions/212528/linux-c-get-the-ip-address-of-local-computer */
#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;
    void * tmpAddrPtr=NULL;

    getifaddrs(&ifAddrStruct);

    while (ifAddrStruct!=NULL) {
        if (ifAddrStruct->ifa_addr->sa_family==AF_INET) { // check it is IP4
            // is a valid IP4 Address
            tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
            char addressBuffer[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
            printf("%s IP Address %s/n", ifAddrStruct->ifa_name, addressBuffer); 
        } else if (ifAddrStruct->ifa_addr->sa_family==AF_INET6) { // check it is IP6
            // is a valid IP6 Address
            tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
            char addressBuffer[INET6_ADDRSTRLEN];
            inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
            printf("%s IP Address %s/n", ifAddrStruct->ifa_name, addressBuffer); 
        } 
        ifAddrStruct=ifAddrStruct->ifa_next;
    }
    return 0;
}

運行 :
[whb@jcwkyl c]$ ./local_ip2 
lo IP Address 127.0.0.1
eth0 IP Address 10.60.56.90
eth0:1 IP Address 192.168.1.3
lo IP Address ::
eth0 IP Address ::2001:da8:b000:6213:20f:1fff
eth0 IP Address 0:0:fe80::20f:1fff

3. 打開一個對外界服務器的網絡連接,通過getsockname()反查自己的IP

 

linux下獲取IP等信息函數

 

在linux下 獲取,修改本機IP地址的兩個函數

 

//獲取本機IP地址函數

 1 QString GetLocalIp()  
 2 {  
 3   
 4     int sock_get_ip;  
 5     char ipaddr[50];  
 6   
 7     struct   sockaddr_in *sin;  
 8     struct   ifreq ifr_ip;     
 9   
10     if ((sock_get_ip=socket(AF_INET, SOCK_STREAM, 0)) == -1)  
11     {  
12          printf("socket create failse...GetLocalIp!/n");  
13          return "";  
14     }  
15      
16     memset(&ifr_ip, 0, sizeof(ifr_ip));     
17     strncpy(ifr_ip.ifr_name, "eth0", sizeof(ifr_ip.ifr_name) - 1);     
18    
19     if( ioctl( sock_get_ip, SIOCGIFADDR, &ifr_ip) < 0 )     
20     {     
21          return "";     
22     }       
23     sin = (struct sockaddr_in *)&ifr_ip.ifr_addr;     
24     strcpy(ipaddr,inet_ntoa(sin->sin_addr));         
25       
26     printf("local ip:%s /n",ipaddr);      
27     close( sock_get_ip );  
28       
29     return QString( ipaddr );  
30 }  

 

//修改本機IP地址的函數

 1 int SetLocalIp( const char *ipaddr )  
 2 {  
 3   
 4     int sock_set_ip;  
 5       
 6     struct sockaddr_in sin_set_ip;  
 7     struct ifreq ifr_set_ip;  
 8   
 9     bzero( &ifr_set_ip,sizeof(ifr_set_ip));  
10    
11     if( ipaddr == NULL )  
12         return -1;  
13   
14     if(sock_set_ip = socket( AF_INET, SOCK_STREAM, 0 ) == -1);  
15     {  
16         perror("socket create failse...SetLocalIp!/n");  
17         return -1;  
18     }  
19    
20     memset( &sin_set_ip, 0, sizeof(sin_set_ip));  
21     strncpy(ifr_set_ip.ifr_name, "eth0", sizeof(ifr_set_ip.ifr_name)-1);     
22       
23     sin_set_ip.sin_family = AF_INET;  
24     sin_set_ip.sin_addr.s_addr = inet_addr(ipaddr);  
25     memcpy( &ifr_set_ip.ifr_addr, &sin_set_ip, sizeof(sin_set_ip));  
26   
27     if( ioctl( sock_set_ip, SIOCSIFADDR, &ifr_set_ip) < 0 )  
28     {  
29         perror( "Not setup interface/n");  
30         return -1;  
31     }  
32   
33     //設置激活標志  
34     ifr_set_ip.ifr_flags |= IFF_UP |IFF_RUNNING;  
35   
36     //get the status of the device  
37     if( ioctl( sock_set_ip, SIOCSIFFLAGS, &ifr_set_ip ) < 0 )  
38     {  
39          perror("SIOCSIFFLAGS");  
40          return -1;  
41     }  
42   
43     close( sock_set_ip );  
44     return 0;  
45 }  

在linux下 獲取本機MAC地址的函數

獲取本機MAC地址函數

 1 QString GetLocalMac()  
 2 {  
 3     int sock_mac;  
 4       
 5     struct ifreq ifr_mac;  
 6     char mac_addr[30];     
 7       
 8     sock_mac = socket( AF_INET, SOCK_STREAM, 0 );  
 9     if( sock_mac == -1)  
10     {  
11         perror("create socket falise...mac/n");  
12         return "";  
13     }  
14       
15     memset(&ifr_mac,0,sizeof(ifr_mac));     
16     strncpy(ifr_mac.ifr_name, "eth0", sizeof(ifr_mac.ifr_name)-1);     
17   
18     if( (ioctl( sock_mac, SIOCGIFHWADDR, &ifr_mac)) < 0)  
19     {  
20         printf("mac ioctl error/n");  
21         return "";  
22     }  
23       
24     sprintf(mac_addr,"%02x%02x%02x%02x%02x%02x",  
25             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[0],  
26             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[1],  
27             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[2],  
28             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[3],  
29             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[4],  
30             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[5]);  
31   
32     printf("local mac:%s /n",mac_addr);      
33       
34     close( sock_mac );  
35     return QString( mac_addr );  
36 }  

在linux下 獲取,修改子網掩碼NETMASK的兩個函數

 

//獲取子網掩碼的函數

 1 QString GetLocalNetMask()  
 2 {  
 3     int sock_netmask;  
 4     char netmask_addr[50];  
 5   
 6     struct ifreq ifr_mask;  
 7     struct sockaddr_in *net_mask;  
 8           
 9     sock_netmask = socket( AF_INET, SOCK_STREAM, 0 );  
10     if( sock_netmask == -1)  
11     {  
12         perror("create socket failture...GetLocalNetMask/n");  
13         return "";  
14     }  
15       
16     memset(&ifr_mask, 0, sizeof(ifr_mask));     
17     strncpy(ifr_mask.ifr_name, ifname, sizeof(ifr_mask.ifr_name )-1);     
18   
19     if( (ioctl( sock_netmask, SIOCGIFNETMASK, &ifr_mask ) ) < 0 )   
20     {  
21         printf("mac ioctl error/n");  
22         return "";  
23     }  
24       
25     net_mask = ( struct sockaddr_in * )&( ifr_mask.ifr_netmask );  
26     strcpy( netmask_addr, inet_ntoa( net_mask -> sin_addr ) );  
27       
28     printf("local netmask:%s/n",netmask_addr);      
29       
30     close( sock_netmask );  
31     return QString( netmask_addr );  
32 }  

//修改子NETMASK的函數

 1 QString SetLocalNetMask(const char *szNetMask)  
 2 {  
 3     int sock_netmask;  
 4     char netmask_addr[32];     
 5   
 6     struct ifreq ifr_mask;  
 7     struct sockaddr_in *sin_net_mask;  
 8           
 9     sock_netmask = socket( AF_INET, SOCK_STREAM, 0 );  
10     if( sock_netmask == -1)  
11     {  
12         perror("Not create network socket connect/n");  
13         return "";  
14     }  
15       
16     memset(&ifr_mask, 0, sizeof(ifr_mask));     
17     strncpy(ifr_mask.ifr_name, "eth0", sizeof(ifr_mask.ifr_name )-1);     
18     sin_net_mask = (struct sockaddr_in *)&ifr_mask.ifr_addr;  
19     sin_net_mask -> sin_family = AF_INET;  
20     inet_pton(AF_INET, szNetMask, &sin_net_mask ->sin_addr);  
21   
22     if(ioctl(sock_netmask, SIOCSIFNETMASK, &ifr_mask ) < 0)   
23     {  
24         printf("sock_netmask ioctl error/n");  
25         return "";  
26     }  
27 }  

//獲去GateWay

 1 QString GetGateWay()  
 2 {  
 3     FILE *fp;  
 4     char buf[512];  
 5     char cmd[128];  
 6     char gateway[30];  
 7     char *tmp;  
 8   
 9     strcpy(cmd, "ip route");  
10     fp = popen(cmd, "r");  
11     if(NULL == fp)  
12     {  
13         perror("popen error");  
14         return "";  
15     }  
16     while(fgets(buf, sizeof(buf), fp) != NULL)  
17     {  
18         tmp =buf;  
19         while(*tmp && isspace(*tmp))  
20             ++ tmp;  
21         if(strncmp(tmp, "default", strlen("default")) == 0)  
22             break;  
23     }  
24     sscanf(buf, "%*s%*s%s", gateway);         
25     printf("default gateway:%s/n", gateway);  
26     pclose(fp);  
27       
28     return QString(gateway);  
29 }  

//設置網關

 1 int SetGateWay(const char *szGateWay)  
 2 {  
 3     int ret = 0;      
 4     char cmd[128];  
 5     QString DefGW = GetGateWay();  
 6   
 7     const char *strGW = DefGW.latin1();   
 8       
 9     strcpy(cmd, "route del default gw ");  
10     strcat(cmd, strGW);  
11     ret = system(cmd);  
12     if(ret < 0)  
13     {  
14         perror("route error");  
15         return -1;  
16     }  
17     strcpy(cmd, "route add default gw ");  
18     strcat(cmd, szGateWay);  
19       
20     ret = system(cmd);  
21     if(ret < 0)  
22     {  
23         perror("route error");  
24         return -1;  
25     }  
26   
27     return ret;  
28 }  

 

 

Linux下如何獲取網卡信息  

有時候,寫程序的時候需要獲取計算機的網絡信息,比如IP地址、電腦名稱、DNS等信息。IP地址和電腦名稱是比較容易獲取到的,而要想獲取地址掩碼、DNS、網關等信息就有些麻煩了。

在Windows下我們一般都是通過從注冊表讀取這些信息。在Linux怎么做呢?其實,Linux下更加容易一些。因為我們可以拿現成的程序看它的源代碼。通過閱讀其源代碼找到解決該問題的方法。那么,看哪個程序的源代碼呢?如果你使用過Linux,並且比較熟悉的話就肯定知道一個命令ifconfig。這個命令和Windows下的ipconfig差不多,都可以輸出網卡的信息,其中就包含DNS、掩碼等信息。所以,我們可以通過看它的源代碼來找到解決該問題的方法。

獲取系統中的網卡數量

並沒有那個系統調用提供網卡數量的獲取。但是,我們可以通過強大的proc文件系統獲取網卡數量的信息。實際上,ifconfig也是這樣做的,請看示例代碼如下: 
0001 #include <stdio.h>
0002 #include <string.h>
0003 #include <errno.h>
0004 
0005 int GetNetCardCount()
0006 {
0007     int nCount = 0;
0008     FILE* f = fopen("/proc/net/dev", "r");
0009     if (!f)
0010     {
0011         fprintf(stderr, "Open /proc/net/dev failed!errno:%d\n", errno);
0012         return nCount;
0013     }
0014 
0015     char szLine[512];
0016 
0017     fgets(szLine, sizeof(szLine), f);    /* eat line */
0018     fgets(szLine, sizeof(szLine), f);
0019 
0020     while(fgets(szLine, sizeof(szLine), f))
0021     {
0022         char szName[128] = {0};
0023         sscanf(szLine, "%s", szName);
0024         int nLen = strlen(szName);
0025         if (nLen <= 0)continue;
0026         if (szName[nLen - 1] == ':') szName[nLen - 1] = 0;
0027         if (strcmp(szName, "lo") == 0)continue;
0028         nCount++;
0029     }
0030 
0031     fclose(f);
0032     f = NULL;
0033     return nCount;
0034 }
0035 
0036 int main(int argc, char* argv[])
0037 {
0038     printf("NetCardCount: %d\n", GetNetCardCount());
0039     return 0;
0040 }

 

獲取IP、掩碼、MAC及網關

獲取IP、掩碼、MAC和廣播地址是比較容易的,只需要調用對應的IOCTL即可。只是大家對Linux下的IOCTL可能不太熟悉。卻看示例代碼:

 

0001 void DispNetInfo(const char* szDevName)
0002 {
0003     int s = socket(AF_INET, SOCK_DGRAM, 0);
0004     if (s < 0)
0005     {
0006         fprintf(stderr, "Create socket failed!errno=%d", errno);
0007         return;
0008     }
0009 
0010     struct ifreq ifr;
0011     unsigned char mac[6];
0012     unsigned long nIP, nNetmask, nBroadIP;
0013 
0014     printf("%s:\n", szDevName);
0015 
0016     strcpy(ifr.ifr_name, szDevName);
0017     if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
0018     {
0019         return;
0020     }
0021     memcpy(mac, ifr.ifr_hwaddr.sa_data, sizeof(mac));
0022     printf("\tMAC: %02x-%02x-%02x-%02x-%02x-%02x\n",
0023             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
0024 
0025     strcpy(ifr.ifr_name, szDevName);
0026     if (ioctl(s, SIOCGIFADDR, &ifr) < 0)
0027     {
0028         nIP = 0;
0029     }
0030     else
0031     {
0032         nIP = *(unsigned long*)&ifr.ifr_broadaddr.sa_data[2];
0033     }
0034     printf("\tIP: %s\n", inet_ntoa(*(in_addr*)&nIP));
0035 
0036     strcpy(ifr.ifr_name, szDevName);
0037     if (ioctl(s, SIOCGIFBRDADDR, &ifr) < 0)
0038     {
0039         nBroadIP = 0;
0040     }
0041     else
0042     {
0043         nBroadIP = *(unsigned long*)&ifr.ifr_broadaddr.sa_data[2];
0044     }
0045     printf("\tBroadIP: %s\n", inet_ntoa(*(in_addr*)&nBroadIP));
0046 
0047     strcpy(ifr.ifr_name, szDevName);
0048     if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0)
0049     {
0050         nNetmask = 0;
0051     }
0052     else
0053     {
0054         nNetmask = *(unsigned long*)&ifr.ifr_netmask.sa_data[2];
0055     }
0056     printf("\tNetmask: %s\n", inet_ntoa(*(in_addr*)&nNetmask));
0057     close(s);
0058 }

 

       那么如何獲取網關地址呢?更加容易,但是,好像很少有人知道。反正我在網上沒有找到有人知道。最后看了nslookup的源代碼以后才知道正確的做法。代碼如下:

      

 1  res_init();      
 2 
 3        for (int i = 0; i < _res.nscount; i++)
 4 
 5        {
 6 
 7               struct sockaddr* server = (struct sockaddr*)&_res.nsaddr_list[i];
 8 
 9               printf("Server:  %s\n", inet_ntoa(*(in_addr*)&(server->sa_data[2])));
10 
11        }

 

代碼很簡單,就不做解釋了。

 

怎么獲取網關呢?這個稍微有點麻煩一些,不過和獲取網卡數量相似,都是通過proc文件系統。這次分析的/proc/net/route文件。我就不再貼出示例代碼了。

最后,我把運行示例程序獲取到的信息附上,以供大家有個直觀的認識:

eth0:

       MAC: 08-00-27-98-bf-f3

       IP: 192.168.1.106

       BroadIP: 255.255.255.255

       Netmask: 255.255.255.0

Gateway: 192.168.1.1

eth1:

       MAC: 08-00-27-16-f4-bf

       IP: 192.168.1.108

       BroadIP: 192.168.1.255

       Netmask: 255.255.255.0

Gateway: 0.0.0.0

eth2:

       MAC: 08-00-27-37-9c-91

       IP: 0.0.0.0

       BroadIP: 0.0.0.0

       Netmask: 0.0.0.0

Gateway: 0.0.0.0

eth3:

       MAC: 08-00-27-5a-d2-39

       IP: 0.0.0.0

       BroadIP: 0.0.0.0

       Netmask: 0.0.0.0

Gateway: 0.0.0.0

NetCardCount: 4

DNS 0:  218.2.135.1

DNS 1:  61.147.37.1

 

Linux下C語言配置網絡與獲取網絡配置信息的方法

Linux下的網絡配置包含三個要素,分別是IP地址、子網掩碼和網關。本文將介紹如何在C語言中進行網絡的配置和配置信息的獲取。

 

 

【配置】

 

 

方法一

 

 

使用system()或exec*()調用ifconfig和route命令進行配置。這種方法的優點是使用簡單,缺點是效率比較低,且依賴於ifconfig與route命令。

 

示例:

見所附代碼中的函數ip_config_system()和ip_config_exec()。

 

 

方法二

 

 

建立一個socket,用ioctl()進行配置。這種方法的優點是效率較高,缺點是程序實現起來比較麻煩。

 

示例:

見所附代碼中的函數ip_config_ioctl()。

 

 

【獲取】

 

 

方法一

 

 

用popen()建立一個管道,管道的一端執行命令ifconfig和route,管道的另一端讀取收到的數據並進行相應的解析。這種方法的優點是使用簡單,缺點是效率比較低,且依賴於ifconfig與route命令。

 

示例:

見所附代碼中的函數ip_get_pipe()。

 

 

方法二

 

 

用fopen()打開/proc/net/route,可以獲取網關(在/proc/net中尚未發現比較好的獲取IP地址和掩碼的方法,知道的請發郵件至cugfeng at gamil.com,謝謝)。這種方法的優點是使用簡單,效率比執行命令高,缺點是依賴於proc文件系統。

 

示例:

見所附代碼中的函數ip_get_proc()。

 

 

方法三

 

 

建立一個socket,用ioctl()進行獲取(用ioctl()尚未發現比較好的獲取網關的方法,知道的請發郵件至cugfeng at gamil.com,謝謝)。這種方法的優點是效率較高,缺點是程序實現起來比較麻煩。

 

示例:

見所附代碼中的函數ip_get_ioctl()。

 

 

BTW,用ioctl()的方法還可以獲取MAC地址,ioctl()命令為SIOCGIFHWADDR,具體用法與ioctl()獲取IP地址的方法相同,這里就不多說了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM