3

我正在开发一个用于控制物理硬件的 iPhone 应用程序。
例程如下:

  • 应用程序在广播通道上的端口 8089 上发送一个特定的 8 字节“唤醒”数据报;消息被重复发送。
  • 侦听端口 8089 的外部硬件接收消息并发送一个 94 字节的数据报,其中包含硬件的 IP 和 MAC 地址等;这也在广播频道上。
  • 应用程序停止发送“唤醒”消息,存储 IP,并开始通过 TCP 套接字与硬件通信

该例程通常有效。但是,我经常在接收时莫名其妙地丢失 UDP 包;也就是说,我发送了 8 字节的“唤醒”信号,但没有得到 94 字节的响应。当应用程序运行时,它运行良好:我几乎不会丢失一个包,如果应用程序错过了第一个 94 字节的消息,它会得到第二个或第三个。当它不起作用时,它会不断地丢失所有包。“不工作”阶段可能会持续几分钟或几小时;我没有发现明显的触发因素 - 就好像在某个阶段,无缘无故地,接收停止工作。

在这里问之前,我已经做了非常广泛的调试。我已经通过 rvictl 和 tcpdump 监控了套接字,并确认我的日志反映了套接字级别发生的情况。为了将外部硬件排除在外,我构建了一个镜像应用程序,其行为与硬件一样。我尝试过更改端口,尝试关闭和关闭套接字,重置它们,暂停和重新启动接收。这些都不起作用。

我用 GCDAsyncUdpSocket 开发了我的通信库。为了安全起见,我也尝试过非 GCD 版本;结果是一样的。我围绕 C 套接字构建了自己的最小包装器;我有同样的行为。

这是我的实现代码:

GCDAsyncUdpSocket *udpSocket;

- (void)startUdpBroadcast {

    if (udpSocket == nil)
    {
        // Setup our socket.
        udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        [udpSocket setIPv6Enabled:NO];
    }

    NSLog(@"Listening for a message on %@",[self getBroadcastAddress]);

    NSError *bindError = nil;
    NSError *enableError = nil;
    NSError *receivingError = nil;

    [udpSocket bindToPort:8089 error:&bindError];
    if (bindError) {
        NSLog(@"Error, can't bind: %@",[bindError localizedDescription]);
        return;
    }
    [udpSocket enableBroadcast:YES error:&enableError];
    if (enableError) {
        NSLog(@"Error, can't enable broadcast: %@",[enableError localizedDescription]);
        return;
    }

    if (![udpSocket beginReceiving:&receivingError])
    {
        NSLog(@"Error, can't receive: %@",[receivingError localizedDescription]);
        return;
    }

    [self logInfo:@"Start listening to UDP boradcast channel"];

    [self sendUdpSignal];

    repeatedBroadcastTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(sendUdpSignal) userInfo:nil repeats:YES];

}

-(void)sendUdpSignal {
    NSData* signal = [self udpBroadcastSignal] ;
    NSLog(@"Send broadcast signal %@ on %@",signal,  [self currentNetworkSsid]);
    [udpSocket sendData:signal toHost:[self getBroadcastAddress] port:8089 withTimeout:10 tag:0];
}

你有什么建议吗?
有没有办法确保套接字接收永远不会停止?

在此先感谢,
戴维德

4

0 回答 0