繁体   English   中英

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

[英]GCDAsyncUdpSocket immediately closes when sending to an IPv6 address

我通过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方法调用一个send,而我的其他回调基本上只是信息(NSLog)。 这是传递给udpSocketDidClose:withError的NSError udpSocketDidClose:withError

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

不太有用。

在修复这个问题时,我想让它与IPv6协同工作而不是强制IPv4 ...强迫IPv4对我来说似乎很脆弱。

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后,包装sockaddr结构的NSData包含此信息。 然而,在你的代码,你提取sin6_portsin6_addr ,然后喂它们回到GCDAsyncUDPSocket泯灭的sin6_flowinfo (你不需要)和sin6_scope_id (在这种情况下,你这样做)。

直接使用-[GCDAsyncUDPSocket connectToAddress:error:] ,使用直接从您的解析服务获得的NSData ,您应该好好去。

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

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

暂无
暂无

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

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