Accessing IP Address with NSHost

2019-01-18 07:40发布

I am trying to get the IP Address using NSHost. With the NSHost object I can use the addresses method to access an array of objects one of which is the IP Address. I fear though that the IP Address may change position in the array from one machine to the other. Is there a way to access this information in a universal way?

There was an attempt to answer this question in a previous post, but as you can see it falls short.

IP Address? - Cocoa

Here is my code:

+(NSString *) ipAddress {
    NSHost * h = [[[NSHost currentHost] addresses] objectAtIndex:1];
    return h ;  
}

7条回答
Root(大扎)
2楼-- · 2019-01-18 08:03

You can create a category on NSHost and do something like this:

#import <arpa/inet.h>
#import <ifaddrs.h>
#import <net/if.h>

.h

+ (NSDictionary *) interfaceIP4Addresses;
+ (NSDictionary *) interfaceIP6Addresses;
+ (NSDictionary *) interfaceIPAddresses;

.m

typedef NS_ENUM(NSUInteger, AddressType) {

    AddressTypeBoth     = 0,
    AddressTypeIPv4     = 1,
    AddressTypeIPv6     = 2
};

@implementation SomeClass

#pragma mark - Helper Methods:

+ (NSDictionary *) _interfaceAddressesForFamily:(AddressType)family {

    NSMutableDictionary *interfaceInfo = [NSMutableDictionary dictionary];
    struct ifaddrs *interfaces;

    if ( (0 == getifaddrs(&interfaces)) ) {

        struct ifaddrs *interface;

        for ( interface=interfaces; interface != NULL; interface=interface->ifa_next ) {

            if ( (interface->ifa_flags & IFF_UP) && !(interface->ifa_flags & IFF_LOOPBACK) ) {

                const struct sockaddr_in *addr = (const struct sockaddr_in *)interface->ifa_addr;

                if ( addr && addr->sin_family == PF_INET ) {

                    if ( (family == AddressTypeBoth) || (family == AddressTypeIPv4) ) {
                        char ip4Address[INET_ADDRSTRLEN];
                        inet_ntop( addr->sin_family, &(addr->sin_addr), ip4Address, INET_ADDRSTRLEN );

                        [interfaceInfo setObject:[NSString stringWithUTF8String:interface->ifa_name]
                                          forKey:[NSString stringWithUTF8String:ip4Address]];

                } } else if ( addr && addr->sin_family == PF_INET6 ) {

                    if ( (family == AddressTypeBoth) || (family == AddressTypeIPv6) ) {
                        char ip6Address[INET6_ADDRSTRLEN];
                        inet_ntop( addr->sin_family, &(addr->sin_addr), ip6Address, INET6_ADDRSTRLEN );

                        [interfaceInfo setObject:[NSString stringWithUTF8String:interface->ifa_name]
                                          forKey:[NSString stringWithUTF8String:ip6Address]];
                } }
            }

        } freeifaddrs( interfaces );

    } return [NSDictionary dictionaryWithDictionary:interfaceInfo];
}

#pragma mark - Class Methods:

+ (NSDictionary *) interfaceIP4Addresses { return [self _interfaceAddressesForFamily:AddressTypeIPv4]; }
+ (NSDictionary *) interfaceIP6Addresses { return [self _interfaceAddressesForFamily:AddressTypeIPv6]; }
+ (NSDictionary *) interfaceIPAddresses  { return [self _interfaceAddressesForFamily:AddressTypeBoth]; }

@end

This works really fast and well. If you need other info or to monitor then use System Configuration framework.

查看更多
登录 后发表回答