Linux实用功能代码集(1) —— 获得机器IP和MAC

Linux实用功能代码集(1) —— 获得机器IP和MAC 不管是在PC如Ubuntu还是嵌入式设备嵌入式Linux上经常需要获取本机IP和MAC。下边就给出实现此功能的代码并进行一定讲解。代码如下#include stdio.h #include stdlib.h #include string.h #include unistd.h #include fcntl.h #include sys/socket.h #include sys/ioctl.h #include net/if.h #include arpa/inet.h int get_ip_by_ifname(const char *ifname, char *ip_buf, int buf_len) { int sockfd -1; struct ifreq ifr; struct sockaddr_in *sin; if (!ifname || !ip_buf) { printf(parameter cant be null\n); return -1; } sockfd socket(AF_INET, SOCK_DGRAM, 0); if (sockfd 0) { perror(socket failed); return -1; } strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFADDR, ifr) 0) { perror(ioctl SIOCGIFADDR failed); close(sockfd); return -1; } sin (struct sockaddr_in *)ifr.ifr_addr; strncpy(ip_buf, inet_ntoa(sin-sin_addr), buf_len - 1); close(sockfd); return 0; } int get_mac_by_ifname(const char *ifname, char *mac_buf, int buf_len) { int sockfd -1; struct ifreq ifr; unsigned char *mac NULL; if (!ifname || !mac_buf) { printf(parameter cant be null\n); return -1; } sockfd socket(AF_INET, SOCK_DGRAM, 0); if (sockfd 0) { perror(socket failed); return -1; } strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFHWADDR, ifr) 0) { perror(ioctl SIOCGIFHWADDR failed); close(sockfd); return -1; } mac (unsigned char *)ifr.ifr_hwaddr.sa_data; snprintf(mac_buf, buf_len, %02x:%02x:%02x:%02x:%02x:%02x, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); close(sockfd); return 0; } int main(int argc, char *argv[]) { int ret; //ip char ip_addr[32] {0}; //ret get_ip_by_ifname(eth0, ip_addr, sizeof(ip_addr)); ret get_ip_by_ifname(ens33, ip_addr, sizeof(ip_addr)); if (!ret) printf(ip is: %s\n, ip_addr); //mac char mac_addr[32] {0}; //ret get_mac_by_ifname(eth0, mac_addr, sizeof(mac_addr)); ret get_mac_by_ifname(ens33, mac_addr, sizeof(mac_addr)); if (!ret) printf(mac is: %s\n, mac_addr); return 0; }main函数中分为了两部分获取IP地址这通过get_ip_by_ifname函数实现获取MAC地址这通过get_mac_by_if_name函数实现。下边依次对这两个函数进行讲解。get_ip_by_ifname函数get_ip_by_name函数主要步骤如下1创建socket代码片段如下sockfd socket(AF_INET, SOCK_DGRAM, 0); if (sockfd 0) { perror(socket failed); return -1; }此步骤的功能是创建一个IPv4的UDP套接字。2获取IP地址并赋值给函数参数代码片段如下strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFADDR, ifr) 0) { perror(ioctl SIOCGIFADDR failed); close(sockfd); return -1; } sin (struct sockaddr_in *)ifr.ifr_addr; strncpy(ip_buf, inet_ntoa(sin-sin_addr), buf_len - 1);通过SIOCGIFADDR这一ioctl告诉内核需要获取IP。通过ifr.ifr_name指明需要获取哪个网卡的IP地址。ioctl调用后内核会把IP地址写入ifr.ifr_addr。将获得的IP地址通过strncpy函数拷贝给函数参数ip_buf。3关闭socket代码片段如下close(sockfd);get_mac_by_ifname函数其实get_mac_by_ifname函数和get_ip_by_ifname函数流程基本一致。只是第2步不同。2获取MAC地址并赋值给函数参数代码片段如下strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFHWADDR, ifr) 0) { perror(ioctl SIOCGIFHWADDR failed); close(sockfd); return -1; } mac (unsigned char *)ifr.ifr_hwaddr.sa_data; snprintf(mac_buf, buf_len, %02x:%02x:%02x:%02x:%02x:%02x, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);通过SIOCGIFHWADDR这一ioctl告诉内核需要获取MAC。通过ifr.ifr_name指明需要获取哪个网卡的MAC地址。ioctl调用后内核会把IP地址写入ifr.ifr_hwaddr中。将获得的MAC地址通过sprintf函数赋值给函数参数mac_buf。注1get_mac_by_ifname和get_ip_by_ifname中的代码完全可以合在一起无需创建两个socket。笔者这样写是为了功能独立以及便于理解。2对于Ubuntu来说网卡名称一般为ens33对于嵌入式Linux来说则仍一般是传统的eth0。这里也给出相关的ioctlioctl(sockfd, SIOCGIFADDR, ifr); // 获取IPioctl(sockfd, SIOCGIFHWADDR, ifr);// 获取MACioctl(sockfd, SIOCGIFNETMASK, ifr); // 获取子网掩码ioctl(sockfd, SIOCGIFBRDADDR, ifr); // 获取广播地址对以上代码进行编译实际命令及结果如下笔者的环境为VMWare虚拟机Ubuntu20.04$ gcc get_ip_mac.c -o get_ip_mac $实际执行结果为$ ./get_ip_mac ip is: 192.168.163.128 mac is: 00:0c:29:23:93:a0与执行ifconfig ens33命令结果一致$ ifconfig ens33: flags4163UP,BROADCAST,RUNNING,MULTICAST mtu 1500 inet 192.168.163.128 netmask 255.255.255.0 broadcast 192.168.163.255 inet6 fe80::dbbe:2936:42b0:1c73 prefixlen 64 scopeid 0x20link ether 00:0c:29:23:93:a0 txqueuelen 1000 (Ethernet) RX packets 182822 bytes 145203754 (145.2 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 114094 bytes 42758976 (42.7 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags73UP,LOOPBACK,RUNNING mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10host loop txqueuelen 1000 (Local Loopback) RX packets 20166 bytes 2886087 (2.8 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 20166 bytes 2886087 (2.8 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0$ ifconfig ens33 ens33: flags4163UP,BROADCAST,RUNNING,MULTICAST mtu 1500 inet 192.168.163.128 netmask 255.255.255.0 broadcast 192.168.163.255 inet6 fe80::dbbe:2936:42b0:1c73 prefixlen 64 scopeid 0x20link ether 00:0c:29:23:93:a0 txqueuelen 1000 (Ethernet) RX packets 182824 bytes 145203893 (145.2 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 114097 bytes 42759194 (42.7 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0完整工程代码已上传至Linux下获取IP和MAC的实用代码资源-CSDN下载。