OC网络学习21:获取网络接口信息getifaddrs函数

张建 lol

前言

ip地址长度现在是有区别的,分为 IPv4IPv6IPv4 地址是类似 A.B.C.D 的格式,它是 32位,用 \".\" 分成 4段,用 10进制表示;而 IPv6 地址类似 X:X:X:X:X:X:X:X 的格式,它是 128位 的,用 \":\" 分成 8段,用 16进制 表示;可见,IPv6地址空间相对于IPv4地址有了极大的扩充

  • IPv4是32位地址长度

  • IPv6是128位地址长度

介绍

  • getifaddrs 函数,是一个用于 获取系统上网络接口信息的函数

  • inet_ntoa 函数,是一个用于将 32位的二进制数字IP地址 转换成 一个点分十进制的字符串形式的IP地址

getifaddrs 使用

  1. 第一步:包含头文件
1
#import <ifaddrs.h>

要使用 getifaddr 函数,首先需要在代码中包含头文件,该头文件包含 getifaddr 函数的定义即相关结构体的定义。

结构体定义:

1
2
3
4
5
6
7
8
9
struct ifaddrs {
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr;
struct sockaddr *ifa_netmask;
struct sockaddr *ifa_dstaddr;
void *ifa_data;
};

函数定义:

1
2
extern int getifaddrs(struct ifaddrs **);
extern void freeifaddrs(struct ifaddrs *);
  1. 第二步:调用 getifaddr 函数并检查返回值
1
extern int getifaddrs(struct ifaddrs **);
  • 参数是一个 结构体类型的指针,该函数通过该指针返回系统上所有网络接口的信息。

  • 返回 0 表示调用成功

  • 返回 非0 表示调用失败

因此,在调用前,我们需要定义一个 ifaddrs 类型的指针变量,并初始化为 NULL

1
2
// 定义 ifaddrs 类型的 指针变量,初始化为 NULL
struct ifaddrs * interfaces = NULL;

调用完成后,检查函数的返回值,如果成功,指针变量存储 的是一个 链表,该链表中存储了系统上所有网络接口信息

  1. 第三步:遍历链表获取网络接口信息

我们需要变量该链表,逐个获取每个网络接口的信息,每个网络接口在链表中对应一个 ifaddrs 类型的结构体,该结构体中存储了网络接口的 名称、地址、掩码等信息

  1. 第四步:释放内存

通过函数 freeifaddrs 释放内存

具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#import <ifaddrs.h>
#import <arpa/inet.h>
#include <netdb.h>
#import <net/if.h>

#define IOS_CELLULAR @"pdp_ip0" // 蜂窝数据
#define IOS_WIFI @"en0" // WIFI
#define IOS_VPN @"utun0" // VPN
#define IP_ADDR_IPv4 @"ipv4" // IPv4
#define IP_ADDR_IPv6 @"ipv6" // IPv6

// 获取Ip地址(字符串)
+ (NSString *)getIpAddressWithIsIPv4:(BOOL)IPv4{
NSArray * IPv4Arr = @[ IOS_VPN @"/" IP_ADDR_IPv4,
IOS_VPN @"/" IP_ADDR_IPv6,
IOS_WIFI @"/" IP_ADDR_IPv4,
IOS_WIFI @"/" IP_ADDR_IPv6,
IOS_CELLULAR @"/" IP_ADDR_IPv4,
IOS_CELLULAR @"/" IP_ADDR_IPv6 ];
NSArray * IPv6Arr = @[ IOS_VPN @"/" IP_ADDR_IPv6,
IOS_VPN @"/" IP_ADDR_IPv4,
IOS_WIFI @"/" IP_ADDR_IPv6,
IOS_WIFI @"/" IP_ADDR_IPv4,
IOS_CELLULAR @"/" IP_ADDR_IPv6,
IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;
NSArray * searchArray = IPv4 ? IPv4Arr : IPv6Arr;
NSDictionary * addresses = [self getIpAddress];
NSLog(@"addresses: %@", addresses);
__block NSString * address;
[searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop){
address = addresses[key];
if(address) * stop = YES;
}];
return address ? address : @"0.0.0.0";
}
// 获取所有相关IP信息(字典)
+ (NSDictionary *)getIpAddress{
NSMutableDictionary * addresses = [NSMutableDictionary dictionaryWithCapacity:8];
/**
lo 本地回环 (Loopback)
en 无线网 (WiFi)
pdp_ip 蜂窝网络 (Cellular)
awdl 通信Wi-Fi (Apple Wireless Direct Link,用于AirDrop、AirPlay、GameKit 和 Apple Pencil )
utun 虚拟隧道 (VPN)
ipsec 虚拟隧道 (VPN)
llw 低延迟无线局域网(Low-latency WLAN)
*/
// 定义 ifaddrs 类型的 指针变量,初始化为 NULL
struct ifaddrs * interfaces = NULL;
/*
getifaddrs:用于获取系统上网络接口信息的函数
包含头文件<ifaddrs.h>
struct ifaddrs ** : ifaddrs 类型的指针
返回 0 成功,非 0 出错
*/
int success = getifaddrs(&interfaces);
if(success) {
struct ifaddrs *interface;
for(interface = interfaces; interface; interface=interface->ifa_next) {
if(!(interface->ifa_flags & IFF_UP)) {
continue;
}
// 网络ip地址
const struct sockaddr_in * addr = (const struct sockaddr_in*)interface->ifa_addr;
// // 子网掩码
// struct sockaddr_in * netmask_addr = (const struct sockaddr_in *)interface->ifa_netmask;
char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
// IPv4 / IPv6
if(addr && (addr->sin_family == AF_INET || addr->sin_family == AF_INET6)) {
NSString * name = [NSString stringWithUTF8String:interface->ifa_name];
NSString * type;
NSString * netmask;
// 网络地址族
if(addr->sin_family == AF_INET) {
if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)){
type = IP_ADDR_IPv4;
}
// if (inet_ntoa(netmask_addr->sin_addr)) {
// netmask = [NSString stringWithUTF8String:inet_ntoa(netmask_addr->sin_addr)];;
// }
} else {
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
type = IP_ADDR_IPv6;
}
}
if(type) {
NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
addresses[key] = [NSString stringWithUTF8String:addrBuf];
}
}
}
// Free memory
freeifaddrs(interfaces);
}
return [addresses count] ? addresses : nil;
}

  • Post title:OC网络学习21:获取网络接口信息getifaddrs函数
  • Post author:张建
  • Create time:2023-07-27 09:15:02
  • Post link:https://redefine.ohevan.com/2023/07/27/OC网络/OC网络学习21:获取网络接口信息getifaddrs函数/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.
On this page
OC网络学习21:获取网络接口信息getifaddrs函数