Bonjour is Apple’s implementation of the ZeroConf standard, which allows services to advertise themselves on a network. It also allows clients to search for services. In this chapter, you are going to create an application that advertises its presence on the local network. It will also search for other devices on the network that advertise the same Bonjour service. The application will display a table view that lists every device running the Bonjour service on the network and a message that the application includes in its advertisement.
Create a new Window-based Application called Nayberz. The first step is to advertise a Bonjour service. This is done by creating an instance of NSNetService
and publishing it. In NayberzAppDelegate.h
, add an instance variable for the net service you are publishing:
Then, in NayberzAppDelegate.m
, create and publish the service:
In that same file, add two net service delegate methods:
Back in NayberzAppDelegate.h, add the following protocol to the class declaration:
When the user exits an application that uses Bonjour, you should shut down the advertisement of services and restart the advertisement when the application launches again. Add two more application delegate methods to NayberzAppDelegate.m to do this:
Build and run the application. You will see on the console that the service was successfully published.
Now you’re going to create a UITableViewController
that displays the Bonjour services that the application discovers in its table view. It will have an instance of NSNetServiceBrowser
and an array of NSNetService
objects that it finds. In Xcode, create a new UIViewController subclass (without a XIB) and name it TableController
.
Open TableController.h
and change the superclass to UITableViewController
.
@interface TableController : UITableViewController
Now create an instance of this view controller and put it on the window. In application:didFinishLaunchingWithOptions:
, create the instance and put its view on the window. Also, import the header file for TableController
at the top of NayberzAppDelegate.m:
Build and run the application. The table view will appear, but it will be empty. Next you are going to fill it with data.
Open TableController.h
and add two instance variables:
In TableController.m
, create an init
method that specifies the style of the table view and creates an empty mutable array. Then, create an instance of NSNetServiceBrowser
and start it searching:
Add the NSNetServiceBrowserDelegate
and NSNetServiceDelegate
protocols to the class declaration:
Also, override the required data source methods:
Now implement the net service browser delegate methods:
Build and run the application on more than one device on the local network. (One of these devices can be the simulator.) In the table view, you will see the device names of all the phones on the local network.
Sometimes it is convenient for a service to include additional useful information that can be read by clients. For example, a printer may tell clients it is in the third-floor library, or a workstation might display the rules for using it. Every NSNetService
has a TXT Record for this purpose. In NayberzAppDelegate.h,
declare a method that will create a TXT record for the netService.
Define this method in NayberzAppDelegate.m
.
In NayberzAppDelegate.m
, update application:didFinishLaunchingWithOptions:
so that it gives the netService an initial message.
The TXT record is not in the initial contact from the published service; the client must first resolve it. You can think of the initial contact (when the NSNetServiceBrowser finds the service) as the first meeting between two people. Resolving, then, is their first date, where the client finds out a bunch of additional information about the service it has found. In TableController.m, send these services on a nice date.
When the net service succeeds in resolving, it sends the message netServiceDidResolveAddress:
to its delegate. When this message is sent, the TXT record for the net service will be valid. Implement this method in TableController.m
.
Display the message in the table view cell:
Build and run the application.
A lot of people may read this chapter and think to themselves, “Well, I guess Bonjour is cool. But I don’t see the point – all I can do is advertise a single chunk of text.” Oh, but there is so much more!
When an NSNetService
is resolved, you can send it the message addresses
. This method returns an NSArray
of NSData
instances. Each NSData
instance actually contains a sockaddr_in
. A sockaddr_in
is a TCP/IP structure that can be used for low-level TCP/IP communication. (There is typically only one address for a server, but there could be more.)
What’s that mean? You can make socket connections to a server advertising an NSNetService
, and, once you have a socket connection, you can communicate back and forth. Unfortunately, making a socket connection and passing data back and forth on it are beyond the scope of this book. Network programming is a huge topic, and there are plenty of resources out there. The best one is Beej’s Guide to Network Programming (http://beej.us/guide/bgnet/).
To get you started, here’s how to extract the sockaddr_in
structure from an NSNetService
. At the top of TableController.m
, import two header files from the standard C library.
#import <netinet/in.h>
#import <arpa/inet.h>
When a Bonjour service is resolved, you will print out its IP address and port number. Add the following code to netServiceDidResolveAddress:
in TableController.m
.
Build and run the application. When a net service resolves, check the console. You will see the IP address and port of the Bonjour server you found. Notice that the port printed to the console is the same port number you advertise the Bonjour service on.
If you wish to dive deeper into network programming, definitely read Beej’s guide. Whether you program using standard C networking code or using Core Foundation or Foundation’s streaming APIs, the concepts discussed in the guide are very important.