从广播模式更改为单播模式后,GCDasyncUdpSocket无法接收数据包

时间:2013-05-23 06:32:06

标签: xcode udp gcdasyncsocket

开发iPAD应用程序,通过WiFi与UDP到串行转换器进行通信。应用程序以广播模式启动并检索响应单元列表(requestPodIds)。接收的数据将SN映射到单元IP地址。然后,所选的IP地址用于在iPad和UDP /串行转换器之间进行点对点通信。

我的代码在广播通信上运行良好。我向单元IP地址发送的单播消息(requestStatus)正由转换器接收,它正在按预期响应。但是,我没有将任何数据返回到didReceiveData方法。

我不明白为什么我没有在方法中获取数据:

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

我的套接字连接位于AppDelegate中,调用是来自viewController的模式。

Buttons on viewController are pressed as follows:
1. button1Click 
2. button2Click; this calls requestPodIds; works fine; data returned which fills ten other button labels with pod ids; one is clicked;

3. getPodIdsClick; this loads the IP address of the UDP/Serial converter;

4. getStatusClick; this is where the problem occurs. The UDP message goes out, the UDP converter receives the message and responds, I never see the response data in didReceiveData.

AppDelegate代码:

 - (int) udpServiceStart {
    NSError * UDPError;
    if(GCDUdpSocket == nil)
    {
        GCDUdpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    GCDUdpSocket.delegate = self;
    [GCDUdpSocket setIPv4Enabled:YES];
    [GCDUdpSocket setIPv6Enabled:NO];
    [GCDUdpSocket enableBroadcast:YES error:&UDPError];

    if (![GCDUdpSocket  bindToPort:udpPort error:&UDPError])  { NSLog(@"Error starting server (bind): %@", UDPError);
        return -1;
    }

    if (![GCDUdpSocket beginReceiving:&UDPError])
        //            if (![GCDUdpSocket receiveOnce:&UDPError])
    {
        [GCDUdpSocket close];
        NSLog(@"Error starting server (recv): %@", UDPError);
        return -1;
    }

    NSLog(@"UDP Link started on port %hu", [GCDUdpSocket localPort]);
    return 0;
}

- (void) connectToPodAtAddress: (NSString *) ipAddress
{
    NSError * UDPError;
    [GCDUdpSocket enableBroadcast:NO error:&UDPError];
    podIp = ipAddress;
//    if (![GCDUdpSocket connectToHost:podIp onPort:udpPort error:&UDPError])
//    {
//        [GCDUdpSocket close];
//        NSLog(@"Error connecting to host: %@", UDPError);
//        return;
//    }
//    if (![GCDUdpSocket beginReceiving:&UDPError])
//        //            if (![GCDUdpSocket receiveOnce:&UDPError])
//    {
//        [GCDUdpSocket close];
//        NSLog(@"Error starting server (recv): %@", UDPError);
//        return;
//    }
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
      fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
    //    NSError * UDPError;

    NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    if (msg)
    {
        NSLog(@"RCV: %@", msg);
        if(!commandBuffer) commandBuffer = [[NSMutableString alloc] initWithString:@""];

        // Append the current message portion to the total message
        [commandBuffer appendString:msg];

        NSString * commands = [[NSString alloc] initWithString: commandBuffer];

        NSInteger cr_index = [commands rangeOfString:@"\r"].location;

        if([commands rangeOfString:@"\r"].location == NSNotFound)
        {
            if([commands rangeOfString:@"~~~ds"].location != NSNotFound)
            {
                [commandBuffer setString:@""];
            }

        } else {
            [self decodeMessage:commands];
        }

    }
    else
    {
        NSString *host = nil;
        uint16_t thePort = 0;
        [GCDAsyncUdpSocket getHost:&host port:&thePort fromAddress:address];
        NSLog(@"Unknown message from : %@:%hu", host, thePort);
    }
    //
    // Queue up to Read Next Message
    //
    //    if (![GCDUdpSocket receiveOnce:&UDPError])
    //    {
    //        [GCDUdpSocket close];
    //        NSLog(@"Error starting server (recv): %@", UDPError);
    //        return;
    //    }


}

- (void)udpSendToHost:(NSString *)host onPort:(int) thePort theMessage: (NSString *) msg
{
    NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
    tag = 0;
    [GCDUdpSocket sendData:data toHost:host port:thePort withTimeout:-1 tag:tag];

    NSLog(@"SENT message for tag (%i) to host %@:%i", (int)tag, host, thePort);
    NSLog(@"Message sent = (%@)", msg);

}

- (void) requestPodIds
{
#ifdef LOGFUNCTIONCALLS
    NSLog(logString,__FUNCTION__);
#endif
    [podTable removeAllObjects];  //    pod_table.Clear(); // Empty table of any previous responses

    if (GCDUdpSocket != nil) // null happens on startup if wireless adapter not found
    {
        //        PodMessage to_pod = new PodMessage(PodCommands.ucget, PodParameters.serial_number);
        PodMessage *to_pod = [[PodMessage alloc] initWithCommand:ucget andParams:serial_number];
        //        int bytes = udp_socket.SendTo(Encoding.ASCII.GetBytes(to_pod.Message()),
        //                                      new IPEndPoint(IPAddress.Broadcast, port));
        [self udpSendToHost:podIp onPort:udpPort theMessage:to_pod.message];
        //        Debug.Assert(bytes == to_pod.Message().Length);
    }
}

- (void) requestStatus
{
    if (GCDUdpSocket != nil) // null happens on startup if wireless adapter not found
    {
        //        PodMessage to_pod = new PodMessage(PodCommands.ucget, PodParameters.serial_number);
        PodMessage *to_pod1 = [[PodMessage alloc] initWithCommand:ucget andParams:status_pod];
        [self udpSendToHost:podIp onPort:udpPort theMessage:to_pod1.message];
//        PodMessage *to_pod2 = [[PodMessage alloc] initWithCommand:ucget andParams:status_line0];
//        [self udpSendToHost:podIp onPort:udpPort theMessage:to_pod2.message];
//        PodMessage *to_pod3 = [[PodMessage alloc] initWithCommand:ucget andParams:status_line1];
//        [self udpSendToHost:podIp onPort:udpPort theMessage:to_pod3.message];
        //        Debug.Assert(bytes == to_pod.Message().Length);
    }
}

从ViewController访问如下:

wifiTestAppDelegate *appDelegate;

appDelegate = (wifiTestAppDelegate *)[[UIApplication sharedApplication] delegate];

- (IBAction)button1Click:(id)sender {

    [appDelegate udpServiceStart];
}

- (IBAction)button2Click:(id)sender {
    if([GCDUdpSocket isClosed])
    {
        NSLog(@"Socket is Closed!");
    } else {
        if([GCDUdpSocket isConnected])
        {
            NSLog(@"Socket is Connected!  Can't Broadcast!");
        } else {
            [appDelegate requestPodIds];
        }
    }
}
- (IBAction)podSelectClick:(id)sender {

    NSLog(@"Button with label %@",((UIButton *)sender).titleLabel.text);
    NSLog(@"Button with tag %i",((UIButton *)sender).tag);


//    UIButton *button = (UIButton *)[self.view viewWithTag:buttonTag++];
//    [button setTitle:[podTable objectForKey:key] forState:UIControlStateNormal];

    NSString * ipAddress = [podTable objectForKey:((UIButton *)sender).titleLabel.text];
    NSLog(@"IP Address = %@",ipAddress);
    podIp = ipAddress;
    pod_sn = ((UIButton *)sender).titleLabel.text;

    [appDelegate connectToPodAtAddress:ipAddress];

    getStatusButton.hidden = NO;

    [selectPodButton setTitle:ipAddress forState:UIControlStateNormal];
}
- (IBAction)getPodIdsClick:(id)sender {
    int buttonTag = 101;
    NSMutableArray * sortArray = [[NSMutableArray alloc] initWithCapacity:100];
    if([podTable count] > 0)
    {
        for (NSString *key in podTable)
        {
            [sortArray addObject:key];
        }
        [sortArray sortUsingSelector:@selector(compare:)];
        for(int i=0; i < [podTable count]; i++)
        {
            UIButton *button = (UIButton *)[self.view viewWithTag:buttonTag++];
            [button setTitle:[sortArray objectAtIndex:i] forState:UIControlStateNormal];
        }
    }

}

- (IBAction)getStatusClick:(id)sender {
    [appDelegate requestStatus];
}

1 个答案:

答案 0 :(得分:0)

没有运气让GCDAsyncUdpSocket发送除了类广播之外的其他内容。解决了广播部分代码的BSD套接字解决方案的实现:

int                 fd;
int                 err;
int                 junk;
struct sockaddr_in  addr;
NSData *            data;
ssize_t             bytesSent;
static const int    kOne = 1;

fd = socket(AF_INET, SOCK_DGRAM, 0);
assert(fd >= 0);

err = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &kOne, sizeof(kOne));
assert(err == 0);

data = [@"hello" dataUsingEncoding:NSUTF8StringEncoding];
assert(data != nil);

memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_len = sizeof(addr);
addr.sin_port = htons(8023);
addr.sin_addr.s_addr = htonl(0xffffffff);  // 255.255.255.255

bytesSent = sendto(fd, [data bytes], [data length], 0, (const struct sockaddr *) &addr, sizeof(addr));
NSLog(@"bytes sent = %zd", bytesSent);

junk = close(fd);
assert(junk == 0);