发送到IPv6地址时GCDAsyncUdpSocket立即关闭(GCDAsyncUdpSocket

2019-07-04 03:17发布

我经由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立即回调在调用时发送)。

- (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的似乎只是脆弱的我。

Answer 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_portsin6_addr ,然后喂它们回到GCDAsyncUDPSocket泯灭的sin6_flowinfo (你不需要)和sin6_scope_id (在这种情况下,你这样做)。

使用-[GCDAsyncUDPSocket connectToAddress:error:]直接使用NSData ,你直接从你的决心服务中获得的,你应该是好去。



Answer 2:

我所做的就是调用setPreferIPv4setIPv6Enabled:FALSE插座,这将使连接失败,如果DNS查找才会返回IPv6地址上。 然后,在udpSocket:didNotConnect:我检查的特定错误( IPv6 has been disabled and DNS lookup found no IPv4 address(es).如果连接失败,因为这个原因,又回到了我的setupConnection方法,并试图再次。 最终,DNS查询将返回IPv4地址和东西从那里顺利进行。

这还不是最完美的解决方案,但它的工作原理。



文章来源: GCDAsyncUdpSocket immediately closes when sending to an IPv6 address