可以直接使用getifaddrs()函数。以下是一个示例:
#include <arpa/inet.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdio.h>
int main ()
{
struct ifaddrs *ifap, *ifa;
struct sockaddr_in *sa;
char *addr;
getifaddrs (&ifap);
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr && ifa->ifa_addr->sa_family==AF_INET) {
sa = (struct sockaddr_in *) ifa->ifa_addr;
addr = inet_ntoa(sa->sin_addr);
printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr);
}
}
freeifaddrs(ifap);
return 0;
}
以下是我在我的电脑上得到的输出:
Interface: lo Address: 127.0.0.1
Interface: eth0 Address: 69.72.234.7
Interface: eth0:1 Address: 10.207.9.3
以下是一些可能对您有所帮助的Linux示例代码。
#include <stdio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#define INT_TO_ADDR(_addr) \
(_addr & 0xFF), \
(_addr >> 8 & 0xFF), \
(_addr >> 16 & 0xFF), \
(_addr >> 24 & 0xFF)
int main()
{
struct ifconf ifc;
struct ifreq ifr[10];
int sd, ifc_num, addr, bcast, mask, network, i;
/* Create a socket so we can use ioctl on the file
* descriptor to retrieve the interface info.
*/
sd = socket(PF_INET, SOCK_DGRAM, 0);
if (sd > 0)
{
ifc.ifc_len = sizeof(ifr);
ifc.ifc_ifcu.ifcu_buf = (caddr_t)ifr;
if (ioctl(sd, SIOCGIFCONF, &ifc) == 0)
{
ifc_num = ifc.ifc_len / sizeof(struct ifreq);
printf("%d interfaces found\n", ifc_num);
for (i = 0; i < ifc_num; ++i)
{
if (ifr[i].ifr_addr.sa_family != AF_INET)
{
continue;
}
/* display the interface name */
printf("%d) interface: %s\n", i+1, ifr[i].ifr_name);
/* Retrieve the IP address, broadcast address, and subnet mask. */
if (ioctl(sd, SIOCGIFADDR, 𝔦[i]) == 0)
{
addr = ((struct sockaddr_in *)(𝔦[i].ifr_addr))->sin_addr.s_addr;
printf("%d) address: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(addr));
}
if (ioctl(sd, SIOCGIFBRDADDR, 𝔦[i]) == 0)
{
bcast = ((struct sockaddr_in *)(𝔦[i].ifr_broadaddr))->sin_addr.s_addr;
printf("%d) broadcast: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(bcast));
}
if (ioctl(sd, SIOCGIFNETMASK, 𝔦[i]) == 0)
{
mask = ((struct sockaddr_in *)(𝔦[i].ifr_netmask))->sin_addr.s_addr;
printf("%d) netmask: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(mask));
}
/* Compute the current network value from the address and netmask. */
network = addr & mask;
printf("%d) network: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(network));
}
}
close(sd);
}
return 0;
}
ioctl
和 getifaddrs
。 - Youda008ioctl
可能会更具可移植性。它在大多数Unix和类Unix系统上都得到支持,并且ioctl
函数调用最初出现在Version 7 AT&T UNIX中。我相信getifaddrs
在BSD和Linux上得到支持,并且最初出现在glibc 2.3中。 - jschmierhtonl()
/ntohl()
函数,而不是自定义的 INT_TO_ADDR
宏。 - Matthieu使用getifaddrs()解决方案非常好。我建议只有一个改进:
--- chrisaycock
+++ normando
@@ -11,7 +11,7 @@
getifaddrs (&ifap);
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr->sa_family==AF_INET) {
+ if (ifa->ifa_addr && ifa->ifa_addr->sa_family==AF_INET) {
sa = (struct sockaddr_in *) ifa->ifa_addr;
addr = inet_ntoa(sa->sin_addr);
printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr);
因为我自己遇到了分段错误。
请参考另一个Stack Overflow问题:列举分配给网络接口的每个IP地址。
总之,你可以使用以下方法:
ioctl(SIOCGIFCONF)
-> 传统的ioctlgetifaddrs()
-> 来自BSDi,现在也适用于Linux和BSD。struct ifreq ifr[MAX_INTERFACES];
struct ifconf ifc;
memset(ifr, 0, sizeof(ifr));
ifc.ifc_len = sizeof(ifr);
ifc.ifc_req = ifr;
// Get the list of interfaces
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) {
fprintf(stderr, "ioctl SIOCGIFCONF failed: %d", errno);
}
struct ifreq *ifr_iterator = ifc.ireq;
int i = 0;
size_t len;
while (i < ifc.ifc_len) {
/* DO STUFF */
// Maybe some more filtering based on SIOCGIFFLAGS
// Your code
// Use ifr_iterator-> ...
len = IFNAMSIZ + ifr_iterator->ifr_addr.sa_len;
ifr_iterator = (struct ifreq *)((char *)ifr_iterator + len);
i += len;
}
ifc.ifc_len/sizeof(struct ifreq)
就可以给你接口数量。相反,你需要像这样迭代列表中的元素:struct ifreq *ifr_iterator = ifc.ireq; size_t len; while (i < ifc.ifc_len) { /* DO STUFF */ len = IFNAMSIZ + ifr_iterator->ifr_addr.sa_len; ifr_iterator = (struct ifreq *)((char *)ifr_iterator + len); i += len; }
- Joakim#define ifc_req ifc_ifcu.ifcu_req /* array of structures ret'd */
从技术上讲不是一个数组,因为大小是可变的?看起来5.9版本添加了更多的东西。此外,ifconfig.c代码似乎没有SIOCGIFCONF。 - GorillaApe如果您还需要IP6地址,您可以像这样扩展接受的答案:
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <netdb.h>
int main() {
struct ifaddrs *ifap;
getifaddrs(&ifap);
for (struct ifaddrs *ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr && (ifa->ifa_addr->sa_family == AF_INET6)) {
char addr[INET6_ADDRSTRLEN];
getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr, sizeof(addr), NULL, 0, NI_NUMERICHOST);
printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr);
} else if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *sa = (struct sockaddr_in *)ifa->ifa_addr;
char *addr = inet_ntoa(sa->sin_addr);
printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr);
}
}
freeifaddrs(ifap);
return 0;
}
stdio.h
行下面添加了一个新的头文件行 "#include <stdlib.h>
",并用这一行 "if (getifaddrs(&ifap) == -1) { perror("getifaddrs"); exit(1); }
" 替换了这一行 "getifaddrs (&ifap);
"。如果没有前面的两行更改,如果 "ifa_addr" 有一个空指针,则会创建分段错误。这些更改受到 Michael-Hampton 在此处显示的代码的启发:https://stackoverflow.com/a/27433320/3553808。这段代码在 macOS(10.15.x/Catalina)上运行良好。 - atErik