Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX

By submitting your information, you agree that devx.com may send you DevX offers via email, phone and text message, as well as email offers about other products and services that DevX believes may be of interest to you. DevX will process your information in accordance with the Quinstreet Privacy Policy.


Bonjour Programming on the iPhone, Part I  : Page 2

Bonjour is Apple's implementation of the Zeroconf protocol, which enables the automatic discovery of computers, devices and services on an IP network.




Application Security Testing: An Integral Part of DevOps

In the BonjourViewController.h file, add the following statements in bold:

#import <UIKit/UIKit.h> @interface BonjourViewController : UIViewController {    IBOutlet UITableView *tbView;    IBOutlet UITextField *message;    IBOutlet UITextView *debug;    //---use for browsing services---    NSNetServiceBrowser *browser;    NSMutableArray *services; } @property (nonatomic, retain) UITableView *tbView; @property (nonatomic, retain) UITextField *message; @property (nonatomic, retain) UITextView *debug; @property (readwrite, retain) NSNetServiceBrowser *browser; @property (readwrite, retain) NSMutableArray *services; -(IBAction) btnConnect:(id)sender; -(IBAction) btnSend:(id)sender; -(IBAction) doneEditing; @end

In the BonjourViewController.m file, add the following statements in bold:

#import "BonjourViewController.h" #import <netinet/in.h> @implementation BonjourViewController @synthesize tbView; @synthesize message; @synthesize debug; @synthesize browser; @synthesize services; //---set the number of rows in the TableView--- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {     return [services count];     } //---display the individual rows in the TableView--- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    static NSString *CellIdentifier = @"Cell";        UITableViewCell *cell = [tableView        dequeueReusableCellWithIdentifier:CellIdentifier];    if (cell == nil) {        cell = [[[UITableViewCell alloc]            initWithStyle:UITableViewCell StyleDefault            reuseIdentifier:CellIdentifie r] autorelease];    }    //---display the hostname of each service---    cell.textLabel.text = [[services objectAtIndex:indexPath.row] hostName];    return cell; } //---browse for services--- -(void) browseServices {    services = [NSMutableArray new];    self.browser = [[NSNetServiceBrowser new] autorelease];    self.browser.delegate = self;    [self.browser searchForServicesOfType:@"_MyService._tcp." inDomain:@""]; } -(void)viewDidLoad {    [self browseServices];    [super viewDidLoad]; } //---hide the keyboard--- -(IBAction) doneEditing {    [message resignFirstResponder];     } //---services found--- -(void)netServiceBrowser:(NSNetServiceBrowser *)aBrowser          didFindService:(NSNetService *)aService moreComing:(BOOL)more {    [services addObject:aService];    debug.text = [debug.text stringByAppendingString:                  ;    @"Found service. Resolving address...\n"];    [self resolveIPAddress:aService]; } //---services removed from the network--- -(void)netServiceBrowser:(NSNetServiceBrowser *)aBrowser        didRemoveService:(NSNetService *)aService moreComing:(BOOL)more {    [services removeObject:aService];    debug.text = [debug.text stringByAppendingFormat:@"Removed: %@\n",                  ;    [aService hostName]];    [self.tbView reloadData]; } //---resolve the IP address of a service--- -(void) resolveIPAddress:(NSNetService *)service {        NSNetService *remoteService = service;    remoteService.delegate = self;    [remoteService resolveWithTimeout:0]; } //---managed to resolve--- -(void)netServiceDidResolveAddress:(NSNetService *)service {    NSString           *name = nil;    NSData             *address = nil;    struct sockaddr_in *socketAddress = nil;    NSString           *ipString = nil;    int                port;    for(int i=0;i < [[service addresses] count]; i++ )    {        name = [service name];        address = [[service addresses] objectAtIndex: i];        socketAddress = (struct sockaddr_in *) [address bytes];        ipString = [NSString stringWithFormat: @"%s",            inet_ntoa(socketAddress->s in_addr)];        port = socketAddress->sin_port;        debug.text = [debug.text stringByAppendingFormat:            @"Resolved: %@-->%@:%hu\n", [service hostName], ipString, port];    }    [self.tbView reloadData]; } //---did not managed to resolve--- -(void)netService:(NSNetService *)service    didNotResolve:(NSDictionary *)errorDict {    debug.text = [debug.text stringByAppendingFormat:                  ;    @"Could not resolve: %@\n", errorDict]; } - (void)dealloc {    [tbView release];    [message release];    [debug release];        [browser release];    [services release];        [super dealloc]; } @end

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

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

As services are discovered, the netServiceBrowser: didFindService:moreComing: method will be called. In this method, you will add all the discovered services into the services mutable array. You will also try to resolve the IP address of the discovered service by calling the resolveIPAddress: method, which you will define.

The resolveIPAddress: method uses the resolveWithTimeout: method of the NSNetService instance (representing the service that was discovered) to obtain its IP address. If it managed to resolve the IP address, the netServiceDidResolveAddress: method will be called. If it did not managed to resolve the IP address, the netService:didNotResolve: method will be called.

In the netServiceDidResolveAddress: method, you extract the IP addresses of the service. You then try to reload the TableView.

When services are removed from the network, the netServiceBrowser:didRemoveService: method will be called, and hence in this method you will remove the service from the services mutable array.

The rest of the code involves load the TableView with the host name of the services that have been discovered.

Testing the Application

Figure 3: Discovering services published on the same network.

That's it! Try deploying the application onto two devices (one on the iPhone Simulator and one on a real device). When the application is running, it will search for all services published on the same network. As services are discovered, you will be able to see the their names appear in the TableView (see Figure 3).


In this article, you have seen how to publish a service on the network and how to discover them on the local network. In the next article, I will show you how you can communicate with another device on the network using TCP/IP.

Wei-Meng Lee is a Microsoft MVP and founder of Developer Learning Solutions, a technology company specializing in hands-on training on the latest Microsoft technologies. He is an established developer and trainer specializing in .NET and wireless technologies. Wei-Meng speaks regularly at international conferences and has authored and coauthored numerous books on .NET, XML, and wireless technologies. He writes extensively on topics ranging from .NET to Mac OS X. He is also the author of the .NET Compact Framework Pocket Guide, ASP.NET 2.0: A Developer's Notebook (both from O'Reilly Media, Inc.), and Programming Sudoku (Apress). Here is Wei-Meng's blog.
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.
Thanks for your registration, follow us on our social networks to keep up-to-date