Linux环境下获取当前主机的IP/MAC等信息(C/C++)

2019-07-13 03:47发布

本文介绍在unix环境下获取当前主机IP,MAC地址等网络接口信息。在不确定设备网卡类型的情况下,通过预先定义几种可能的网卡类型,然后依次遍历可能的设备如eth0,eth1,借助ioctl函数获取主机的全部网络接口信息。ioctl函数可以获取所在主机的全部网络接口信息,包括接口地址(IP,MAC,MASK…)、是否支持广播等。ioctl函数的头文件没有标准化,许多系统在“unistd.h中定义,而传统的BSD系统中,通常在 “sys/ioctl.h”中定义 。ioctl的原型为: 
int ioctl(int fd,int request, void *arg ); 
返回:成功返回0,失败返回-1 
参数fd通常是获取接口信息所用到的句柄,在本文获取ip等信息时,是socket连接句柄; 
参数arg总是一个指针,其类型依赖于request参数; 
request类型主要分为6类:套接字操作、文件操作、接口操作、ARP高速缓存操作、路由表操作、流系统 
本文要介绍的获取IP地址和MAC等属于接口操作。其中 
IP地址的request类型为SIOCGIFADDR 
MAC地址的request类型为SIOCGIFHWADDR 
其余类型参考文献[1],第17章相关章节。有关请求参数struct ifreq的定义为位于“net/if.h”if.h> /* Interface request structure used for socket ioctl's. All interface ioctl's must have parameter definitions which begin with ifr_name. The remainder may be interface specific. */ struct ifreq { # define IFHWADDRLEN 6 # define IFNAMSIZ IF_NAMESIZE union { char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */ } ifr_ifrn; union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; struct sockaddr ifru_netmask; struct sockaddr ifru_hwaddr; short int ifru_flags; int ifru_ivalue; int ifru_mtu; struct ifmap ifru_map; char ifru_slave[IFNAMSIZ]; /* Just fits the size */ char ifru_newname[IFNAMSIZ]; __caddr_t ifru_data; } ifr_ifru; }; # define ifr_name ifr_ifrn.ifrn_name /* interface name */ # define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ # define ifr_addr ifr_ifru.ifru_addr /* address */ # define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ # define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ # define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ # define ifr_flags ifr_ifru.ifru_flags /* flags */ # define ifr_metric ifr_ifru.ifru_ivalue /* metric */ # define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ # define ifr_map ifr_ifru.ifru_map /* device map */ # define ifr_slave ifr_ifru.ifru_slave /* slave device */ # define ifr_data ifr_ifru.ifru_data /* for use by interface */ # define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */ # define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */ # define ifr_qlen ifr_ifru.ifru_ivalue /* queue length */ # define ifr_newname ifr_ifru.ifru_newname /* New name */ # define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0) # define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0) # define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)


下面是相关代码:#include #include #include #include #include #include #include #include #include #include using namespace std; bool GetIP(const vector<string>& vNetType,string& strip) { for(size_t i=0;ifor(char c='0';c<='9';++c) { string strDevice = vNetType[i] + c; //根据网卡类型,遍历设备如eth0,eth1 int fd; struct ifreq ifr; //使用UDP协议建立无连接的服务 fd = socket(AF_INET, SOCK_DGRAM, 0); strcpy(ifr.ifr_name, strDevice.c_str() ); //获取IP地址 if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) { ::close(fd); continue; } // 将一个IP转换成一个互联网标准点分格式的字符串 strip = inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr); if(!strip.empty()) { ::close(fd); return true; } } } return false; } int main() { vector<string> vs;//预先定义了几种可能的网卡类型 vs.push_back("eth"); vs.push_back("em"); vs.push_back("oct"); string str; if( (GetIP(vs,str)) ) { cout<return 0; }

获取MAC地址的代码片段如下:获取MAC地址的代码如下 fd = socket(AF_INET, SOCK_DGRAM, 0); strcpy(ifr.ifr_name, strDevice.c_str() ); if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { ::close(fd); continue; } unsigned char macaddr[6]; memcpy(macaddr,ifr.ifr_hwaddr.sa_data,6); for(int k=0;k<6;k++) { printf("%02x",macaddr[k]); if(k<5) printf(":"); }