本文介绍了如何在iOS/MacOS上以编程方式获取我的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吗?

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无法处理它们).这是由Apple论坛上的 Jens Alfke 指出的-正确使用的功能是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.

字典键的形式为接口""/""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;
}

代码已于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或蜂窝网络),则先前的代码将失败.现在,它甚至可以与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.

(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.

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

09-05 17:14
查看更多