GCDAsyncUdpSocket and multicast sending and receiving

Błażej picture Błażej · Aug 9, 2013 · Viewed 13.7k times · Source

In first approach I create client-server app ,based on sampleProject , which send some data to server.

Legend:
sender
    address = reciver ip
    port = reciver port
reciver
    address = null since he is listening
    port = in my case 55555

Working code

skipping error checking is intentional only for public reasons

Sender

-(id*)initForSender:(NSString*)address port:(int)port
 {
   self = [super init];
   if (self) {
        _port = port;
        _address = address;
        tag = 0;
        _udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

        [_udpSocket bindToPort:0 error:&error];
        [_udpSocket beginReceiving:&error];

      return self;
    }
}

-(void)send:(NSData*)data{
     [_udpSocket sendData:data toHost:_address port:_port withTimeout:-1 tag:tag];
     tag++;
}

Receiver / Listener

-(id*)initForReceiver:(NSString*)address port:(int)port
{
   self = [super init];
   if (self) {
        _port = port;
        _udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        NSError *error = nil;

       [_udpSocket bindToPort:0 error:&error];
       [_udpSocket beginReceiving:&error];
    }
    return self;
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
      fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
    //Do something with receive data
}

Multicast

But then I want client which will send to many receivers. Form I know sendre or listener should use [GCDAsyncUdpSocket joinMulticastGroup:error];. I ran throu stackoverflow, uncle google and CococaAsyncSocket (where is no word abou udp), match gathered pieces of information and came up with this code. I'm perfectly sure, that is not working but I don't have a clue why.

Legend:
sender
    address = sender ip
    port = sender port in my case 55555
reciver
    address = sender ip
    port = sender port in my case 55555

Not working code

-(id*)initForSender:(NSString*)address port:(int)port
{
    self = [super init];
    if (self) {
        _port = port;
        _address = address;
        _udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        NSError *error = nil;

        [_udpSocket bindToPort:_port error:&error];
        [_udpSocket joinMulticastGroup:_address error:&error];
        [_udpSocket enableBroadcast:YES error:&error];

    }
    return self;
}

-(void)send:(NSData*)data{
     [_udpSocket sendData:data toHost:_address port:_port withTimeout:-1 tag:tag];
     tag++;
}

Receiver / Listener

-(id*)initForReceiver:(NSString*)address port:(int)port
{
    self = [super init];
    if (self) {
        _port = port;
        _address = address;
        _udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
         NSError *error = nil;

        [_udpSocket bindToPort:_port error:&error];
        [_udpSocket joinMulticastGroup:_address error:&error];
        [_udpSocket beginReceiving:&error])

    }
    return self;
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
      fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
   //Do something with receive data
}

UPDATE:

It's turn out that when I use some unuse IP as address for example @"224.0.1.1" then it wroks, but it feels weird a bit. Am I doing it correct?

Answer

user523234 picture user523234 · Aug 10, 2013
  1. Multicast addresses are special reserved addresses for multicasting purpose. When a host send a data to a multicast address (group), all hosts that have joined that group will receive the data.

  2. Any host that wishes to receive data from a multicast group needs to join that group. The three steps for GCDAsyncUdpSocket are: (note that group address and group port combination must be unique for that selected multicast group)

    [_udpSocket bindToPort:_port error:&error];
    [_udpSocket joinMulticastGroup:_address error:&error];
    [_udpSocket beginReceiving:&error])
    
  3. For a sender, you don't need these two lines as you have.

    [_udpSocket bindToPort:0 error:&error];  //bindToPort:0 is same as auto-select sender port by default.
    [_udpSocket beginReceiving:&error];   //if you don't want to received, no need for this.
    

Use the 239.0.0.0-239.255.255.255 for your private local network. Avoid 224... You can read more from the link above.