3

我通过 UDP 连接到 Bonjour 宣传的不同设备上的服务器。当运行此代码的 iOS 设备和服务器都在我们的 wifi 网络上时,它工作得很好,因为 bonjour 服务解析为我们的 dhcp 服务器分发的 192.168.0.xxx 地址。但是,当它通过蓝牙进行广告时,有时服务会解析为 169.254.xxx.xxx (IPv4),在这种情况下它工作得很好。但有时它会解析为 fe80::xxxx:xxxx:xxxx:xxxx (IPv6),在这种情况下,套接字连接(我收到udpSocket:didConnectToAddress回调)但在我尝试发送数据时立即关闭(我udpSocketDidClose:withError在调用 send 时立即收到回调)。

- (BOOL) setupConnection: (DNSSDService*) service
{
    NSString *host = [service resolvedHost];
    NSUInteger port = [service resolvedPort];
    NSLog(@"in setupConnection: host %@ port %u",
          host, port);

    self.sock = [[GCDAsyncUdpSocket alloc]initWithDelegate:self 
                delegateQueue:dispatch_get_main_queue() ];
    NSError *err = nil;
    if (![self.sock connectToHost:host onPort:port error:&err]) {
        NSLog(@"we goofed: %@", err);
        return NO;
    }
    return YES;
}

我的udpSocket:didConnectToAddress方法调用了发送,此时我的其他回调基本上只是信息性的(NSLog)。这是传递给的 NSError udpSocketDidClose:withError

Error Domain=GCDAsyncUdpSocketErrorDomain Code=4 "Socket closed" UserInfo=0x2630c0 {NSLocalizedDescription=Socket closed}

用处不大。

在解决这个问题时,我想让它与 IPv6 一起工作,而不是强制 IPv4 ......强制 IPv4 对我来说似乎很脆弱。

4

2 回答 2

1

fe80 是链路本地 IPv6 地址。您要连接的机器必须有多个网络接口——大多数都有,例如以太网和WiFi。要完全指定 IPv6 地址,需要 scope_id。这是 sin6_scope_id 来自:

// IPv6 AF_INET6 sockets:

struct sockaddr_in6 {
    u_int16_t       sin6_family;   // address family, AF_INET6
    u_int16_t       sin6_port;     // port number, Network Byte Order
    u_int32_t       sin6_flowinfo; // IPv6 flow information
    struct in6_addr sin6_addr;     // IPv6 address
    u_int32_t       sin6_scope_id; // Scope ID
};

当与地址结合并转换为字符串时,如下所示:fe80::e2f8:47ff:fe23:5392%eth1

解析 DNS 后,NSData包装sockaddr结构体将包含此信息。但是,在您的代码中,您正在提取sin6_portand sin6_addr,然后将它们反馈回GCDAsyncUDPSocket没有sin6_flowinfo(您不需要)和sin6_scope_id(在这种情况下您需要)。

直接使用-[GCDAsyncUDPSocket connectToAddress:error:],使用NSData你直接从你的解析服务中获得的,你应该很高兴。

于 2013-03-18T03:02:45.610 回答
0

我所做的是调用setPreferIPv4setIPv6Enabled:FALSE在套接字上,如果 DNS 查找仅返回 IPv6 地址,这将导致连接失败。然后,udpSocket:didNotConnect:我检查了那个特定的错误(IPv6 has been disabled and DNS lookup found no IPv4 address(es).),如果由于这个原因连接失败,回到我的setupConnection方法并再次尝试。最终,DNS 查找返回一个 IPv4 地址,事情从那里顺利进行。

这不是最优雅的解决方案,但它有效。

于 2012-11-28T22:28:01.353 回答