设为首页 收藏本站
查看: 951|回复: 0

[经验分享] Linux 获取本机IP、MAC地址用法大全

[复制链接]

尚未签到

发表于 2017-7-6 15:57:29 | 显示全部楼层 |阅读模式
getifaddrs()和struct ifaddrs的使用,获取本机IP


  ifaddrs结构体定义如下:



struct ifaddrs   
{   
     struct ifaddrs  *ifa_next;    /* Next item in list */   
     char            *ifa_name;    /* Name of interface */   
     unsigned int     ifa_flags;   /* Flags from SIOCGIFFLAGS */   
     struct sockaddr *ifa_addr;    /* Address of interface */   
     struct sockaddr *ifa_netmask; /* Netmask of interface */   
     union   
     {   
         struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */   
         struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */   
     } ifa_ifu;   
     #define              ifa_broadaddr ifa_ifu.ifu_broadaddr   
     #define              ifa_dstaddr   ifa_ifu.ifu_dstaddr   
     void            *ifa_data;    /* Address-specific data */   
};   
  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++) {
printf("%s/t", inet_ntoa(*(struct in_addr*)(hent->h_addr_list)));
}
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地址函数



QString GetLocalIp()  
{  
   
     int sock_get_ip;  
     char ipaddr[50];  
   
     struct   sockaddr_in *sin;  
     struct   ifreq ifr_ip;     
   
     if ((sock_get_ip=socket(AF_INET, SOCK_STREAM, 0)) == -1)  
     {  
          printf("socket create failse...GetLocalIp!/n");  
          return "";  
     }  
      
     memset(&ifr_ip, 0, sizeof(ifr_ip));     
     strncpy(ifr_ip.ifr_name, "eth0", sizeof(ifr_ip.ifr_name) - 1);     
   
     if( ioctl( sock_get_ip, SIOCGIFADDR, &ifr_ip) < 0 )     
     {     
          return "";     
     }      
     sin = (struct sockaddr_in *)&ifr_ip.ifr_addr;     
     strcpy(ipaddr,inet_ntoa(sin->sin_addr));         
      
     printf("local ip:%s /n",ipaddr);      
     close( sock_get_ip );  
      
     return QString( ipaddr );  
}  
  //修改本机IP地址的函数



int SetLocalIp( const char *ipaddr )  
{  
   
     int sock_set_ip;  
      
     struct sockaddr_in sin_set_ip;  
     struct ifreq ifr_set_ip;  
   
     bzero( &ifr_set_ip,sizeof(ifr_set_ip));  
   
     if( ipaddr == NULL )  
         return -1;  
   
     if(sock_set_ip = socket( AF_INET, SOCK_STREAM, 0 ) == -1);  
     {  
         perror("socket create failse...SetLocalIp!/n");  
         return -1;  
     }  
   
     memset( &sin_set_ip, 0, sizeof(sin_set_ip));  
     strncpy(ifr_set_ip.ifr_name, "eth0", sizeof(ifr_set_ip.ifr_name)-1);     
      
     sin_set_ip.sin_family = AF_INET;  
     sin_set_ip.sin_addr.s_addr = inet_addr(ipaddr);  
     memcpy( &ifr_set_ip.ifr_addr, &sin_set_ip, sizeof(sin_set_ip));  
   
     if( ioctl( sock_set_ip, SIOCSIFADDR, &ifr_set_ip) < 0 )  
     {  
         perror( "Not setup interface/n");  
         return -1;  
     }  
   
     //设置激活标志  
     ifr_set_ip.ifr_flags |= IFF_UP |IFF_RUNNING;  
   
     //get the status of the device  
     if( ioctl( sock_set_ip, SIOCSIFFLAGS, &ifr_set_ip ) < 0 )  
     {  
          perror("SIOCSIFFLAGS");  
          return -1;  
     }  
   
     close( sock_set_ip );  
     return 0;  
}  
在linux下 获取本机MAC地址的函数
  获取本机MAC地址函数



QString GetLocalMac()  
{  
     int sock_mac;  
      
     struct ifreq ifr_mac;  
     char mac_addr[30];     
      
     sock_mac = socket( AF_INET, SOCK_STREAM, 0 );  
     if( sock_mac == -1)  
     {  
         perror("create socket falise...mac/n");  
         return "";  
     }  
      
     memset(&ifr_mac,0,sizeof(ifr_mac));     
     strncpy(ifr_mac.ifr_name, "eth0", sizeof(ifr_mac.ifr_name)-1);     
   
     if( (ioctl( sock_mac, SIOCGIFHWADDR, &ifr_mac)) < 0)  
     {  
         printf("mac ioctl error/n");  
         return "";  
     }  
      
     sprintf(mac_addr,"%02x%02x%02x%02x%02x%02x",  
             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[0],  
             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[1],  
             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[2],  
             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[3],  
             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[4],  
             (unsigned char)ifr_mac.ifr_hwaddr.sa_data[5]);  
   
     printf("local mac:%s /n",mac_addr);      
      
     close( sock_mac );  
     return QString( mac_addr );  
}  
在linux下 获取,修改子网掩码NETMASK的两个函数
  //获取子网掩码的函数



QString GetLocalNetMask()  
{  
     int sock_netmask;  
     char netmask_addr[50];  
   
     struct ifreq ifr_mask;  
     struct sockaddr_in *net_mask;  
           
     sock_netmask = socket( AF_INET, SOCK_STREAM, 0 );  
     if( sock_netmask == -1)  
     {  
         perror("create socket failture...GetLocalNetMask/n");  
         return "";  
     }  
      
     memset(&ifr_mask, 0, sizeof(ifr_mask));     
     strncpy(ifr_mask.ifr_name, ifname, sizeof(ifr_mask.ifr_name )-1);     
   
     if( (ioctl( sock_netmask, SIOCGIFNETMASK, &ifr_mask ) ) < 0 )   
     {  
         printf("mac ioctl error/n");  
         return "";  
     }  
      
     net_mask = ( struct sockaddr_in * )&( ifr_mask.ifr_netmask );  
     strcpy( netmask_addr, inet_ntoa( net_mask -> sin_addr ) );  
      
     printf("local netmask:%s/n",netmask_addr);      
      
     close( sock_netmask );  
     return QString( netmask_addr );  
}  
  //修改子NETMASK的函数



QString SetLocalNetMask(const char *szNetMask)  
{  
     int sock_netmask;  
     char netmask_addr[32];     
   
     struct ifreq ifr_mask;  
     struct sockaddr_in *sin_net_mask;  
           
     sock_netmask = socket( AF_INET, SOCK_STREAM, 0 );  
     if( sock_netmask == -1)  
     {  
         perror("Not create network socket connect/n");  
         return "";  
     }  
      
     memset(&ifr_mask, 0, sizeof(ifr_mask));     
     strncpy(ifr_mask.ifr_name, "eth0", sizeof(ifr_mask.ifr_name )-1);     
     sin_net_mask = (struct sockaddr_in *)&ifr_mask.ifr_addr;  
     sin_net_mask -> sin_family = AF_INET;  
     inet_pton(AF_INET, szNetMask, &sin_net_mask ->sin_addr);  
   
     if(ioctl(sock_netmask, SIOCSIFNETMASK, &ifr_mask ) < 0)   
     {  
         printf("sock_netmask ioctl error/n");  
         return "";  
     }  
}  
  //获去GateWay



QString GetGateWay()  
{  
     FILE *fp;  
     char buf[512];  
     char cmd[128];  
     char gateway[30];  
     char *tmp;  
   
     strcpy(cmd, "ip route");  
     fp = popen(cmd, "r");  
     if(NULL == fp)  
     {  
         perror("popen error");  
         return "";  
     }  
     while(fgets(buf, sizeof(buf), fp) != NULL)  
     {  
         tmp =buf;  
         while(*tmp && isspace(*tmp))  
             ++ tmp;  
         if(strncmp(tmp, "default", strlen("default")) == 0)  
             break;  
     }  
     sscanf(buf, "%*s%*s%s", gateway);         
     printf("default gateway:%s/n", gateway);  
     pclose(fp);  
      
     return QString(gateway);  
}  
  //设置网关



int SetGateWay(const char *szGateWay)  
{  
     int ret = 0;      
     char cmd[128];  
     QString DefGW = GetGateWay();  
   
     const char *strGW = DefGW.latin1();   
      
     strcpy(cmd, "route del default gw ");  
     strcat(cmd, strGW);  
     ret = system(cmd);  
     if(ret < 0)  
     {  
         perror("route error");  
         return -1;  
     }  
     strcpy(cmd, "route add default gw ");  
     strcat(cmd, szGateWay);  
      
     ret = system(cmd);  
     if(ret < 0)  
     {  
         perror("route error");  
         return -1;  
     }  
   
     return ret;  
}  

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的源代码以后才知道正确的做法。代码如下:



  res_init();      

        for (int i = 0; i < _res.nscount; i++)

        {

               struct sockaddr* server = (struct sockaddr*)&_res.nsaddr_list;

               printf("Server:  %s\n", inet_ntoa(*(in_addr*)&(server->sa_data[2])));

        }
  代码很简单,就不做解释了。
  怎么获取网关呢?这个稍微有点麻烦一些,不过和获取网卡数量相似,都是通过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地址的方法相同,这里就不多说了。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-391059-1-1.html 上篇帖子: Mac终端(Terminal)自定义颜色,字体,背景 下篇帖子: 【ReactNative】Mac下分分钟打包 Android apk
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表