GCDasyncUdpSocket can't reveive packets after changing from broadcast to unicast mode

StackOverflow https://stackoverflow.com/questions/16707061

  •  30-05-2022
  •  | 
  •  

Question

Developing an iPAD app which communicates via WiFi to a UDP to serial converter. App starts out in broadcast mode and retrieves a list of responding units (requestPodIds). The received data maps a SN to the units IP address. The selected IP address is then used to communicate point-to-point between the iPad and the UDP/serial converter.

My code works fine on the broadcast communications. And the unicast message I send out (requestStatus) to the units IP address is being received by the converter and it is responding as expected. However, I do not get any data back into the didReceiveData method.

I do not understand why I am not getting the data back in the method:

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

My socket connections are located in the AppDelegate and the calls are mode from a 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 code:

 - (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);
    }
}

Access from the ViewController is as follows:

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];
}
Était-ce utile?

La solution

No luck in getting GCDAsyncUdpSocket to send other than class broadcast. Resolved with implementation of BSD sockets solution for broadcast portion of code:

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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top