iOS上的GCDAsyncUdpSocket缺少多播数据报

时间:2012-10-28 21:59:41

标签: ios udp wireshark multicast gcdasyncsocket

我在网络上有一个设备通过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上运行iOS设备,我将查看Apple的iOS ping示例,看看我是否可以让设备ping自己来刺激自己的无线适配器(127.0.0.1)。 / p>

3 个答案:

答案 0 :(得分:13)

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

  1. 只要处于活动模式,适配器就会响应很快。我的响应时间为3-5ms。

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

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

  4. 通过发出ping命令可以完全重现此行为。 E.g。

    ping -i 0.2 <ios-device-ip>
    

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

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

    检查ping技巧是否有帮助。

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

    至于为什么苹果决定实施这样的功能,我只能推测。但是,保持适配器有效可能需要足够的电池电量才能使这种设计选择合法化。

    希望这有帮助。

答案 1 :(得分:1)

我遇到了同样的问题。

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

UIApplication* app = [UIApplication sharedApplication];
app.networkActivityIndicatorVisible = YES;

答案 2 :(得分:1)

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

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