7

最近の経験的調査結果および Web 上のさまざまな投稿に基づくと、個人用ホットスポットが有効になっている iPhone で実行されているアプリケーションは、個人用ホットスポットのネットワークにブロードキャストおよび/またはマルチキャストを送信できないようです。誰でもこの問題の原因を明らかにできますか?

アプリケーション

私は、クロスプラットフォームの C++ コードで構築された IOS アプリケーションを持っています。このアプリケーションは、実行中のネットワークにその存在をブロードキャストおよびマルチキャストします。iPhone が Wi-Fi ネットワークに接続されている場合、アプリケーションは問題なく動作します。この場合、ネットワーク上の他のデバイスはブロードキャスト/マルチキャストを受信し、すべてが正しく機能します。これは、WireShark を実行しているコンピュータをネットワークに接続することで簡単に確認できます。ブロードキャスト/マルチキャスト パケットは、パケット トレースで確認できます。

言うまでもなく、このアプリケーションはローカル Wi-Fi に接続された iPhone でも問題なく動作します。

問題

パーソナル ホットスポットが有効になっている iPhone でアプリケーションを実行すると、ホットスポット ネットワークにブロードキャスト/マルチキャストがリリースされません。これは、WireShark を使用して確認できますが、トレースにそのようなパケットは表示されません。

パーソナル ホットスポットを、ブロードキャストとマルチキャストを処理できるネットワーク ルーターとして使用することに関して、何か制約はありますか?

ブラウザを使用して「WireSharking」デバイスで Web ページを要求すると、パーソナル ホットスポットはすべてのパケットに正しく応答し、Web コンテンツを返します。

担保情報

同じまたは類似の問題を報告している他の Stack Overflow の投稿に出くわしました。

  1. iPhone をホットスポットとして使用すると、TCP 接続が正しく機能しない
  2. パーソナル ホットスポットで ssdp ブロードキャストを送信できない

このようなブロードキャスト/マルチキャスト アプリケーションを iPhone で作成するための優れたチュートリアルは、Michael Tyson の「The Making of Talkie: Multi-interface Broadcasting and Multicast」です。私のアプリケーションがすべての要件に準拠していると言えれば十分です (たとえば、ソケット オプション SO_BROADCAST、SO_DONTROUTE、および IP_MULTICAST_IF を適切に設定するなど)。

上記の参照 (1) への返信には、「パーソナル ホットスポットがネットワーク アドレス変換を導入したためでしょうか?」と書かれています。ホットスポット IP に接続されたパケットのみを表示するように WireShark トレースをフィルタリングしましたが、パーソナル ホットスポットが NAT アドレスに何かを送信している証拠はありません。

要約すれば

パーソナル ホットスポットを実行している iPhone がパケットをブロードキャスト/マルチキャストしない理由と、問題の解決方法を説明できる人はいますか?

よろしくお願いします。

4

2 に答える 2

7

ブロードキャストが機能しました(iOS 10で)

パーソナル ホットスポット モードで iOS 10 でブロードキャストを動作させる方法を見つけたので、2 番目の回答を投稿します。解決策は少し複雑ですが、これを機能させる方法は次のとおりです。

  1. getifaddrs(if)すべてのインターフェースをループするために使用します ( do {} while (if = if->ifa_next))
  2. ループバック インターフェイスを拒否する ( if->ifa_flags & IFF_LOOPBACK)
  3. ブロードキャストをサポートするインターフェースのみをフィルタリングする ( if->ifa_flags & IFF_BROADCAST)
  4. でソケットを作成しますint sock = socket()
  5. ブロードキャストを有効にする:int yes = 1; setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes)
  6. ブロードキャスト アドレスに接続します。connect(sock, if->ifa_dstaddr, if->ifa_dstaddr->sa_len)
  7. 今すぐsend()あなたのメッセージを送信するために使用してください!

これは、iPhone が WiFi ネットワークに接続されているときと、パーソナル ホットスポット モードのときの両方で動作することを確認しています。

完全なサンプル コード

#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>

-(IBAction)sayHello:(id)sender {

    // fetch a linked list of all network interfaces
    struct ifaddrs *interfaces;
    if (getifaddrs(&interfaces) == -1) {
        NSLog(@"getifaddrs() failed: %s", strerror(errno));
        return;
    }

    // loop through the linked list
    for(struct ifaddrs *interface=interfaces; interface; interface=interface->ifa_next) {

        // ignore loopback interfaces
        if (interface->ifa_flags & IFF_LOOPBACK) continue;

        // ignore interfaces that don't have a broadcast address
        if (!(interface->ifa_flags & IFF_BROADCAST) || interface->ifa_dstaddr == NULL) continue;

        // check the type of the address (IPv4, IPv6)
        int protocol_family;
        struct sockaddr_in ipv4_addr = {0};
        struct sockaddr_in6 ipv6_addr = {0};
        struct sockaddr *addr;
        if (interface->ifa_dstaddr->sa_family == AF_INET) {
            if (interface->ifa_dstaddr->sa_len > sizeof ipv4_addr) {
                NSLog(@"Address too big");
                continue;
            }
            protocol_family = PF_INET;
            memcpy(&ipv4_addr, interface->ifa_dstaddr, interface->ifa_dstaddr->sa_len);
            ipv4_addr.sin_port = htons(16000);
            addr = (struct sockaddr *)&ipv4_addr;

            char text_addr[255] = {0};
            inet_ntop(AF_INET, &ipv4_addr.sin_addr, text_addr, sizeof text_addr);
            NSLog(@"Sending message to %s:%d", text_addr, ntohs(ipv4_addr.sin_port));
        }
        else if (interface->ifa_dstaddr->sa_family == AF_INET6) {
            if (interface->ifa_dstaddr->sa_len > sizeof ipv6_addr) {
                NSLog(@"Address too big");
                continue;
            }
            protocol_family = PF_INET6;
            memcpy(&ipv6_addr, interface->ifa_dstaddr, interface->ifa_dstaddr->sa_len);
            ipv6_addr.sin6_port = htons(16000);
            addr = (struct sockaddr *)&ipv6_addr;

            char text_addr[255] = {0};
            inet_ntop(AF_INET6, &ipv6_addr.sin6_addr, text_addr, sizeof text_addr);
            NSLog(@"Sending message to %s:%d", text_addr, ntohs(ipv6_addr.sin6_port));
        }
        else {
            NSLog(@"Unsupported protocol: %d", interface->ifa_dstaddr->sa_family);
            continue;
        }

        // create a socket
        int sock = socket(protocol_family, SOCK_DGRAM, IPPROTO_UDP);
        if (sock == -1) {
            NSLog(@"socket() failed: %s", strerror(errno));
            continue;
        }

        // configure the socket for broadcast mode
        int yes = 1;
        if (-1 == setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes)) {
            NSLog(@"setsockopt() failed: %s", strerror(errno));
        }

        // create some bytes to send
        NSString *message = @"Hello world!\n";
        NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];

        if (-1 == connect(sock, addr, addr->sa_len)) {
            NSLog(@"connect() failed: %s", strerror(errno));
        }

        // send the message
        ssize_t sent_bytes = send(sock, data.bytes, data.length, 0);
        if (sent_bytes == -1) {
            NSLog(@"send() failed: %s", strerror(errno));
        }
        else if (sent_bytes<data.length) {
            NSLog(@"send() sent only %d of %d bytes", (int)sent_bytes, (int)data.length);
        }

        // close the socket! important! there is only a finite number of file descriptors available!
        if (-1 == close(sock)) {
            NSLog(@"close() failed: %s", strerror(errno));
        }
    }

    freeifaddrs(interfaces);
}

このサンプル メソッドは、ポート 16000 で UDP メッセージをブロードキャストします。

デバッグには、ツールを使用できますsocat。コンピューターで次のコマンドを実行するだけです (電話と同じネットワーク上にある必要があります)。

socat UDP-RECV:16000 STDOUT
于 2016-11-10T09:53:32.250 に答える
3

手っ取り早い回避策

UDP マルチキャスト メッセージを使用してネットワーク上のデバイスを検出する iPhone アプリを開発しているときにも、同じ問題に遭遇しました。どうやら、iPhone はパーソナル ホットスポット モードでマルチキャスト メッセージをブロックするようです。

ただし、iPhone172.20.10.0/28はパーソナル ホットスポット ネットワーク上のデバイスにサブネットを使用しているようです。これは、可能なアドレスが 16 個しかないことを意味します。これらのうち、172.20.10.0明らかに使用されていない172.20.10.1のは iPhone 自体であり、メッセージの送信172.20.10.15は「許可されていません」というエラーで失敗します。これは、次の 13 個のアドレスのみがクライアントで使用できることを意味します: 172.20.10.2172.20.10.3、...、172.20.10.14

したがって、私の回避策は非常に簡単です。ブロードキャスト メッセージを にのみ送信する代わりに224.0.0.0、サブネット内の他のすべての可能なアドレス ( 172.20.10.2- 172.20.10.14) にも送信します。

もちろん、実稼働アプリで将来を保証するためには、おそらくネットワーク インターフェイスのリストを確認し、IP とサブネットを確認する必要がありますが、私の個人的な使用では、この方法で十分です。

于 2016-11-10T08:06:55.540 に答える