Доступ к IP-адресу с NSHost

Я пытаюсь получить IP-адрес с помощью NSHost, С NSHost объект Я могу использовать метод адресов для доступа к массиву объектов, одним из которых является IP-адрес. Я боюсь, что IP-адрес может изменить положение в массиве с одного компьютера на другой. Есть ли способ получить доступ к этой информации универсальным способом?

Была попытка ответить на этот вопрос в предыдущем посте, но, как вы можете видеть, он терпит неудачу.

Айпи адрес? - какао

Вот мой код:

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

7 ответов

Решение

Я использовал это на многих машинах без проблем.

 -(void) getIPWithNSHost{
    NSArray *addresses = [[NSHost currentHost] addresses];

for (NSString *anAddress in addresses) {
    if (![anAddress hasPrefix:@"127"] && [[anAddress componentsSeparatedByString:@"."] count] == 4) {
         stringAddress = anAddress;
        break;
    } else {
        stringAddress = @"IPv4 address not available" ;
    }
}
        //NSLog (@"getIPWithNSHost: stringAddress = %@ ",stringAddress);    

}

NSString * stringAddress; объявляется еще где

Единственное, о чем я могу думать, - это использовать что-то вроде " http://www.dyndns.org/cgi-bin/check_ip.cgi", другие могут найти лучший способ.

Это пример (т. Е. Быстро скомпонованный код)

NSUInteger  an_Integer;
NSArray * ipItemsArray;
NSString *externalIP;

NSURL *iPURL = [NSURL URLWithString:@"http://www.dyndns.org/cgi-bin/check_ip.cgi"];

if (iPURL) {
    NSError *error = nil;
    NSString *theIpHtml = [NSString stringWithContentsOfURL:iPURL 
                                                  encoding:NSUTF8StringEncoding 
                                                     error:&error];
    if (!error) {
                NSScanner *theScanner;
        NSString *text = nil;

        theScanner = [NSScanner scannerWithString:theIpHtml];

        while ([theScanner isAtEnd] == NO) {

                // find start of tag
            [theScanner scanUpToString:@"<" intoString:NULL] ; 

                // find end of tag
            [theScanner scanUpToString:@">" intoString:&text] ;

                // replace the found tag with a space
                //(you can filter multi-spaces out later if you wish)
            theIpHtml = [theIpHtml stringByReplacingOccurrencesOfString:
                    [ NSString stringWithFormat:@"%@>", text]
                                                   withString:@" "] ;
            ipItemsArray =[theIpHtml  componentsSeparatedByString:@" "];
            an_Integer=[ipItemsArray indexOfObject:@"Address:"];

                externalIP =[ipItemsArray objectAtIndex:  ++an_Integer];



        } 


            NSLog(@"%@",externalIP);
    } else {
        NSLog(@"Oops... g %d, %@", 
              [error code], 
              [error localizedDescription]);
    }
}




[pool drain];
return 0;}

Я хотел обновить свой первоначальный ответ при получении внешнего ip.

Не так много изменений, но я хотел показать, как получить и проанализировать HTML с использованием NSXMLDocument и Xquary

Это также дает небольшую иллюстрацию того, как вы можете анализировать HTML, получая узлы. Что, на мой взгляд, более прямолинейно. Хотя NSXMLDocument изначально предназначен для XML, он будет анализировать HTML-дерево DOM.

    NSString *externalIP;

    ///--DYNDNS.ORG  URL

    NSURL *iPURL = [NSURL URLWithString:@"http://www.dyndns.org/cgi-bin/check_ip.cgi"];
    if (iPURL) {

        NSError *err_p = nil;


        //--use NSXMLDocument to get the url:(*Requests NSXMLNode to preserve whitespace characters (such as tabs and carriage returns) in the XML source that are not part of node content*)
    NSXMLDocument * xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:iPURL
                                                                  options:(NSXMLNodePreserveWhitespace|
                                                                           NSXMLNodePreserveCDATA)
                                                                    error:&err_p];

    if (xmlDoc == nil) {

        //-- That did not work so lets see if we can change the malformed XML into valid XML during processing of the document.
        xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:iPURL
                                                      options:NSXMLDocumentTidyXML
                                                        error:&err_p];

    }


    if (!err_p) {
 NSError * error;
        //-- We will use XQuary to get the text from the child node. Dyndns.org page is very simple. So we just need to get the Body text.

    NSString *xpathQueryTR =  @"//body/text()";
        //-- we get the first node's string value. We use string value to in effect cast to NSString.
        //We the seperate the string into components using a space. and obtain the last object in the returned array.
        //--This gives us the IP string without the "Current IP Address:" string.
    externalIP = [[[[[xmlDoc nodesForXPath:xpathQueryTR error:&error]objectAtIndex:0] stringValue]componentsSeparatedByString:@" "]lastObject];

    if (!error) {

    NSLog(@"%@",externalIP);

    }else {
        NSLog(@"Oops... g %ld, %@",
              (long)[error code],
              [error localizedDescription]);
    }

    }else {
        NSLog(@"Oops... g %ld, %@",
              (long)[err_p code],
              [err_p localizedDescription]);
    }
}

Сделал служебный класс для поиска IP-адресов. Минималистичный подход. Вы можете сделать это с большим количеством условий или проверкой регулярных выражений.

 NSLog(@"Addresses: %@", [[NSHost currentHost] addresses]);

Это список, возвращаемый NSHost

 "fe80::1610:9fff:fee1:8c2f%en0",
 "192.168.212.61",
 "fe80::2829:3bff:fee6:9133%awdl0",
 "fe80::e54b:8494:bbc8:3989%utun0",
 "fd68:cc16:fad8:ded9:e54b:8494:bbc8:3989",
 "10.11.51.61",
 "::1",
 "127.0.0.1",
 "fe80::1%lo0"

Метод испытания,

- (void)testHost {
    NSLog(@"Addresses: %@", [[NSHost currentHost] addresses]);

    for (NSString *s in [[NSHost currentHost] addresses]) {
        IPAddress *addr = [[IPAddress alloc] initWithString:s];
        if (![addr isLocalHost] && [addr isIPV4]) {
            // do something
        }
    }
}

IPAddress.h

#import <Foundation/Foundation.h>

@interface IPAddress : NSObject

@property (nonatomic, strong) NSString *IPAddress;

- (id)initWithString:(NSString *)ipaddress;

- (BOOL)isLocalHost;
- (BOOL) isIPV4;
- (BOOL) isIPV6;

@end

IPAddress.m

#import "IPAddress.h"

@implementation IPAddress

- (id)initWithString:(NSString *)ipaddress {
    self = [super init];
    if (self) {
        self.IPAddress = ipaddress;
    }
    return self;
}

- (BOOL)isLocalHost {
    if (self.IPAddress == nil) return NO;
    if ([@"127.0.0.1" compare:self.IPAddress options:NSCaseInsensitiveSearch] == NSOrderedSame) {
        return YES;
    }

    if ([@"localhost" compare:self.IPAddress options:NSCaseInsensitiveSearch] == NSOrderedSame) {
        return YES;
    }

    if ([@"::1" compare:self.IPAddress options:NSCaseInsensitiveSearch] == NSOrderedSame) {
        return YES;
    }

    return NO;
}

- (BOOL) isIPV4 {
    NSArray *ar = [self.IPAddress componentsSeparatedByString:@"."];
    if (ar.count == 4) {
        return YES;
    }
    return NO;
}

- (BOOL) isIPV6 {
    if (![self isIPV4]) {
        if ([self.IPAddress rangeOfString:@":"].location != NSNotFound) {
            return YES;
        }
    }
    return NO;
}

@end

Как уже говорилось в ответах на вопрос, который вы упомянули выше, один компьютер может иметь различные IP-адреса. Если это то, что вы хотите, то вам может быть лучше использовать names метод NSHost для получения массива имен, который затем можно отфильтровать по суффиксу (то есть *.lan), чтобы получить имя хоста, который вы хотите с этим именем. В моем случае..lan адрес возвращает мой сетевой IP-адрес в виде точечного квадрата.

Если вы хотите найти внешний IP-адрес, то это хороший ответ.

Мой первый ответ - указать частный IP-адрес, назначенный устройству в частной сети, например, от вашего маршрутизатора.

Если вы хотите увидеть общедоступный IP-адрес, который стоит перед Интернетом. Обычно назначается вашим поставщиком услуг. Вы можете посмотреть на ответ Джима Голубя -> здесь

Я протестировал его, и он работал хорошо, но прочитал остальные комментарии и ответы, которые указывают на неясности в попытке получить публичный IP.

Вы можете создать категорию на NSHost и сделать что-то вроде этого:

#import <arpa/inet.h>
#import <ifaddrs.h>
#import <net/if.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

Это работает очень быстро и хорошо. Если вам нужна другая информация или для мониторинга, используйте платформу конфигурации системы.

Другие вопросы по тегам