GCDAsyncUdpSocket 在发送到 IPv6 地址时立即关闭
Posted
技术标签:
【中文标题】GCDAsyncUdpSocket 在发送到 IPv6 地址时立即关闭【英文标题】:GCDAsyncUdpSocket immediately closes when sending to an IPv6 address 【发布时间】:2012-11-26 17:56:20 【问题描述】:我正在通过 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)。这是传递给udpSocketDidClose:withError
的NSError:
Error Domain=GCDAsyncUdpSocketErrorDomain Code=4 "Socket closed" UserInfo=0x2630c0 NSLocalizedDescription=Socket closed
用处不大。
在解决这个问题时,我想让它与 IPv6 一起工作,而不是强制 IPv4...强制 IPv4 对我来说似乎很脆弱。
【问题讨论】:
【参考方案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 后,包装 sockaddr
结构的 NSData
包含此信息。但是,在您的代码中,您将提取sin6_port
和sin6_addr
,然后将它们反馈给GCDAsyncUDPSocket
,没有sin6_flowinfo
(您不需要)和sin6_scope_id
(在这种情况下你这样做)。
直接使用-[GCDAsyncUDPSocket connectToAddress:error:]
,使用您直接从解析服务获得的NSData
,您应该可以继续使用。
【讨论】:
【参考方案2】:我所做的是在套接字上调用 setPreferIPv4
和 setIPv6Enabled:FALSE
,如果 DNS 查找仅返回 IPv6 地址,这将导致连接失败。然后,在udpSocket:didNotConnect:
中,我检查了该特定错误(IPv6 has been disabled and DNS lookup found no IPv4 address(es).
),如果连接因此失败,则返回我的setupConnection
方法并再次尝试。最终,DNS 查找返回一个 IPv4 地址,事情从那里顺利进行。
这不是最优雅的解决方案,但它确实有效。
【讨论】:
以上是关于GCDAsyncUdpSocket 在发送到 IPv6 地址时立即关闭的主要内容,如果未能解决你的问题,请参考以下文章
GCDAsyncUdpSocket 在发送到 IPv6 地址时立即关闭