在Linux环境下使用C语言获取网络接口的MAC地址是网络编程中的常见需求,MAC地址作为网络设备的物理地址,在数据链路层通信中扮演着重要角色,本文将详细介绍几种在Linux C程序中获取MAC地址的方法,包括通过sysfs文件系统、ioctl系统调用以及解析网络接口配置文件等技术手段,并提供完整的代码示例和注意事项。

通过sysfs文件系统获取MAC地址
Linux内核通过sysfs虚拟文件系统导出了网络设备的详细信息,其中MAC地址存储在/sys/class/net/<interface>/address文件中,这种方法简单高效,无需特殊权限,是获取MAC地址的首选方式,以下是具体实现步骤:
- 打开指定网络接口的address文件,例如
/sys/class/net/eth0/address - 读取文件内容,MAC地址以十六进制字符串形式存储,每两个字符间用冒号分隔
- 关闭文件句柄
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int get_mac_via_sysfs(const char *interface, char *mac_addr) {
char path[128];
FILE *fp;
char buffer[18]; // MAC地址最大长度:17字符+1个终止符
snprintf(path, sizeof(path), "/sys/class/net/%s/address", interface);
fp = fopen(path, "r");
if (fp == NULL) {
perror("Failed to open sysfs file");
return -1;
}
if (fgets(buffer, sizeof(buffer), fp) == NULL) {
perror("Failed to read MAC address");
fclose(fp);
return -1;
}
fclose(fp);
// 去除可能的换行符
buffer[strcspn(buffer, "\n")] = '\0';
strcpy(mac_addr, buffer);
return 0;
}
使用ioctl系统调用获取MAC地址
ioctl是另一种传统方法,通过套接字与网络设备驱动交互获取硬件地址,这种方法需要root权限或适当的 capabilities,适用于需要直接访问网络设备的场景。
实现步骤如下:

- 创建套接字(通常使用AF_INET或AF_PACKET)
- 准备ifreq结构体,指定网络接口名称
- 调用ioctl命令SIOCGIFHWADDR获取硬件地址
- 从ifreq结构体中提取MAC地址
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
int get_mac_via_ioctl(const char *interface, unsigned char *mac_addr) {
int sockfd;
struct ifreq ifr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket creation failed");
return -1;
}
strncpy(ifr.ifr_name, interface, IFNAMSIZ - 1);
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
perror("ioctl failed");
close(sockfd);
return -1;
}
memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, 6);
close(sockfd);
return 0;
}
解析网络接口配置文件
对于不需要实时获取MAC地址的场景,可以解析/proc/net/if_inet6或/proc/net/dev等系统文件,这种方法不需要特殊权限,但解析过程相对复杂,且可能因内核版本不同而有所差异。
以下是解析/proc/net/if_inet6的示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int get_mac_from_proc(const char *interface, char *mac_addr) {
FILE *fp;
char line[256];
char if_name[16];
unsigned char addr[6];
int found = 0;
fp = fopen("/proc/net/if_inet6", "r");
if (fp == NULL) {
perror("Failed to open /proc/net/if_inet6");
return -1;
}
while (fgets(line, sizeof(line), fp)) {
if (sscanf(line, "%*2x%*2x%*2x%*2x%*2x%*2x%*2x%*2x %*2x%*2x%*2x%*2x %*2x%*2x %*2x %*15s %15s",
if_name) == 1) {
if (strcmp(if_name, interface) == 0) {
found = 1;
break;
}
}
}
fclose(fp);
if (!found) {
fprintf(stderr, "Interface %s not found\n", interface);
return -1;
}
// 注意:此方法仅演示文件解析,实际MAC地址获取需要更复杂的处理
// 实际应用中建议优先使用sysfs或ioctl方法
return 0;
}
方法比较与选择
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| sysfs文件系统 | 简单高效,无需特殊权限 | 依赖sysfs挂载 | 现代Linux系统,推荐首选 |
| ioctl系统调用 | 功能强大,可获取更多信息 | 需要root权限 | 需要直接访问网络设备的场景 |
| 解析系统文件 | 无需权限,兼容性好 | 解析复杂,可能受内核版本影响 | 简单脚本或不需要实时性的场景 |
注意事项
- 权限问题:ioctl方法通常需要root权限,而sysfs方法对普通用户可读
- 错误处理:实际应用中应完善错误处理机制,检查接口是否存在、文件是否可读等
- 多线程安全:确保在多线程环境中正确使用文件描述符和互斥锁
- 接口名称:网络接口名称可能因系统配置而异(如eth0、ens33、wlan0等)
- 虚拟接口:某些虚拟接口可能没有真实的MAC地址
完整示例程序
以下是一个结合sysfs和ioctl方法的完整示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#define MAC_ADDR_LEN 18
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <interface>\n", argv[0]);
return EXIT_FAILURE;
}
char mac_str[MAC_ADDR_LEN];
unsigned char mac_bin[6];
// 尝试使用sysfs方法
if (get_mac_via_sysfs(argv[1], mac_str) == 0) {
printf("MAC via sysfs: %s\n", mac_str);
} else {
printf("sysfs method failed, trying ioctl...\n");
// 回退到ioctl方法
if (get_mac_via_ioctl(argv[1], mac_bin) == 0) {
for (int i = 0; i < 6; i++) {
printf("%02x", mac_bin[i]);
if (i < 5) printf(":");
}
printf("\n");
} else {
fprintf(stderr, "Failed to get MAC address for %s\n", argv[1]);
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
通过以上方法,开发者可以根据实际需求选择最适合的技术方案获取网络接口的MAC地址,在实际开发中,建议优先使用sysfs方法,既简单又安全,只有在需要特殊功能时才考虑ioctl等其他方法。


















