简体   繁体   English

iPhone:Bonjour NSNetService IP地址和端口

[英]iPhone: Bonjour NSNetService IP address and port

Excuse my iPhone/Objective-C newbie status please! 请原谅我的iPhone / Objective-C新手状态!

I've found my HTTP server using NSNetServiceBrowser, but now I just want the IP address and port of the service found. 我发现我的HTTP服务器使用NSNetServiceBrowser,但现在我只想要找到服务的IP地址和端口。

I've got something like the following in my delegate method: 我的委托方法中有以下内容:

NSNetService* server = [serverBrowser.servers objectAtIndex:0];

NSString            *name = nil;
NSData              *address = nil;
struct sockaddr_in  *socketAddress = nil;
NSString            *ipString = nil;
int                 port;
uint                 i;
for (i = 0; i < [[server addresses] count]; i++)
{
    name = [server name];
    address = [[server addresses] objectAtIndex:i];
    socketAddress = (struct sockaddr_in *)
    [address bytes];
    ipString = [NSString stringWithFormat: @"%s",
                inet_ntoa (socketAddress->sin_addr)];
    port = socketAddress->sin_port;
    NSLog(@"Server found is %s %d",ipString,port);
}

but the for loop is never entered, even though the delegate is called. 但是,即使调用了委托,也永远不会输入for循环。 Any ideas? 有任何想法吗? Thanks! 谢谢!

I realize this is an old thread, but I've just run across this as well. 我意识到这是一个老线程,但我也遇到了这个问题。 There are a few problems with the code above: 上面的代码有一些问题:

  1. It's not IPv6 savvy. 这不是IPv6的精明。 At a minimum, it should detect and discard IPv6 addresses if the rest of your app can only handle v4 addresses, but ideally you should be prepared to pass both address families upstream. 如果应用程序的其余部分只能处理v4地址,它至少应该检测并丢弃IPv6地址,但理想情况下,您应该准备好在上游传递两个地址系列。

  2. The port assignment will generate incorrect values for Intel processors. 端口分配将为Intel处理器生成不正确的值。 You need to use htons to fix that. 您需要使用htons来修复它。

  3. As Andrew noted above, the iteration should use the enhanced for loop. 正如安德鲁上面提到的,迭代应该使用增强的for循环。

  4. (EDIT: Added this) As noted on another related thread, the use of inet_ntoa is discouraged in favor of inet_ntop . (编辑:添加了这个)如另一个相关主题所述,不鼓励使用inet_ntoa来支持inet_ntop

Putting all of this together, you get: 把所有这些放在一起,你得到:

char addressBuffer[INET6_ADDRSTRLEN];

for (NSData *data in self.addresses)
{
    memset(addressBuffer, 0, INET6_ADDRSTRLEN);

    typedef union {
        struct sockaddr sa;
        struct sockaddr_in ipv4;
        struct sockaddr_in6 ipv6;
    } ip_socket_address;

    ip_socket_address *socketAddress = (ip_socket_address *)[data bytes];

    if (socketAddress && (socketAddress->sa.sa_family == AF_INET || socketAddress->sa.sa_family == AF_INET6))
    {
        const char *addressStr = inet_ntop(
                socketAddress->sa.sa_family,
                (socketAddress->sa.sa_family == AF_INET ? (void *)&(socketAddress->ipv4.sin_addr) : (void *)&(socketAddress->ipv6.sin6_addr)),
                addressBuffer,
                sizeof(addressBuffer));

        int port = ntohs(socketAddress->sa.sa_family == AF_INET ? socketAddress->ipv4.sin_port : socketAddress->ipv6.sin6_port);

        if (addressStr && port)
        {
            NSLog(@"Found service at %s:%d", addressStr, port);
        }
    }
}

The NSNetService you get back in the callback isn't ready to be used. 您在回调中返回的NSNetService尚未准备好使用。 You have to call the following method to get addresses for it: 您必须调用以下方法来获取它的地址:

- (void)resolveWithTimeout:(NSTimeInterval)timeout;

Implement the NSNetService delegate method to find out when it resolves: 实现NSNetService委托方法以找出它何时解析:

- (void)netServiceDidResolveAddress:(NSNetService *)sender;

At that point, there should be at least one address in the service. 此时,服务中至少应有一个地址。

Also, take care to read the documentation and the header file carefully! 另外,请仔细阅读文档和头文件! There is some complexity to the issue here that I've glossed over. 这里的问题有些复杂,我已经掩饰了。

Remix of the accepted answer in a category: 在一个类别中混合接受的答案:

NSNetService+Util.h NSNetService + Util.h

#import <Foundation/Foundation.h>

@interface NSNetService (Util)

- (NSArray*) addressesAndPorts;

@end


@interface AddressAndPort : NSObject 

@property (nonatomic, assign) int port;
@property (nonatomic, strong)  NSString *address;

@end

NSNetService+Util.m NSNetService + Util.m

#import "NSNetService+Util.h"
#include <arpa/inet.h>

@implementation NSNetService (Util)

- (NSArray*) addressesAndPorts {

    // this came from http://stackoverflow.com/a/4976808/8047
    NSMutableArray *retVal = [NSMutableArray array];
    char addressBuffer[INET6_ADDRSTRLEN];

    for (NSData *data in self.addresses)
    {
        memset(addressBuffer, 0, INET6_ADDRSTRLEN);

        typedef union {
            struct sockaddr sa;
            struct sockaddr_in ipv4;
            struct sockaddr_in6 ipv6;
        } ip_socket_address;

        ip_socket_address *socketAddress = (ip_socket_address *)[data bytes];

        if (socketAddress && (socketAddress->sa.sa_family == AF_INET || socketAddress->sa.sa_family == AF_INET6))
        {
            const char *addressStr = inet_ntop(
                                               socketAddress->sa.sa_family,
                                               (socketAddress->sa.sa_family == AF_INET ? (void *)&(socketAddress->ipv4.sin_addr) : (void *)&(socketAddress->ipv6.sin6_addr)),
                                               addressBuffer,
                                               sizeof(addressBuffer));

            int port = ntohs(socketAddress->sa.sa_family == AF_INET ? socketAddress->ipv4.sin_port : socketAddress->ipv6.sin6_port);

            if (addressStr && port)
            {
                AddressAndPort *aAndP = [[AddressAndPort alloc] init];
                aAndP.address = [NSString stringWithCString:addressStr encoding:kCFStringEncodingUTF8];
                aAndP.port = port;
                [retVal addObject:aAndP];
            }
        }
    }
    return retVal;

}


@end


@implementation AddressAndPort
@end

[Yes, I have no fear of creating lots of NSObject instances...] [是的,我不用担心会创建很多NSObject实例......]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM