您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > C语言获取Linux系统的IP地址和MAC地址
实际环境和特殊需求往往会将简单问题复杂化,比如计算机IP地址,对于一个连接中socket,可以直接获得本端和对端的IP、端口信息。但在一些特殊场合我们可能需要更多的信息,比如系统中有几块网卡,他们的Mac地址是多少,每块网卡分配了几个IP(一个网卡对应多个IP)等等。这些信息往往需要通过ifconfig指令来获得,对于程序员来说,在代码中调用外部的shell指令可不是个最佳方案,因为没人能保障不同平台、不同版本的ifconfig指令输出的格式是一致的。本篇文章中将介绍通过ioctl函数实现上述需求。#includeintioctl(intfd,intrequest,…);返回:成功返回0,失败返回-1ioctl函数的参数只有3个,但却是Unix中少有的几个“家族类”复杂函数,这里摘录一段《Unix网络编程》一书中对ioctl函数的描述:在传统上ioctl函数是用于那些普遍使用、但不适合归入其他类别的任何特殊的系统接口……网络程序(一般是服务器程序)中ioctl常用于在程序启动时获得主机上所有接口的信息:接口的地址、接口是否支持广播、是否支持多播,等等。ioctl函数的第一个参数fd,可以表示一个打开的文件(文件句柄)或网络套接字,第二个和第三个参数体现了函数的家族特色,参数二request根据函数功能分类定义了多组宏,而参数三总是一个指针,指针的类型依赖于参数二request。因为ioctl的种类实在太多,这里只列出和本文相关的几个参数定义:分类参数二(宏)参数三描述接口SIOCGIFCONFstructifconf获得所有接口列表SIOCGIFADDRstructifreq获得接口地址SIOCGIFFLAGSstructifreq获得接口标志SIOCGIFBRDADDRstructifreq获得广播地址SIOCGIFNETMASKstructifreq获得子网掩码上表中列出了两个相关的结构体:structifconf和structifreq,要了解ioctl函数的具体运用,首先要了解这两个结构:structifconf{intifc_len;union{__caddr_tifcu_buf;structifreq*ifcu_req;}ifc_ifcu;};structifreq{#defineIFHWADDRLEN6#defineIFNAMSIZIF_NAMESIZEunion{charifrn_name[IFNAMSIZ];}ifr_ifrn;union{structsockaddrifru_addr;structsockaddrifru_dstaddr;structsockaddrifru_broadaddr;structsockaddrifru_netmask;structsockaddrifru_hwaddr;shortintifru_flags;intifru_ivalue;intifru_mtu;structifmapifru_map;charifru_slave[IFNAMSIZ];charifru_newname[IFNAMSIZ];__caddr_tifru_data;}ifr_ifru;};structifconf的第二个元素ifc_ifcu是一个联合,是指向structifreq结构的地址,通常是一组structifreq结构空间(每一个描述一个接口),structifconf的第一个元素ifc_len描述了structifreq结构空间的大小;结构structifreq也有两个元素,第一个元素ifr_ifrn内含一个字符串,用来描述接口的名称,比如“eth0″、”wlan0”等,第二个元素是联合,比较复杂,用来描述套接口的地址结构。structifconf和structifreq的关系可以参考下图:ioctl函数中的structifconf和structifreq结构关系通常运用ioctl函数的第一步是从内核获取系统的所有接口,然后再针对每个接口获取其地址信息。获取所有接口通过SIOCGIFCONF请求来实现:structifconfifc;structifreqifrs[16];ifc.ifc_len=sizeof(ifrs);ifc.ifc_buf=(caddr_t)ifrs;ioctl(fd,SIOCGIFCONF,(char*)&ifc);获得了接口列表,就可以通过structifconf结构中*ifcu_req的指针得到structifreq结构数组的地址,通过遍历获得每隔接口的详细地址信息:printf(接口名称:%s/n,ifrs[n].ifr_name);ioctl(fd,SIOCGIFADDR,(char*)&ifrs[n]);printf(IP地址:%s/n,(char*)inet_ntoa(((structsockaddr_in*)(&ifrs[n].ifr_addr))-sin_addr));ioctl(fd,SIOCGIFNETMASK,(char*)&ifrs[n]);printf(子网掩码:%s/n,(char*)inet_ntoa(((structsockaddr_in*)(&ifrs[n].ifr_addr))-sin_addr));ioctl(fd,SIOCGIFBRDADDR,(char*)&ifrs[n]);printf(广播地址:%s/n,(char*)inet_ntoa(((structsockaddr_in*)(&ifrs[n].ifr_addr))-sin_addr));ioctl(fd,SIOCGIFHWADDR,(char*)&ifrs[n]);printf(MAC地址:x:x:x:x:x:x/n,(unsignedchar)ifrs[n].ifr_hwaddr.sa_data[0],(unsignedchar)ifrs[n].ifr_hwaddr.sa_data[1],(unsignedchar)ifrs[n].ifr_hwaddr.sa_data[2],(unsignedchar)ifrs[n].ifr_hwaddr.sa_data[3],(unsignedchar)ifrs[n].ifr_hwaddr.sa_data[4],(unsignedchar)ifrs[n].ifr_hwaddr.sa_data[5]);最后,给出一个参考程序代码。ioctl函数没有纳入POXIS规范,各系统对ioctl的实现也不尽相同,下面的代码在我的Ubuntu10.04linux上可执行通过,但在其他Unix系统上不一定能够通过编译,例如在PowerAIX5.3上需要将获得MAC地址的那段代码注释掉。#include#include#include#include#include#include#include#include#defineMAXINTERFACES16intfd;intif_len;structifreqbuf[MAXINTERFACES];structifconfifc;intmain(argc,argv){if((fd=socket(AF_INET,SOCK_DGRAM,0))==-1){perror(socket(AF_INET,SOCK_DGRAM,0));return-1;}ifc.ifc_len=sizeof(buf);ifc.ifc_buf=(caddr_t)buf;if(ioctl(fd,SIOCGIFCONF,(char*)&ifc)==-1){perror(SIOCGIFCONFioctl);return-1;}if_len=ifc.ifc_len/sizeof(structifreq);printf(接口数量:%d/n/n,if_len);while(if_len–0){printf(接口:%s/n,buf[if_len].ifr_name);if(!(ioctl(fd,SIOCGIFFLAGS,(char*)&buf[if_len]))){if(buf[if_len].ifr_flags&IFF_UP){printf(接口状态:UP/n);}else{printf(接口状态:DOWN/n);}}else{charstr[256];sprintf(str,SIOCGIFFLAGSioctl%s,buf[if_len].ifr_name);perror(str);}if(!(ioctl(fd,SIOCGIFADDR,(char*)&buf[if_len]))){printf(IP地址:%s/n,(char*)inet_ntoa(((structsockaddr_in*)(&buf[if_len].ifr_addr))-sin_addr));}else{charstr[256];sprintf(str,SIOCGIFADDRioctl%s,buf[if_len].ifr_name);perror(str);}if(!(ioctl(fd,SIOCGIFNETMASK,(char*)&buf[if_len]))){printf(子网掩码:%s/n,(char*)inet_ntoa(((structsockaddr_in*)(&buf[if_len].ifr_addr))-sin_addr));}else{charstr[256];sprintf(str,SIOCGIFADDRioctl%s,buf[if_len].ifr_name);perror(str);}if(!(ioctl(fd,SIOCGIFBRDADDR,(char*)&buf[if_len]))){printf(广播地址:%s/n,(char*)inet_ntoa(((structsockaddr_in*)(&buf[if_len].ifr_addr))-sin_addr));}else{charstr[256];sprintf(str,SIOCGIFADDRioctl%s,buf[if_len].ifr_name);perror(str);}if(!(ioctl(fd,SIOCGIFHWADDR,(char*)&buf[if_len]))){printf(MAC地址:x:x:x:x:x:x/n/n,(unsignedchar)buf[if_len].ifr_hwaddr.sa_data[0],(unsignedchar)buf[if_len].ifr_hwaddr.sa_data[1],(unsignedchar)buf[if_len].ifr_hwaddr.sa_data[2],(unsignedchar)buf[if_len].ifr_hwaddr.sa_data[3],(unsignedchar)buf[if_len].ifr_hwaddr.sa_data[4],(unsignedchar)buf[if_len].ifr_hwaddr.sa_data[5]);}else{charstr[256];sprintf(str,SIOCGIFHWADDRioctl%s,buf[if_len].ifr_name);perror(str);}}//–whileend//关闭socketclose(fd);return0;}在我的系统上,程序输出:接口数量:4接口:wlan0接口状态:UPIP地址:192.168.1.142子网掩码:255.255.255.0广播地址:192.168.1.255MAC地址:00:14:a5:65:47:57接口:eth0:0接口状态:UPIP地址:192.168.4.113子网掩码:255.255.255.0广播地址:192.168.4.255MAC地址:00:14:c2:e5:45:57接口:eth0接口状态:UPIP地址:192.168.4.111子网掩码:255.255.255.0广播地址:192.168.4.255MAC地址:00:14:c2:e5:45:57接口:lo接口状态:UPIP地址
本文标题:C语言获取Linux系统的IP地址和MAC地址
链接地址:https://www.777doc.com/doc-3722037 .html