首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >个人热点模式下iPhone未发送的网络广播/多播

个人热点模式下iPhone未发送的网络广播/多播
EN

Stack Overflow用户
提问于 2015-03-01 16:13:40
回答 2查看 3K关注 0票数 7

根据最近的经验发现,基于web上的各种帖子,运行在启用个人热点的iPhone上的应用程序似乎无法将广播和/或多播发送到个人热点的网络上。有人能说明这个问题的原因吗?

应用程序

我有一个IOS应用程序,由跨平台的C++代码构建,它可以在运行的网络上广播和多播它的存在。当iPhone连接到Wi网络时,应用程序工作得完美无缺.在这种情况下,网络上的其他设备接收广播/多播,一切正常工作。通过将运行WireShark的计算机连接到网络可以很容易地验证这一点--广播/多播数据包可以在数据包跟踪中看到。

不用说,该应用程序在连接到本地Wi的iPhone上运行良好。

问题

当我在启用个人热点的iPhone上运行应用程序时,没有广播/多播发布到热点网络。这可以使用WireShark进行验证,因为它在跟踪中没有显示这样的数据包。

对于使用个人热点作为能够处理广播和多播的网络路由器是否有任何限制?

当我使用浏览器在"WireSharking“设备上请求网页时,个人热点将正确响应所有数据包,返回网页内容。

抵押品信息

我遇到了其他的Stack溢出帖子,它们报告了相同或类似的问题:

  1. 当使用iPhone作为热点时,TCP连接不能正常工作
  2. 无法通过个人热点发送ssdp广播

在iPhone上编写这样的广播/多播应用程序的一个很好的教程是Michael的"Talkie的制作:多接口广播和多播“。只需说我的应用程序符合所有要求就足够了(例如,在适当的情况下设置套接字选项SO_BROADCAST、SO_DONTROUTE和IP_MULTICAST_IF )。

对上述参考文献(1)的答复写道:“可能是因为个人热点引入了网络地址翻译吗?”我过滤了WireShark跟踪,只显示连接到hotspot IP的数据包,没有证据表明个人热点向NAT地址发送任何内容。

中的概述

谁能解释为什么运行个人热点的iPhone不广播/多播数据包,以及如何解决这个问题?

在此之前,非常感谢您。

EN

回答 2

Stack Overflow用户

发布于 2016-11-10 09:53:32

我得到广播工作(在iOS 10上)

我发布了第二个答案,因为我找到了一种在个人热点模式下在iOS 10上进行广播的方法。解决方案有点复杂,但下面是我如何让它工作的方法:

  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网络时使用,也可以在个人热点模式下使用。

全示例代码

代码语言:javascript
复制
#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。只需在您的计算机上运行以下命令(它应该在与电话相同的网络上):

代码语言:javascript
复制
socat UDP-RECV:16000 STDOUT
票数 7
EN

Stack Overflow用户

发布于 2016-11-10 08:06:55

快速和肮脏的解决方案

在开发一个使用UDP组播消息发现网络设备的iPhone应用程序时,我也遇到了同样的问题。显然,iPhone在个人热点模式下阻塞多播消息。

然而,iPhone似乎将172.20.10.0/28子网用于个人热点网络上的设备。这意味着只有16个可能的地址。其中,显然没有使用172.20.10.0172.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和子网等等,但是对于我个人来说,这种方法已经足够了。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28795808

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档