3

Bonjourによってアドバタイズされている別のデバイス上のサーバーにUDP経由で接続しています。このコードが実行されているiOSデバイスとサーバーの両方がwifiネットワーク上にある場合、bonjourサービスはdhcpサーバーから渡される192.168.0.xxxアドレスに解決されるため、正常に機能します。ただし、Bluetoothによってアドバタイズされると、サービスが169.254.xxx.xxx(IPv4)に解決される場合があります。その場合、サービスは正常に機能します。ただし、fe80 :: xxxx:xxxx:xxxx:xxxx(IPv6)に解決される場合があります。その場合、ソケットは接続します(udpSocket:didConnectToAddressコールバックを受信します)が、データを送信しようとするとすぐに閉じます(udpSocketDidClose:withErrorsendを呼び出すとすぐにコールバックを受信します)。

- (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)です。これはに渡されるNSErrorudpSocketDidClose:withErrorです:

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

役に立たない。

これを修正する際に、IPv4を強制するのではなくIPv6で動作させたいと思います...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_portてから、 (不要な)と(この場合は必要な)を含まないsin6_addrようにフィードバックします。GCDAsyncUDPSocketsin6_flowinfosin6_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 に答える