一、getifaddrs简介
getifaddrs是一种系统级函数,可用于检索网络接口的地址信息。其定义在ifaddrs.h头文件中。该函数通过动态分配存储空间来保存设备地址列表。通常情况下,您需要使用freeifaddrs函数释放该列表。
struct ifaddrs {
struct ifaddrs *ifa_next; /* 下一个地址 */
char *ifa_name; /* 名称,任务类型,和类型信息 */
unsigned int ifa_flags; /* 属性 */
struct sockaddr *ifa_addr; /* 地址信息 */
struct sockaddr *ifa_netmask; /* 网络掩码 */
union {
struct sockaddr *ifu_broadaddr;
/* 广播地址 */
struct sockaddr *ifu_dstaddr;
/* 目标地址 */
} ifa_ifu;
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
void *ifa_data; /* 地址信息 */
};
二、使用getifaddrs函数
下面是使用getifaddrs函数的基本步骤:
1、定义一个ifaddrs类型指针,用于存储指向设备地址列表的第一个元素的指针。
2、调用getifaddrs函数,并将指向ifaddrs类型指针的指针传递给函数。
3、遍历设备地址列表,并执行所需操作。
4、最终执行freeifaddrs函数,以释放分配给设备地址列表的存储空间。
三、getifaddrs的特性
1、获取网络接口信息
使用getifaddrs函数可获取网络接口的信息,包括接口名称、IP地址、子网掩码等。此外,还可以轻松获取相关的网络接口的广播地址和目标地址。
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
family = ifa->ifa_addr->sa_family;
/* 显示地址族(针对IPV4和IPV6),IPV4地址和端口号,IPV6地址和端口号,并将地址存储在host数组中 */
if (family == AF_INET || family == AF_INET6) {
s = getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
host, NI_MAXHOST,
NULL, 0, NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("%s address: %s\n", ifa->ifa_name, host);
}
}
freeifaddrs(ifaddr);
2、实现TCP/IP Server / Client 套接字列表
使用getifaddrs函数,可以轻松实现TCP/IP服务器和客户端套接字列表。下面是实现TCP/IP服务器/客户端套接字列表的代码示例。
int sockfd, status, s, max_fds = 0;
struct addrinfo hints, *servinfo, *p;
struct ifaddrs *ifaddr, *ifa;
/* 获取可用地址列表 */
getifaddrs(&ifaddr);
/* 循环连接可用地址 */
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET) {
continue;
}
/* 定义TCP/IP Socket服务器地址 */
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; /* IPV4 */
hints.ai_socktype = SOCK_STREAM; /* 流套接字(比如TCP) */
hints.ai_flags = AI_PASSIVE; /* 意味着底层套接字地址将被用于bind调用中data */
/* 获取可用服务器地址 */
s = getaddrinfo(NULL, "8080", &hints, &servinfo);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
return -1;
}
/* 循环连接可用地址 */
for (p = servinfo; p != NULL; p = p->ai_next) {
/* 创建TCP/IP Socket */
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd < 0) {
continue;
}
/* 确认连接 */
status = connect(sockfd, p->ai_addr, p->ai_addrlen);
if (status < 0) {
close(sockfd);
continue;
}
/* 监听客户端 */
status = listen(sockfd, 10);
if (status < 0) {
close(sockfd);
continue;
}
/* 记录最大的文件描述符号码 */
max_fds = MAX(max_fds, sockfd);
}
/* free the list */
freeaddrinfo(servinfo);
}
freeifaddrs(ifaddr);
四、Getifaddrs崩溃
在使用getifaddrs时,一些安全漏洞可能导致崩溃。应该注意以下问题:
1、内存泄漏
必须使用freeifaddrs函数显式释放分配的内存。否则可能会导致内存泄漏。
2、缓冲区溢出
缓冲区溢出是指将输入数据存储在内存缓冲区之外的情况。这可能导致程序失败或崩溃。可以使用lwip中的替代方案lwip_getifaddrs避免此问题。
结论
getifaddrs是一种用于检索网络接口地址信息的系统级函数。通过动态分配存储空间来保存设备地址列表。使用该函数,您可以轻松实现TCP/IP服务器和客户端套接字列表、获取网络接口信息等。但是,在使用getifaddrs时,必须注意避免内存泄漏和缓冲区溢出引起的崩溃问题。