Linux平台获取IP地址
首先是使用ioctl
获取IP地址的方法,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| #include <iostream> #include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <stdio.h>
#include <unistd.h> #include <net/if.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> #include <vector>
using namespace std;
void getIPAddr(vector<string>& ipAddrs) { int fd; int interfaceNum = 0; struct ifreq buf[16]; struct ifconf ifc; struct ifreq ifrcopy; char ip[32] = {0};
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); close(fd); return; }
ifc.ifc_len = sizeof(buf); ifc.ifc_req = buf; if (!ioctl(fd, SIOCGIFCONF, (char *)&ifc)) { interfaceNum = ifc.ifc_len / sizeof(struct ifreq); while (interfaceNum-- > 0) { ifrcopy = buf[interfaceNum]; if (ioctl(fd, SIOCGIFFLAGS, &ifrcopy)) { printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__); close(fd); return; }
if (!ioctl(fd, SIOCGIFADDR, (char *)&buf[interfaceNum])) { snprintf(ip, sizeof(ip), "%s", (char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_addr))->sin_addr)); ipAddrs.push_back(string(ip)); } else { printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__); close(fd); return; } } } else { printf("ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__); close(fd); return; }
close(fd); }
int main() { vector<string> iplist; getIPAddr(iplist); cout << "get " << iplist.size() << " ip." << endl; int ipnum = iplist.size(); for (int i = 0; i < ipnum; i++) { string ip = iplist[i]; cout << "ip" << i << ": "; printf("%s\n", ip.c_str()); } return 0; }
|
以上代码通过ioctl
获得本机的ip,核心代码为:
1 2
| fd = socket(AF_INET, SOCK_DGRAM, 0); ioctl(fd, SIOCGIFADDR, (char *)&buf[interfaceNum]);
|
当ioctl
第二个参数为SIOCGIFADDR
,得到的结果就是ip地址。
Linux获得mac地址
下面是一种最常用的使用ioctl
获取mac地址的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include <stdio.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <netinet/in.h> #include <net/if.h> #include <string.h>
int main(int argc, char *argv[]) {
struct ifreq m_ifreq; int sock;
if(argc!=2) { printf("Usage: ethname\n "); return 1; } if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return 2; }
strcpy(m_ifreq.ifr_name,argv[1]); if(ioctl(sock, SIOCGIFHWADDR, &m_ifreq) < 0) { perror("ioctl"); return 3; } printf( "%02x:%02x:%02x:%02x:%02x:%02x\n", (unsigned char)m_ifreq.ifr_hwaddr.sa_data[0], (unsigned char)m_ifreq.ifr_hwaddr.sa_data[1], (unsigned char)m_ifreq.ifr_hwaddr.sa_data[2], (unsigned char)m_ifreq.ifr_hwaddr.sa_data[3], (unsigned char)m_ifreq.ifr_hwaddr.sa_data[4], (unsigned char)m_ifreq.ifr_hwaddr.sa_data[5]); return 0; }
|
获得mac地址的核心代码为:
1 2
| sock=socket(AF_INET, SOCK_STREAM, 0); ioctl(sock, SIOCGIFHWADDR, &m_ifreq);
|
获取到的mac地址放在结构体m_ifreq.ifr_hwaddr.sa_data
中。
QNX平台获取mac的方法
在QNX平台中,net/if.h
与linux下不同,ifreq
结构体的定义中不存在ifr_hwaddr
的成员,我估计ioctl
的实现方式也不同,因此上述方法不能使用。
这时应该转而使用ifaddrs.h
中的方法:getifaddrs
。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include <string.h> #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <ifaddrs.h> #ifdef __linux__ #include <arpa/inet.h> #include <netpacket/packet.h> #include <net/ethernet.h> #else #include <net/if_dl.h> #endif
int listmacaddrs(void) { struct ifaddrs *ifap, *ifaptr; unsigned char *ptr;
if (getifaddrs(&ifap) == 0) { for(ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) { #ifdef __linux__ char macp[INET6_ADDRSTRLEN]; if (((ifaptr)->ifa_addr)->sa_family == AF_PACKET) { struct sockaddr_ll *s = (struct sockaddr_ll*)(ifaptr->ifa_addr); int i; int len = 0; for (i = 0; i < 6; i++) { len += sprintf(macp+len, "%02X%s", s->sll_addr[i], i < 5 ? ":":""); } printf("%s: %s\n", (ifaptr)->ifa_name, macp); } #else if (((ifaptr)->ifa_addr)->sa_family == AF_LINK) { ptr = (unsigned char *)LLADDR((struct sockaddr_dl *)(ifaptr)->ifa_addr); printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n", (ifaptr)->ifa_name, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)); } #endif } freeifaddrs(ifap); return 1; } else { return 0; } }
|
使用getifaddrs(&ifap)
将mac地址与ip地址同时放到ifap
结构体中,该结构体的类型为ifaddrs
。
其核心代码为:
1 2 3 4 5 6
| struct ifaddrs *ifap, *ifaptr; getifaddrs(&ifap); for(ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) { ptr = (unsigned char *)LLADDR((struct sockaddr_dl *)(ifaptr)->ifa_addr); printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n", (ifaptr)->ifa_name, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)); }
|
ifaddrs::ifa_name
为网卡名,ifaddrs::ifa_addr
中存放mac地址。
通过getnameinfo
可获得ip地址,ip地址在host
中:
1
| s = getnameinfo(ifa->ifa_addr, (family == AF_INET)?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NUMERICHOST);
|
完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include <arpa/inet.h> #include <sys/socket.h> #include <netdb.h> #include <ifaddrs.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char *argv[]) { struct ifaddrs *ifaddr, *ifa; int family, s; char host[NI_MAXHOST]; if (getifaddrs(&ifaddr) == -1) { perror("getifaddrs"); exit(EXIT_FAILURE); }
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; family = ifa->ifa_addr->sa_family;
printf("%s address family: %d%s\n", ifa->ifa_name, family, (family == AF_PACKET) ? " (AF_PACKET)" : (family == AF_INET) ? " (AF_INET)" : (family == AF_INET6) ? " (AF_INET6)" : ""); if (family == AF_INET || family == AF_INET6) { s = getnameinfo(ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (s != 0) { printf("getnameinfo() failed: %s\n", gai_strerror(s)); exit(EXIT_FAILURE); } printf("\taddress: <%s>\n", host); } } freeifaddrs(ifaddr); exit(EXIT_SUCCESS); }
|
必须要注意的是getifaddrs
的调用必须与freeifaddrs
成对出现,如果不进行内存释放,会造成内存泄漏
参考资料
Linxu的struct ifaddrs与getifaddrs()函数:https://blog.csdn.net/g457499940/article/details/13630549
怎么得到带有getifaddrs的mac地址?:https://cloud.tencent.com/developer/ask/148099
Linux下的ioctl()函数详解:https://www.cnblogs.com/tdyizhen1314/p/4896689.html