本文介绍了iPhone / iPad / OSX:如何以编程方式获取我的IP地址?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想以编程方式获取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吗?

Thanks.PS: Can I disable IPv6 somehow?

推荐答案

以下代码查找iOS上的所有IPv4和IPv6地址OSX设备。第一个 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).

更有趣的是,它可以返回找到的所有地址的字典,跳过的地址而不是接口或与 loopback 相关联的地址。以前的代码以及关于此主题的其他解决方案将无法正确解码IPv6(inet_ntoa无法处理它们)。在Apple论坛上指出了这一点 - 使用的正确函数是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或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;
}

EDIT1:代码于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.

EDIT2 :(由一些不知名的人):进一步改进2015年3月13日:如果用户使用VPN(无论是通过WiFi还是Cellular),以前的代码都会失败。现在,它甚至可以与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.

EDIT3:(9/8/2016)鉴于遇到的问题通过@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.

这篇关于iPhone / iPad / OSX:如何以编程方式获取我的IP地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 07:25