7

我在网络上有一个设备通过 UDP 多播一个非常小的文件。我正在开发的 iOS 应用程序负责读取这些数据包,我选择使用GCDAsyncUdpSocket来执行此操作。该文件每半秒发送一次,但是我几乎没有收到它(大约每 3-10 秒接收一次)。

考虑到这可能是设备的问题,我开始使用 Wireshark 监控流量。这似乎反映了我在应用程序中看到的内容,直到我在 Wireshark 中启用“监控模式”,此时每个 UDP 数据包都被捕获。此外,iOS 模拟器开始接收所有丢失的数据包,因为它与我正在开发的 Mac 共享 NIC。

有没有办法在 iOS 设备上启用“监控模式”或我缺少的东西可以让丢失的数据包进入?我还看到 GCDAsyncUdpSocket 中有一个 readStream 方法。也许我需要使用它而不是 beginReceiving?如果是这样的话,虽然我不知道如何在 Objective-C 中设置流。

这是我现在的测试代码:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSLog(@"View Loaded");
    [self setupSocket];             
}

- (void)setupSocket
{
    udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    NSError *error = nil;
    if (![udpSocket bindToPort:5555 error:&error])
    {
        NSLog(@"Error binding to port: %@", error);
        return;
    }
    if(![udpSocket joinMulticastGroup:@"226.1.1.1" error:&error]){
        NSLog(@"Error connecting to multicast group: %@", error);
        return;
    }
    if (![udpSocket beginReceiving:&error])
    {
        NSLog(@"Error receiving: %@", error);
        return;
    }
    NSLog(@"Socket Ready");
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
      fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
    NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    if (msg)
    {
        NSLog(@"RCV: %@", msg);
    }
    else
    {
        NSString *host = nil;
        uint16_t port = 0;
        [GCDAsyncUdpSocket getHost:&host port:&port fromAddress:address];
        NSLog(@"Unknown message from : %@:%hu", host, port);
    }
}

任何将来来这里的人的解决方案:

根据 ilmiacs 的回答,我能够通过 ping 目标 iOS 设备显着减少丢失数据包的数量。使用 Mac,我在终端中运行了它 -

sudo ping -i 0.2 -s 4 <Target IP>

既然我已经使用 Mac ping iOS 设备运行它,我将研究 Apple 的 iOS ping 示例,看看是否可以让设备 ping 自身以刺激其自己的无线适配器 (127.0.0.1)。

4

3 回答 3

13

通过我为 iOS 设备开发网络应用程序的工作,我发现它们的网络适配器有两种不同的模式,我们称它们为主动和被动。我没有找到任何关于此的文档。以下是我的发现:

  1. 只要处于活动模式,适配器就会非常敏感。我的响应时间为 3-5 毫秒。

  2. 经过一段时间的不活动后,iOS 的网络适配器从主动模式变为被动模式。发生这种情况的时间取决于实际的设备型号。第三代 iPad 大约是 200 毫秒。对于 iPhone 4,它更像是 50 毫秒。

  3. ping 请求或 TCP 数据包会将适配器从被动模式移动到主动模式。这可能需要 50 毫秒到 800 毫秒,平均大约 200 毫秒。

通过发出 ping 命令,这种行为是完全可重现的。例如

ping -i 0.2 <ios-device-ip>

将 ping 间隔设置为 200 毫秒,并使我的 iPad 网络适配器保持活动状态。

如果适配器(通常)在被动模式下忽略 UDP 数据包,则此行为与您的观察完全一致。Wireshark 活动可能会使其处于活动模式,因此它将获得 UDP。

检查 ping 技巧是否有帮助。

可以通过打开和连接设备本身的两个套接字并定期向自身发送数据包来使 iDevice 的网络适配器保持活动状态。这将引入一些最小的开销。

至于为什么苹果决定实现这样的功能,我只能推测。但是,保持适配器处于活动状态可能会花费足够的电池电量来使这种设计选择合法化。

希望这可以帮助。

于 2013-01-17T15:27:03.450 回答
1

我遇到过同样的问题。

启动网络活动指示器为我解决了这个问题:

UIApplication* app = [UIApplication sharedApplication];
app.networkActivityIndicatorVisible = YES;
于 2013-05-02T19:09:55.810 回答
1

如果要在 iOS 设备上查看数据包,可以将 iOS 设备连接到 Mac 并使用shell 命令 rvictl挂载 wifi 适配器。然后你可以使用wireshark、tcpdump等来监控你iOS设备上802.11接口的流量。

直到 3 到 7 秒才接收数据 - 很可能您的设备正在进入省电模式 (IEEE PSM),这是一种 802.11 功能,基本上使无线 NIC 进入睡眠状态。
PSM 模式可能会在设备上产生较差的性能- 特别是在您每 1/2 秒有周期性数据突发的情况下。您的定期 ping 正在唤醒 NIC。

于 2014-01-11T04:41:37.603 回答