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地址的方法相同,這里就不多說了。