在 Linux 系統編程中,獲取本機所有網卡的 IP 地址、介面名稱與運行狀態(UP/DOWN/PROMISC)是網路工具、監控代理、容器網路組件的基礎需求。本文提供一個完整、可編譯的 C++ 類封裝,使用 `ioctl` + `SIOCGIFCONF` / `SIOCGIFFLAGS` / `SIOCGIFADDR` 實現,無第三方依賴。
#define MAX_INTERFACES 16
enum IfStatus { UNKNOWN, PROMISC, UP, RUNNING, DOWN };
struct IfInfo {
char name[IFNAMSIZ]; // 介面名稱,如 "eth0"
char address[INET_ADDRSTRLEN]; // IPv4 地址字串
IfStatus status;
};
class IfConfig {
public:
IfInfo interfaces[MAX_INTERFACES];
int count = 0;
};
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int getLocalHostAddress(IfConfig &cfg) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) { perror("socket"); return -1; }
struct ifreq ifr[MAX_INTERFACES];
struct ifconf ifc;
ifc.ifc_len = sizeof(ifr);
ifc.ifc_buf = (caddr_t)ifr;
// 1. 獲取介面列表
if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
perror("SIOCGIFCONF");
close(sock);
return -1;
}
int num = ifc.ifc_len / sizeof(struct ifreq);
for (int i = 0; i < num && cfg.count < MAX_INTERFACES; ++i) {
// 2. 獲取介面標誌 (UP/BROADCAST/RUNNING/PROMISC...)
if (ioctl(sock, SIOCGIFFLAGS, &ifr[i]) < 0) continue;
strncpy(cfg.interfaces[cfg.count].name, ifr[i].ifr_name, IFNAMSIZ-1);
unsigned short flags = ifr[i].ifr_flags;
if (flags & IFF_PROMISC) cfg.interfaces[cfg.count].status = PROMISC;
else if (flags & IFF_UP) cfg.interfaces[cfg.count].status = UP;
else if (flags & IFF_RUNNING) cfg.interfaces[cfg.count].status = RUNNING;
else cfg.interfaces[cfg.count].status = DOWN;
// 3. 獲取 IPv4 地址
if (ioctl(sock, SIOCGIFADDR, &ifr[i]) == 0) {
struct sockaddr_in* sin = (struct sockaddr_in*)&ifr[i].ifr_addr;
inet_ntop(AF_INET, &sin->sin_addr,
cfg.interfaces[cfg.count].address, INET_ADDRSTRLEN);
} else {
strcpy(cfg.interfaces[cfg.count].address, "0.0.0.0");
}
cfg.count++;
}
close(sock);
return cfg.count;
}
int main() {
IfConfig cfg;
int n = getLocalHostAddress(cfg);
for (int i = 0; i < n; ++i) {
printf("[%d] %-8s %-15s %s\n", i,
cfg.interfaces[i].name,
cfg.interfaces[i].address,
(cfg.interfaces[i].status == UP) ? "UP" :
(cfg.interfaces[i].status == RUNNING) ? "RUNNING" :
(cfg.interfaces[i].status == PROMISC) ? "PROMISC" : "DOWN");
}
return 0;
}
g++ -std=c++11 -o get_if get_if.cpp
./get_if
[0] lo 127.0.0.1 UP [1] eth0 192.168.1.100 RUNNING [2] docker0 172.17.0.1 UP
| 需求 | 方案 |
|---|---|
| IPv6 地址 | `AF_INET6` + `SIOCGIFADDR` + `inet_ntop(AF_INET6, ...)` |
| 硬體地址 (MAC) | `SIOCGIFHWADDR` + `ifr.ifr_hwaddr.sa_data` |
| MTU | `SIOCGIFMTU` |
| 流量統計 | 讀取 `/proc/net/dev` 或 `rtnetlink` (NETLINK) |
| 動態變更通知 | `NETLINK_ROUTE` + `RTM_NEWLINK`/`RTM_DELLINK`/`RTM_NEWADDR` |
| 跨平台 (Windows) | `GetAdaptersAddresses` (IPHLPAPI) / `WSAIoctl(SIO_GET_INTERFACE_LIST)` |