问题描述
我想以编程方式获取我的 iPad 的 IP 地址.如何查询网络子系统以找出我的 IPv4(和 IPv6)地址?
I would like to obtain my iPad's IP address programmatically.How can I query the networking subsystem to find out what my IPv4 (and IPv6) addresses are?
PS:我可以以某种方式禁用 IPv6 吗?
PS: Can I disable IPv6 somehow?
推荐答案
以下代码查找 iOS 或 OSX 设备上的所有 IPv4 和 IPv6 地址.第一个 getIPAddress
方法或多或少作为此答案中的旧代码:您可以选择一种或另一种类型的地址,并且它始终更喜欢 WIFI 而非蜂窝网络(显然您可以更改此设置).
The following code finds all IPv4 and IPv6 addresses on an iOS or OSX device. The first getIPAddress
method acts more or less as the older code in this answer: you can prefer either one or the other type address, and it always prefers WIFI over cellular (obviously you could change this).
更有趣的是,它可以返回所有找到的地址的字典,跳过not up
接口的地址,或与loopback
关联的地址.之前的代码以及关于此主题的其他解决方案将无法正确解码 IPv6(inet_ntoa 无法处理它们).这是由 Jens Alfke 在 Apple 论坛上向我指出的 - 使用的正确函数是 inet_ntop(查看手册页,和/或参考这篇 inet_ntop 文章也由 Jens 提供.
More interestingly it can return a dictionary of all addresses found, skipping addresses for not up
interfaces, or addresses associated with loopback
. The previous code as well as other solutions on this topic will not properly decode IPv6 (inet_ntoa cannot deal with them). This was pointed out to me by Jens Alfke on an Apple forum - the proper function to use is inet_ntop (look at the man page, and or refer to this inet_ntop article also provided by Jens.
字典键的形式为interface"/"ipv4 or ipv6".
The dictionary keys have the form "interface" "/" "ipv4 or ipv6".
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>
#define IOS_CELLULAR @"pdp_ip0"
#define IOS_WIFI @"en0"
//#define IOS_VPN @"utun0"
#define IP_ADDR_IPv4 @"ipv4"
#define IP_ADDR_IPv6 @"ipv6"
- (NSString *)getIPAddress:(BOOL)preferIPv4
{
NSArray *searchArray = preferIPv4 ?
@[ /*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 ] :
@[ /*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 ] ;
NSDictionary *addresses = [self getIPAddresses];
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";
}
- (NSDictionary *)getIPAddresses
{
NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
// retrieve the current interfaces - returns 0 on success
struct ifaddrs *interfaces;
if(!getifaddrs(&interfaces)) {
// Loop through linked list of interfaces
struct ifaddrs *interface;
for(interface=interfaces; interface; interface=interface->ifa_next) {
if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
continue; // deeply nested code harder to read
}
const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
NSString *type;
if(addr->sin_family == AF_INET) {
if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
type = IP_ADDR_IPv4;
}
} 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;
}
代码于 2014 年 5 月 16 日更新(lhunath 指出的错误,请参阅评论).现在返回了环回地址,但您可以轻松取消对测试的注释以自行排除它们.
Code updated on May 16, 2014 (bug pointed out by lhunath, see comments). Loopback addresses now returned, but its easy for you to uncomment the test to exclude them yourself.
(由某个不知名的人提供):2015 年 3 月 13 日进一步改进:如果用户使用 VPN(无论是通过 WiFi 还是蜂窝网络),之前的代码都会失败.现在,它甚至适用于 VPN 连接.VPN 连接优先于 WiFi 和 Cell,因为这是设备处理它的方式.这甚至适用于 Mac,因为 Mac 上的 VPN 连接也使用 IF utun0 但未经测试.
(by some unknown person): Improved further March 13, 2015: In case the user uses a VPN (regardless over WiFi or Cellular), the previous code would have failed. Now, it works even with VPN connections. VPN connections are given precedence over WiFi and Cell because that's how the device handles it. This should even work for Macs as the VPN connection on a Mac is also using IF utun0 but not tested.
(2016 年 9 月 8 日)鉴于 @Qiulang(见评论)与 VPN 代码(其他人添加的)遇到的问题,我已将其注释掉.如果有人确切知道如何指定用户 VPN,请发表评论.
(9/8/2016) Given the problems experienced by @Qiulang (see comments) with the VPN code (which someone else added), I've commented it out. If anyone knows definitively how to specify a user VPN please chime in with a comment.
这篇关于如何在 iOS/macOS 上以编程方式获取我的 IP 地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!