BROWSING FOR SERVICES

Now that you have seen how to publish a service, this section demonstrates how you can browse for services that have been published on the network. You will use the NSNetServiceBrowser class to discover services published on the network.

TRY IT OUT: Browsing for Services on the Network

  1. Using the Bonjour project from the previous Try it Out, add the following bold statements to the BonjourViewController.h importfile:
    #import <arpa/inet.h>
    
    @interface BonjourViewController : UIViewController
    <UITableViewDelegate, UITableViewDataSource,
     NSNetServiceDelegate, NSNetServiceBrowserDelegate>
    {
        IBOutlet UITableView *tbView;
        IBOutlet UITextView *debug;
        NSNetServiceBrowser *browser;
        NSMutableArray *services;
    }
    
    @property (nonatomic, retain) UITableView *tbView;
    @property (nonatomic, retain) UITextView *debug;
    @property (nonatomic, retain) NSNetServiceBrowser *browser;
    @property (nonatomic, retain) NSMutableArray *services;
    
    -(void) resolveIPAddress:(NSNetService *)service;
    -(void) browseServices;
    
    @end
  2. In the BonjourViewController.m file, add the following bold statements:
    #import“BonjourViewController.h”
    
    @implementation BonjourViewController
    
    @synthesize tbView;
    @synthesize debug;
    
    @synthesize browser;
    @synthesize services;
    
    -(NSInteger) tableView:(UITableView *)tableView
      numberOfRowsInSection:(NSInteger)section {
        return [self.services count];
    }
    
    -(UITableViewCell *) tableView:(UITableView *)tableView  cellForRowAtIndexPath:
             (NSIndexPath *)indexPath {
        static NSString *CellIdentifier = @“Cell”;
    
        UITableViewCell *cell = [tableView
                    dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc]
                     initWithStyle:UITableViewCellStyleDefault
                     reuseIdentifier:CellIdentifier] autorelease];
        }
        //---display the name of each service---
        cell.textLabel.text = [[self-services objectAtIndex:indexPath.row] name];
    
        return cell;
    }
    
    -(void) netServiceBrowser:(NSNetServiceBrowser *)aBrowser
                 didFindService:(NSNetService *)aService moreComing:(BOOL)more {
        [self.services addObject:aService];
        debug.text = [debug.text stringByAppendingString:
                     @“Found service. Resolving address...
    ”];
        [self resolveIPAddress:aService];
    }
    
    -(void) netServiceBrowser:(NSNetServiceBrowser *)aBrowser
            didRemoveService:(NSNetService *)aService moreComing:(BOOL)more {
        [self.services removeObject:aService];
            debug.text = [debug.text stringByAppendingFormat:@“Removed: %@
    ”,
                    [aService hostName]];
            [self.tbView reloadData];
    }
    
    -(void) resolveIPAddress:(NSNetService *)service {
        NSNetService *remoteService = service;
        remoteService.delegate = self;
        [remoteService resolveWithTimeout:0];
    }
    
    -(void) netServiceDidResolveAddress:(NSNetService *)service {
        NSData           *address = nil;
        struct sockaddr_in *socketAddress = nil;
        NSString           *ipString = nil;
        int                port;
    
        for (int i=0;i < [[service addresses] count]; i++ ) {
            address = [[service addresses] objectAtIndex: i];
            socketAddress = (struct sockaddr_in *) [address bytes];
            ipString = [NSString stringWithFormat: @“%s”,
                        inet_ntoa(socketAddress->sin_addr)];
            port = socketAddress->sin_port;
            debug.text = [debug.text stringByAppendingFormat:
                         @“Resolved: %@-->%@:%hu
    ”,
                         [service hostName], ipString, port];
    }
        [self.tbView reloadData];
    }
    
    -(void) netService:(NSNetService *)service
         didNotResolve:(NSDictionary *)errorDict {
       debug.text = [debug.text stringByAppendingFormat:
                     @“Could not resolve: %@
    ”, errorDict];
    }
    
    -(void) browseServices {
        self-services = [[NSMutableArray new] autorelease];
        self.browser = [[NSNetServiceBrowser new] autorelease];
        self.browser.delegate = self;
        [self.browser searchForServicesOfType:@“_MyService._tcp.”inDomain:@“”];
    }
    
    - (void) viewDidLoad
    {
        [self browseServices];
        [super viewDidLoad];
    }
    
    - (void)dealloc {
        [tbView release];
        [debug release];
        [browser release];
        [services release];
        [super dealloc];
    }
  3. That's it! Deploy the application onto the iPhone Simulator.
  4. In the BonjourAppDelegate.m file, change the following in bold:

    image

    FIGURE 18-3

    //---publish the service---
    netService = [[NSNetService alloc]
                  initWithDomain:@“”
                  type:@“_MyService._tcp.”
                  name:@“iOS 5 Device”
                  port:9876];
    netService.delegate = self;
    [netService publish];
  5. Deploy the application onto a real iPhone.
  6. When the application is running, it will search for all services published on the same network. As services are discovered, their names appear in the Table View. Figure 18-3 shows the Table View displaying the hostname of the devices it has discovered.

How It Works

There is quite a bit of coding involved here, so let's take a more detailed

First, you defined the browseServices method, which uses the NSNetServiceBrowser class to search for the service named“_MyService._tcp.” in the default domain:

-(void) browseServices {
    self.services = [[NSMutableArray new] autorelease];
    self.browser = [[NSNetServiceBrowser new] autorelease];
    self.browser.delegate = self;
    [self.browser searchForServicesOfType:@“_MyService._tcp.”inDomain:@“”];
}

As services are discovered, the netServiceBrowser:didFindService:moreComing: method is called. In this method, you add all the discovered services to the services mutable array:

(void) netServiceBrowser:(NSNetServiceBrowser *)aBrowser
           didFindService:(NSNetService *)aService moreComing:(BOOL)more {
    [self.services addObject:aService];
    debug.text = [debug.text stringByAppendingString:
                  @“Found service. Resolving address...
”];
    [self resolveIPAddress:aService];
}

You also try to resolve the IP address of the discovered service by calling the resolvelPhonedress: method, which you define.

The resolvelPAddress: method uses the resolveWithTimeout: method of the NSNetService instance (representing the service that was discovered) to obtain its IP addresses:

(void) resolveIPAddress:(NSNetService *)service {
    NSNetService *remoteService = service;
    remoteService.delegate = self;
    [remoteService resolveWithTimeout:0];
}

If it manages to resolve the IP addresses of the service, the netServiceDidResolveAddress: method is called. If it does not manage to resolve the IP address, the netService:didNotResolve: method is called.

In the netServiceDidResolveAddress: method, you extracted all the available IP addresses of the service and displayed them on the Text View. You then try to reload the Table View using the reloadData method of the UITableView class:

-(void) netServiceDidResolveAddress:(NSNetService *)service {
    NSData               *address = nil;
    struct sockaddr_in *socketAddress = nil;
    NSString           *ipString = nil;
    int                   port;

    for (int i=0;i < [[service addresses] count]; i++ ) {
       address = [[service addresses] objectAtlndex: i];
socketAddress = (struct sockaddr_in *) [address bytes];
       ipString = [NSString stringWithFormat: @“%s”,
                   inet_ntoa(socketAddress->sin_addr)];
       port = socketAddress->sin_port;
       debug.text = [debug.text stringByAppendingFormat:
                        @“Resolved: %@-->%@:%hu
”,
                        [service hostName], ipString, port];
   }
   [self.tbView reloadData];
}

When services are removed from the network, the netServiceBrowser:didRemoveService: method is called; therefore, in this method you remove the service from the services mutable array:

(void) netServiceBrowser:(NSNetServiceBrowser *)aBrowser
          didRemoveService:(NSNetService *)aService moreComing:(BOOL)more {
    [self.services removeObject:aService];
    debug.text = [debug.text stringByAppendingFormat:@“Removed: %@
”,
                  [aService hostName]];
    [self.tbView reloadData];
}
The rest of the code involves loading the Table View with the hostname of the
   services that have been discovered. In particular, you display the host name
   of each service in the Table View:-(NSInteger) tableView:(UITableView *)tableView
  numberOfRowsInSection:(NSInteger)section {
    return [self.services count];
}

-(UITableViewCell *) tableView:(UITableView *)tableView
    cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @“Cell”

    UITableViewCell *cell = [tableView
                             dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc]
                 initWithStyle:UITableViewCellStyleDefault
                 reuseIdentifier:CellIdentifier] autorelease];
    }

    //---display the name of each service---
    cell.textLabel.text = [[self.services objectAtIndex:indexPath.row] name];
    return cell;
}

DOING MORE WITH TCP/IP

With peers on the network discovered, what can you do next? You can use TCP/IP to connect with your network peers and send messages to them. A discussion of using TCP/IP for networking is beyond the scope of this book, but interested users can download a working application from the author's website — www.learn2develop.net — that illustrates how to build a chat application using Bonjour (see Figure 18-4).

image

FIGURE 18-4

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.3.245