无法接收使用 GCDAsyncSocket 发送的 UDP 数据包的响应

Posted

技术标签:

【中文标题】无法接收使用 GCDAsyncSocket 发送的 UDP 数据包的响应【英文标题】:Not able to receive response of the sent UDP packets using GCDAsyncSocket 【发布时间】:2015-04-18 06:02:13 【问题描述】:

我正在制作一个应用程序来发送UDP 数据包以打开LED bulb。当我连接到由Wifi bridge 创建的Ad-hoc 时,我已经能够执行所有操作。

现在,我想配置Wifi bridge 以便它可以连接到我的主路由器。我设置了 AT 命令来执行此过程,但不知何故,我无法接收来自Wifi bridge 的针对我发送给它的命令的响应。

程序如下:-

第一步: 发送UDP消息到局域网广播IP地址“10.10.100.255”和端口48899 =>“Link_Wi-Fi” LAN 上的所有 Wifi 网桥都会响应它们的详细信息。响应为“10.10.100.254,ACCF232483E8”

第 2 步:(用于更改 wifi 网桥上的设置可选):然后将“+ok”发送到 LimitlessLED Wifi 网桥。向步骤1返回的响应IP地址发送UDP消息“10.10.100.254”=>“+ok”

步骤 3:(更改 wifi 网桥设置可选):之后您可以向模块发送 AT 命令(以 \r\n 结尾)。

发送UDP包的代码如下

-(void)configureWifi

    counter++;
    NSString *host = @"10.10.100.255";
    if ([host length] == 0)
    
        [self logError:@"Address required"];
        return;
    

    int port = 48899; //[portField.text intValue];
    if (port <= 0 || port > 65535)
    
        [self logError:@"Valid port required"];
        return;
    
    NSString *msg = @"Link_Wi-Fi";
    NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"the message sent is %@", data);
    [udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:tag];


现在为了设置套接字并接收数据,我使用这两种委托方法:

 - (void)setupSocket

    // Setup our socket.
    // The socket will invoke our delegate methods using the usual delegate paradigm.
    // However, it will invoke the delegate methods on a specified GCD delegate dispatch queue.
    // 
    // Now we can configure the delegate dispatch queues however we want.
    // We could simply use the main dispatc queue, so the delegate methods are invoked on the main thread.
    // Or we could use a dedicated dispatch queue, which could be helpful if we were doing a lot of processing.
    // 
    // The best approach for your application will depend upon convenience, requirements and performance.
    // 
    // For this simple example, we're just going to use the main thread.

    udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

    NSError *error = nil;

    if (![udpSocket bindToPort:0 error:&error])
    
        [self logError:FORMAT(@"Error binding: %@", error)];
        return;
    
    if (![udpSocket beginReceiving:&error])
    
        [self logError:FORMAT(@"Error receiving: %@", error)];
        return;
    

    [self logInfo:@"Ready"];

为了接收数据,这是在发送 UDP 数据包后被调用的方法。这是我在项目中使用的 GCDAsyncUdpSocket 类的委托方法,用于发送和接收 UDP 数据包。

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
                                               fromAddress:(NSData *)address
                                         withFilterContext:(id)filterContext

    NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    if (msg)
    
        [self logMessage:FORMAT(@"RECV: %@", msg)];
    
    else
    
        NSString *host = nil;
        uint16_t port = 0;
        [GCDAsyncUdpSocket getHost:&host port:&port fromAddress:address];

        [self logInfo:FORMAT(@"RECV: Unknown message from: %@:%hu", host, port)];
    

一旦我能够收到响应,我就可以发送下一个 AT 命令来配置网桥。

谢谢。任何帮助将不胜感激。

【问题讨论】:

当有人说他们正在发送广播数据包时,我总是问的第一个问题是“你怎么知道这是你的广播地址?”尤其是在 10. A 类地址空间内。您正在发送到 10.10.100.255,但这只是您的广播地址,如果您网段中的其他人都认为它是广播地址。许多设备上的 IP 堆栈被写入认为 10.255.255.255 是 10.x.x.x 网络的广播地址。您能否向 .255 地址发送 ping 并观察到尽可能多的响应? 在您的设置方法中,您绑定到端口 0,允许操作系统选择一个空闲端口,然后您开始侦听套接字。您是如何将此套接字编号传达给想要联系您的应用的人的? @tobinjim 我们正在尝试将 UDP 数据包发送到“10.10.100.255”或 255.255.255.255,以便接收有多少 Wi-Fi 网桥处于活动状态。一旦我们能够接收到它的响应,我们就必须将所有 UDP 数据包发送到“10.10.100.254”或我们想要访问的任何 Wi-Fi 网桥。 @tobinjim 对于第二条评论我无法理解端口绑定的重要性。我通常应该在 Setup 方法中选择绑定哪个端口。 我的建议是相信你的代码,而不是相信设备。相反,请使用单独的工具来检查设备是否实际接收并响应您。使用 Terminal.app ping 10.10.100.255 地址 - 如果一堆灯泡没有响应,则表明它们无法从您的位置到达,或者他们认为 10.10.100.255 不是他们应该监听的地址。如果他们确实响应了,那么问题确实在您的应用程序中。 【参考方案1】:

以下是我建议您使用的故障排除步骤:

1- 我假设您使用的是ARC,因此请确保您的udpSocket 变量在整个异步通信过程中具有强引用。如果它被释放,那么这可以解释没有回调。

2- 确保沟通确实按照您认为的方式进行。使用Wireshark之类的软件来捕获网络上正在交换的数据包。这应该可以让您确认您的数据包确实在调用sendData: 时被发送,它还可以让您确认您是否收到回复。

3- 确保您正确使用了GCDAsyncUdpSocket。考虑到您要广播消息,您不应该在 setupSocket 方法中调用 bindToPort:error:。相反,您应该致电enableBroadcast:error:。考虑到您还想在广播后接收数据包,您应该使用connectToHost:onPort:error: 方法更改套接字的状态以允许双向通信。完成后,您可以将 sendData:toHost:port:withTimeout:tag: 的用法替换为 sendData:withTimeout:tag:。最后,您可以调用beginReceiving:,以便为任何传入的数据包调用委托。

4- 如果这仍然不能让您通过它,我建议您通读 GCDAsyncUdpSocket 的文档,该文档非常有据可查。

【讨论】:

【参考方案2】:

您可以使用 Wireshark 或任何网络捕获工具解决问题。 我们曾经在广泛使用 Wireshark 的类似项目中工作。 如果数据包已到达设备(Z-Wave),它将发送某种 Ack。 这将有助于确保数据包被发送出去。

【讨论】:

以上是关于无法接收使用 GCDAsyncSocket 发送的 UDP 数据包的响应的主要内容,如果未能解决你的问题,请参考以下文章

GCDAsyncSocket 未接收到所有传输的数据,缺少最后一个“块”

无法使用GCDAsyncSocket从服务器读取数据

GCDAsyncSocket 在接收数据时冻结 UI

iOS之GCDAsyncSocket第三方库的使用

在 iOS 中通过 GCDAsyncsocket 读取 xml 文件

NSJSONSerialization 无法解析有效的 JSON - “垃圾结束”