2012-11-26 3 views
2

Bonjour에서 광고하는 다른 장치의 서버에 UDP를 통해 연결합니다. 이 코드가 실행되는 iOS 장치와 서버가 모두 wifi 네트워크에 연결되어 있으면 bonjour 서비스가 dhcp 서버가 전달하는 192.168.0.xxx 주소로 연결되기 때문에 정상적으로 작동합니다. 그러나 블루투스로 광고를하는 경우 서비스가 169.254.xxx.xxx (IPv4)로 해결되는 경우도 있습니다.이 경우 제대로 작동합니다. 하지만 때로는 fe80 :: xxxx : xxxx : xxxx : xxxx (IPv6)로 소켓을 연결하는 경우 (내가 udpSocket:didConnectToAddress 콜백을 받음) 즉시 데이터를 보내려고 할 때 닫힙니다. 전화를 걸면 즉시 udpSocketDidClose:withError 콜백을받습니다. .IPv6 주소로 보낼 때 GCDAsyncUdpSocket이 즉시 닫습니다.

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

이하.

이 문제를 해결하기 위해 강제로 IPv4 대신 강제로 작동하도록하고 싶습니다. IPv4를 강요하는 것은 나에게 취약한 것처럼 보입니다.

답변

0

내가 한 것은 소켓에서 setPreferIPv4setIPv6Enabled:FALSE으로 전화를 걸었 기 때문에 DNS 조회가 IPv6 주소 만 반환하면 연결에 실패하게됩니다. 그런 다음 udpSocket:didNotConnect:에서 해당 오류 (IPv6 has been disabled and DNS lookup found no IPv4 address(es).)를 확인했는데 연결이 실패한 경우 내 setupConnection 방법으로 돌아가서 다시 시도했습니다. 결국 DNS 조회가 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가 해결

NSDatasockaddr 구조체 포장이 정보가 포함되어 있습니다. 그러나 코드에서 sin6_portsin6_addr을 추출한 다음 sin6_flowinfo (필요하지 않음)과이 경우에는 sin6_scope_id이없는 GCDAsyncUDPSocket에 다시 입력합니다.

NSData을 직접 사용하십시오. 해결 서비스에서 직접 받으십시오.

관련 문제