常見 gethostname + gethostbyname 組合往往返回 127.0.0.1 或非預期介面 IP。需精確綁定指定網卡(如 eth0、ens33)的局域網 IPv4 地址。
getifaddrs 遍歷介面#include#include #include #include const char* get_interface_ipv4(const char *iface_name) { struct ifaddrs *ifaddr, *ifa; static char ip_str[INET_ADDRSTRLEN]; // 靜態緩衝區,線程不安全 if (getifaddrs(&ifaddr) == -1) return NULL; for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) continue; if (ifa->ifa_addr->sa_family != AF_INET) continue; // 僅 IPv4 if (strcmp(ifa->ifa_name, iface_name) != 0) continue; struct sockaddr_in *sa = (struct sockaddr_in*)ifa->ifa_addr; inet_ntop(AF_INET, &sa->sin_addr, ip_str, INET_ADDRSTRLEN); freeifaddrs(ifaddr); return ip_str; } freeifaddrs(ifaddr); return NULL; }
getifaddrs 獲取鏈表,需配對 freeifaddrs 釋放。ifa_addr->sa_family == AF_INET 過濾 IPv4(排除 IPv6/AF_PACKET 等)。inet_ntop 線程安全替代 inet_ntoa,支援 IPv6 擴展。#include#include #include #include #include int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } const char *ip = get_interface_ipv4(argv[1]); if (ip) printf("Interface %s IPv4: %s\n", argv[1], ip); else fprintf(stderr, "Interface not found or no IPv4 address\n"); return 0; }
gcc -o get_ip get_ip.c ./get_ip eth0 # 輸出:Interface eth0 IPv4: 192.168.1.100
| 場景 | 問題 | 對策 |
|---|---|---|
| 多 IP 別名 | eth0:1 視為獨立介面 | 精確匹配 ifa_name 或遍歷所有同前綴介面 |
| 容器/虛擬網卡 | 介面名不固定 | 配合 ip route get 8.8.8.8 解析出口介面 |
| 無權限 | 需 root 讀取 /proc/net | getifaddrs 通常無需特權 |
| Windows 移植 | 無 getifaddrs | 使用 GetAdaptersAddresses (IPHLPAPI) |