linux C获取Mac地址
此处是通过设置ifr_name,然后通过ioctl获取mac地址,ifr_name一般是eth0或者ens33。无论是否联网都可以获取到,但是当程序运行在其他客户端,不可能要求用户那里的网卡名称也是eth0,所以此方法仅能用作本地测试,或者用命令行方式传入网卡名称,然后获取指定网卡名称的mac地址。可是ifconfig命令不是更好用更方便吗?ioctl调用SIOCGIFCONF只能获取到活动网卡,
1.基础用法,获取eth0的mac地址
#include <stdio.h>
#include <sys/ioctl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h> // struct ifreq
int get_mac(unsigned char binMAC[6])
{
int sock;
struct ifreq ifr;
unsigned char *puc;
memset(binMAC, 0, 6);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1)
{
perror("socket");
return -1;
}
strcpy(ifr.ifr_name, "eth0"); // 虚拟机中是ens33
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
{
close(sock);
perror("ioctl");
return -1;
}
puc = ifr.ifr_hwaddr.sa_data;
close(sock);
memcpy(binMAC, puc, 6);
return 0;
}
int main(){
unsigned char mac[6];
get_mac(mac);
printf("get_mac: %02x-%02X-%02X-%02X-%02X-%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
此处是通过设置ifr_name,然后通过ioctl获取mac地址,ifr_name一般是eth0或者ens33。无论是否联网都可以获取到,但是当程序运行在其他客户端,不可能要求用户那里的网卡名称也是eth0,所以此方法仅能用作本地测试,或者用命令行方式传入网卡名称,然后获取指定网卡名称的mac地址。可是ifconfig命令不是更好用更方便吗?
2.遍历活动网卡
#include <stdio.h>
#include <sys/ioctl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <net/if.h> // struct ifreq
int print_macs()
{
int sock;
int i = 0, ifCount = 0;
int code = 0;
struct ifreq ifr;
struct ifreq* it = NULL;
struct ifconf ifc;
unsigned char* pBuffer = NULL;
unsigned char *puc = NULL;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1)
{
perror("socket");
return -1;
}
pBuffer = (unsigned char*)malloc(3000);
ifc.ifc_len = 3000;
ifc.ifc_buf = pBuffer;
code = ioctl(sock, SIOCGIFCONF, &ifc);
printf("ioctl return %d, ifc_len:3000->%d, ifr size:%d\n", code, ifc.ifc_len, sizeof(struct ifreq));
if (code < 0)
{
free(pBuffer);
close(sock);
perror("ioctl");
return -1;
}
it = ifc.ifc_req;
ifCount = ifc.ifc_len/sizeof(struct ifreq);
for(i = 0; i < ifCount; ++i){
strcpy(ifr.ifr_name, it[i].ifr_name);
code = ioctl(sock, SIOCGIFFLAGS, &ifr);
printf("\n%d:%s:\n", i, ifr.ifr_name);
if(0 == code){
printf("flags:%x\n", ifr.ifr_flags);
}else{
printf("flagserror\n");
}
code = ioctl(sock, SIOCGIFHWADDR, &ifr);
if(0 == code){
puc = ifr.ifr_hwaddr.sa_data;
printf("mac:%02x-%02x-%02x-%02x-%02x-%02x\n", \
puc[0], puc[1], puc[2], puc[3], puc[4], puc[5]);
}else{
printf("mac:errrrrrrrr\n");
}
}
close(sock);
free(pBuffer);
return 0;
}
int main(){
print_macs();
}
ioctl调用SIOCGIFCONF只能获取到活动网卡,如果把ens33或者eth0的网络连接断开,就获取不到了。
3.参考ifconfig
经过方式1和2,只要能获取到网卡的名称就能获取到mac地址了,但是方式2获取不到无连接的网卡,方式1能获取mac地址却不能提前知道网卡名称。只能想着用其他方式获取网卡名称了。
查看了ifconfig的部分源码发现:
interface name是从/proc/net/dev中读取的。如虚拟机从该文件中读到了ens33,
address是从/sys/class/net/ens33/address中读取的,ens33是interface name,address是ens33的其中一个属性,ens33目录下还有多个其他文件。通过文件属性查看是一个symbol link,指向一个device。
小贴士:
ioctl参数:
man ioctl_list
man的输出窗口中输入/sock可以搜索到关键词sock,下面就是sock相关的ioctl的command
sock的ioctl参数主要是ifreq和ifconf
man netdevice可以看到两个结构体的定义
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)