一、getifaddrs簡介
getifaddrs是一種系統(tǒng)級函數(shù),可用于檢索網(wǎng)絡(luò)接口的地址信息。其定義在ifaddrs.h頭文件中。該函數(shù)通過動態(tài)分配存儲空間來保存設(shè)備地址列表。通常情況下,您需要使用freeifaddrs函數(shù)釋放該列表。
struct ifaddrs {
struct ifaddrs *ifa_next; /* 下一個地址 */
char *ifa_name; /* 名稱,任務(wù)類型,和類型信息 */
unsigned int ifa_flags; /* 屬性 */
struct sockaddr *ifa_addr; /* 地址信息 */
struct sockaddr *ifa_netmask; /* 網(wǎng)絡(luò)掩碼 */
union {
struct sockaddr *ifu_broadaddr;
/* 廣播地址 */
struct sockaddr *ifu_dstaddr;
/* 目標(biāo)地址 */
} ifa_ifu;
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
void *ifa_data; /* 地址信息 */
};
二、使用getifaddrs函數(shù)
下面是使用getifaddrs函數(shù)的基本步驟:
1、定義一個ifaddrs類型指針,用于存儲指向設(shè)備地址列表的第一個元素的指針。
2、調(diào)用getifaddrs函數(shù),并將指向ifaddrs類型指針的指針傳遞給函數(shù)。
3、遍歷設(shè)備地址列表,并執(zhí)行所需操作。
4、最終執(zhí)行freeifaddrs函數(shù),以釋放分配給設(shè)備地址列表的存儲空間。
三、getifaddrs的特性
1、獲取網(wǎng)絡(luò)接口信息
使用getifaddrs函數(shù)可獲取網(wǎng)絡(luò)接口的信息,包括接口名稱、IP地址、子網(wǎng)掩碼等。此外,還可以輕松獲取相關(guān)的網(wǎng)絡(luò)接口的廣播地址和目標(biāo)地址。
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數(shù)組中 */
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、實(shí)現(xiàn)TCP/IP Server / Client 套接字列表
使用getifaddrs函數(shù),可以輕松實(shí)現(xiàn)TCP/IP服務(wù)器和客戶端套接字列表。下面是實(shí)現(xiàn)TCP/IP服務(wù)器/客戶端套接字列表的代碼示例。
int sockfd, status, s, max_fds = 0;
struct addrinfo hints, *servinfo, *p;
struct ifaddrs *ifaddr, *ifa;
/* 獲取可用地址列表 */
getifaddrs(&ifaddr);
/* 循環(huán)連接可用地址 */
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服務(wù)器地址 */
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; /* IPV4 */
hints.ai_socktype = SOCK_STREAM; /* 流套接字(比如TCP) */
hints.ai_flags = AI_PASSIVE; /* 意味著底層套接字地址將被用于bind調(diào)用中data */
/* 獲取可用服務(wù)器地址 */
s = getaddrinfo(NULL, "8080", &hints, &servinfo);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
return -1;
}
/* 循環(huán)連接可用地址 */
for (p = servinfo; p != NULL; p = p->ai_next) {
/* 創(chuàng)建TCP/IP Socket */
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd < 0) {
continue;
}
/* 確認(rèn)連接 */
status = connect(sockfd, p->ai_addr, p->ai_addrlen);
if (status < 0) {
close(sockfd);
continue;
}
/* 監(jiān)聽客戶端 */
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時,一些安全漏洞可能導(dǎo)致崩潰。應(yīng)該注意以下問題:
1、內(nèi)存泄漏
必須使用freeifaddrs函數(shù)顯式釋放分配的內(nèi)存。否則可能會導(dǎo)致內(nèi)存泄漏。
2、緩沖區(qū)溢出
緩沖區(qū)溢出是指將輸入數(shù)據(jù)存儲在內(nèi)存緩沖區(qū)之外的情況。這可能導(dǎo)致程序失敗或崩潰。可以使用lwip中的替代方案lwip_getifaddrs避免此問題。
結(jié)論
getifaddrs是一種用于檢索網(wǎng)絡(luò)接口地址信息的系統(tǒng)級函數(shù)。通過動態(tài)分配存儲空間來保存設(shè)備地址列表。使用該函數(shù),您可以輕松實(shí)現(xiàn)TCP/IP服務(wù)器和客戶端套接字列表、獲取網(wǎng)絡(luò)接口信息等。但是,在使用getifaddrs時,必須注意避免內(nèi)存泄漏和緩沖區(qū)溢出引起的崩潰問題。