Доступ к 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
Это работает очень быстро и хорошо. Если вам нужна другая информация или для мониторинга, используйте платформу конфигурации системы.