iPhone:Bonjour NSNetService IP 地址和端口

发布于 2024-07-23 12:14:15 字数 872 浏览 3 评论 0原文

请原谅我的 iPhone/Objective-C 新手身份!

我已经使用 NSNetServiceBrowser 找到了我的 HTTP 服务器,但现在我只想找到该服务的 IP 地址和端口。

我的委托方法中有类似以下内容的内容:

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);
}

但即使调用委托,也永远不会进入 for 循环。 有任何想法吗? 谢谢!

Excuse my iPhone/Objective-C newbie status please!

I've found my HTTP server using NSNetServiceBrowser, but now I just want the IP address and port of the service found.

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. Any ideas? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

微暖i 2024-07-30 12:14:15

我意识到这是一个旧线程,但我也刚刚遇到过这个。 上面的代码存在一些问题:

  1. 它不了解 IPv6。 在一个
    至少,它应该检测并
    如果剩余的 IPv6 地址被丢弃
    您的应用程序只能处理 v4
    地址,但理想情况下你应该是
    准备传递两个地址
    家庭上游。

  2. 端口分配将
    为英特尔生成不正确的值
    处理器。 您需要使用htons
    来解决这个问题。

  3. 正如安德鲁上面指出的,
    迭代应该使用增强的
    for 循环。

  4. (编辑:添加了此内容)正如另一个相关线程中所述,不鼓励使用 inet_ntoa,而是使用 inet_ntop

将所有这些放在一起,您将得到:

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);
        }
    }
}

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

  2. The port assignment will
    generate incorrect values for Intel
    processors. You need to use htons
    to fix that.

  3. As Andrew noted above, the
    iteration should use the enhanced
    for loop.

  4. (EDIT: Added this) As noted on another related thread, the use of inet_ntoa is discouraged in favor of 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);
        }
    }
}
夏九 2024-07-30 12:14:15

您在回调中返回的 NSNetService 尚未准备好使用。 您必须调用以下方法来获取它的地址:

- (void)resolveWithTimeout:(NSTimeInterval)timeout;

实现 NSNetService 委托方法以查明它何时解析:

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

此时,服务中应该至少有一个地址。

另外,请务必仔细阅读文档和头文件! 这里的问题有一些复杂性,我已经忽略了。

The NSNetService you get back in the callback isn't ready to be used. 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:

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

莫言歌 2024-07-30 12:14:15

类别中已接受答案的混音:

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

#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

[是的,我不担心创建大量 NSObject 实例...]

Remix of the accepted answer in a category:

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

#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...]

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文