Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2012-707
$eventId
ID of event: wwdc2012
$eventContentId
ID of session without event part: 707
$eventShortId
Shortened ID of event: wwdc12
$year
Year of session: 2012
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2012] [Session 707] Simplify Ne...

WWDC12 • Session 707

Simplify Networking with Bonjour

Core OS • iOS, OS X • 46:04

Learn how your network applications and services on iOS, OS X and other platforms can use Bonjour to simplify your user experience. Bonjour, also known as zero-configuration networking, is used by a wide range of products and applications for streamlined and reliable networking to easily publish, discover, and resolve network services.

Speakers: Stuart Cheshire, Bill Hoppin, Rory McGuire

Unlisted on Apple Developer site

Downloads from Apple

HD Video (147.5 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Good afternoon, ladies and gentlemen. Thanks for coming to our afternoon Bonjour session. My name is Stuart Cheshire, and I'm going to be telling you a little bit about Bonjour. First, we're going to talk about user experience, which is what Bonjour is all about. Fundamentally, that's why we built this technology, is to give a good user experience. I'm going to talk a little bit about the background and the products and platforms that use Bonjour.

I'm going to give you an overview of the technology that makes it work. And then I'm going to give you a description of the operations that you use in your applications to interact with the Bonjour services. We have a demo for you, and then my colleague, Rory McGuire, is going to go into some more in-depth information about specific programming details.

It's 2012 and we still see applications that look like this on the App Store, where the user has to type in IP addresses and port numbers and half the time they don't know what to type in. And I know you guys are in the room because you know better than this, we don't want this. We want good user experience for our customers and for yours. Here's an example of something very simple. I want to print an email. I tap on the arrow, I tap on print. There's the name of the printer. No IP addresses, no port numbers, very easy.

And of course, it's not just for iOS devices. This is a network camera made by Axis, one of my favorite network cameras. It's got a really good quality lens, good sensor, good low-light capability. And of course, it has Bonjour. So you plug the Ethernet cable in. I don't know what IP address it has. I don't care. I look in Safari. I look in the Bonjour collection. And right there, I see Access Network Camera. I double-click it, and I'm connected. I never need to see an IP address. I never need to see a port number.

So, I want to give you a little bit of a history of how we got to here with Bonjour. A little over 10 years ago, we launched Bonjour on Mac OS 10.2, and within months, the printer and scanner vendors were on board because they'd been making AppleTalk printers, and they understood the importance of ease of use their customers demanded it. Other Apple products, like Apple TV and airport base stations, use Bonjour for configuration, for backups, for communicating with iTunes.

Other third-party devices like network cameras and TiVo DVRs use Bonjour. If you guys haven't seen it, you should check out the TiVo remote control app for the iPad. It's a wonderful example of a good user experience. Stuart Cheshire, Bill Hoppin, Rory McGuire Other third-party devices like network cameras and TiVo DVRs use Bonjour. If you guys haven't seen it, you should check out the TiVo remote control app for the iPad. It's a wonderful example of a good user experience.

The TiVo guys were really creative and came up with a wonderful UI that makes use of that screen. But of course, if the user didn't know what IP address to type in, they would fall at the first hurdle, and they would never get to see all this wonderful work that the TiVo engineers did. So Bonjour enables users to connect seamlessly without worrying about IP addresses. Stuart Cheshire, Bill Hoppin, Rory McGuire Of course, when iOS devices shipped with the first iPhone, they had Bonjour from the start.

And this is not just about Apple products. If you are producing applications for other platforms, then Bonjour is available there too. Stuart Cheshire, Bill Hoppin, Rory McGuire And I mention that because some of you guys in the room are producing applications for iOS. Some of you guys are producing hardware devices and accessories.

Stuart Cheshire, Bill Hoppin, Rory McGuire And a question that we get is, Stuart Cheshire, Bill Hoppin, Rory McGuire Well, I'm making my accessory, and on Apple devices, I use Bonjour to discover it. On other platforms, do I need to use something different? And the answer is no. We have Bonjour for you on those platforms as well.

Stuart Cheshire, Bill Hoppin, Rory McGuire We have Safari on Windows with the same Bonjour collection that we have on Safari on the Mac. And if you're shipping some other Windows application, you can license the Bonjour for Windows installer for free. Stuart Cheshire, Bill Hoppin, Rory McGuire To bundle with your installer for your application. This is also available through the MFI program if you're participating in that.

So I've talked about the things that Bonjour does for you to give a good user experience. And now I want to tell you a little bit about how it does that. And there are three very simple technologies here. The first one is addressing. Now, we love DHCP. DHCP is great. You plug your laptop into the Ethernet or you join a Wi-Fi network and you get a DHCP address. And we're not competing with that.

But in the case where there isn't a DHCP server or it isn't working, we don't want all the devices to just fail. So we have a safety net. And in the case where DHCP is not available, then the device makes up its own address, selected randomly, in a range that's reserved by IANA for that purpose, and it sends an ARP request. And if nobody replies, then the device concludes, hey, this address is not in use. I can have it.

And by that mechanism, all the devices on the network can pick unique addresses. And this is great because now we've got past the first hurdle. We have a bunch of devices that have different IP addresses. But it's not a complete solution. If you don't know what the address is, then how are you going to use it? So the second step is naming.

The conventional way of naming devices on the internet with internet software is DNS host names. And just like with DHCP, DNS is great. And if you run your own DNS server at home, and you know how to maintain and configure it, and you can add your own host names to your own domain, then that's a great way of doing naming. But for many of our customers, they don't run their own DNS server at home, and we still want them to be able to refer to devices by name. So that's where multicast DNS comes in.

Same name syntax, same record types, same packet format, a standard unicast DNS. But instead of sending it to a specific configured server, it's multicast to every device on the network. And each device is running a little piece of code called the multicast DNS responder. And when it sees a query for its name, it kind of metaphorically raises its hand and says, yes, that's me. And it sends back a standard DNS format response, giving its name and its address. Stuart Cheshire, Bill Hoppin, Rory McGuire Same name syntax, same record types, same packet format, a standard unicast DNS. But instead of sending it to a specific configured server, it's multicast DNS.

But instead of sending it to a specific configured server, it's multicast DNS. DNS Service Discovery lets a piece of software say, I want to perform this particular task on the network, and I don't know what hosts provide that service, but I know the task I want to perform. And it gets back a list of the instances on the network that can meet its needs.

If you're writing an application for iOS or Mac OS X or Windows, then link local addressing is handled for you by the operating system. Multicast DNS naming is handled for you by Bonjour. If you're building a hardware device, then you'll want to do those two things. But for most people developing applications, the place you interact with Bonjour is at the service discovery layer. So I want to talk a little bit more about that now.

There are three basic API operations. The first one is registering your service. Here we have an Apple TV. We connect the power cable, and the first thing it does is announce that it provides the AirPlay service on the network. It does that in case there were clients out there listening for it. In this case, there weren't. The packet disappears into the ether.

A common misperception about Bonjour service discovery is that it works like some other service discovery protocols that are continuously broadcasting their presence on the network. Once a minute, twice a minute, ten times a second, whatever it is, continually pounding the network. Bonjour would not be sustainable if it worked like that.

After this initial announcement, the device shuts up and it just listens quietly. Now, suppose you come to visit me. You bring your iPad and you say, I've got this great slideshow of photos I'd like to show you. And rather than look on the small screen, I'd like to show you on my big screen.

You open up, you get out your iPad and you tap on the AirPlay icon and it sends out a multicast query on the network saying, are there any AirPlay services? And the Apple TV sends back a response saying, yes, I support AirPlay. And Apple TV then appears in the list of available services. That's browsing.

The next step is resolving. And this is a key point. We have two separate steps here. A lot of service discovery mechanisms in the past combined these into one. And there's a good reason why they're separate. And that is browsing the network to discover what's there is an operation that you do often relatively infrequently. For example, when you're setting up a printer, you may pick your default printer just once.

But you may print on it every day. And with the dynamic addressing that I talked about with DHCP, with link local addressing, the address might not be the same from day to day. So if when I set up my default printer, I store its IP address, then tomorrow it may not work. What I want to do is store its Bonjour service name. And then at time of day, I can set up my default printer.

And at time of use, every time I print, I do the resolve operation to say what is the current IP address and port number for this service. So in the AirPlay example, when I tap on Apple TV, it sends out a query saying what is the current right now live information for how to connect to this service.

So those are the three operations. And if you follow the advice Rory will give later about some of the higher level APIs, you don't even need to do the resolve. Because if you do, you're going to be able to do the resolve. So it's done automatically for you. You have a Bonjour service name. And you say give me a connection to this. And the resolve and connect are handled for you automatically at the API layer.

I talked about the AirPlay service, and I used that in a kind of loose human sense that the Apple TV provides the AirPlay service, but at a protocol level, we need a really rigorous definition of what it means to offer a certain service. Every service on the network is represented by a structured instance name, and this is a three-part name.

The first part is the user-visible instance name. It's rich text, uppercase, lowercase, spaces, non-Roman characters, anything you can show in Unicode you can use in the instance name. The second part of the name is the service type. In this case, it's IPP, Internet Printing Protocol. And then the final part is the domain. In this case, it's local, which means look this up on the local network with multicast DNS. With wide area Bonjour, that could be apple.com or any other domain. But right now, I want to talk about the service type.

Service types are unique strings, and they identify two things. They identify what the service does and how it does it. And I want to go into that a little bit more because that's a very important point. What the service does might be, say, printing. From the user's point of view, I want paper with letters on it.

I want printing. So that's the user's conceptual service. But there's LPR printing. There's IPP printing. There are various proprietary data stream protocols for doing printing. And if I've got a client that speaks IPP and I've got a printer that only speaks LPR, the fact that they're both printers from the human point of view doesn't help the software communicate.

So we need to know both what the service does and also what protocol it uses, that it's a protocol that we speak. And the same issue applies kind of in reverse as well, that sometimes because things are the same protocol doesn't mean that they're doing the same logical service on the network.

And I'll give an example of that. iTunes music sharing, if you look with TCP dump, is little more than HTTP GET. You want to play a song? If you want to play a piece of music, it will just do an HTTP GET for that MP4 file and start playing the music.

The fact that it's built using HTTP is a perfectly sound engineering decision. That's a good protocol to use. That doesn't mean that iTunes is serving web pages that it would make sense for you to look at in Safari, and it doesn't mean that the average web server has music that iTunes can play. Stuart Cheshire, Bill Hoppin, Rory McGuire There's a case where the on-the-wire protocol is HTTP, but the purpose is very different. The service type identifies both what the protocol is and what purpose it's being used for.

These are 15-character strings, US ASCII, letters, digits, and hyphens, and they are managed by IANA, the Internet Assigned Numbers Authority. You can see the list of service types that are already assigned at the URL there. You can apply for your own. It doesn't cost anything. It's very quick and easy.

And it's really important that you do this because they manage the unique namespace to make sure that there aren't any accidental conflicts. We don't want you to ship an application that uses DAAP for your game because DAAP is the digital audio access protocol used by iTunes. And if you were to advertise that service, your service would appear in iTunes, which probably wouldn't help because they probably don't have any music. And your clients would discover iTunes music sharing. So that's why the service type strings exist, and IANA provides this free service to the community of managing that namespace.

A question that comes up often is, yeah, Bonjour looks great, but really, we're just going to send some UDP broadcast packets. How hard could it be? Well, we thought that as well 12 years ago when we started working on this, and I can tell you some of the hurdles that you'll have to encounter.

The first very obvious one is that networking is not reliable. Packets get lost. What do you do about that? Well, everybody knows the answer. You retransmit. That's easy. But how much do you retransmit? How often? I'll give you an example of a problem that used to happen with AppleTalk.

You send a multicast query looking for printers, and 50 printers respond. But because of packet loss, you retransmit. So you send the query again, and 50 printers respond. And you send it again, and 50 printers respond. And UPnP has the same problem. To my knowledge, every other service discovery protocol has this efficiency problem.

Bonjour solves it with something called known answer lists. When I retransmit the query, I say, "Here are the 50 printers I already know about, so you guys keep quiet. Is there anybody else out there that I missed?" And what that means is that after two or three retransmissions, the query process pretty soon degenerates into a single query with no more replies. So we put a lot of work into efficiency, and that's just one example. Another issue is you will notice with Apple applications, there's no refresh button. When you want to add a printer, you don't see a flashlight panning back and forth for 10 seconds.

And then it stops. And from the moment the list is being displayed on the screen, it's already becoming stale and out of date. No. The list is pretty much immediate, and it stays up to date until you dismiss it. When new things appear, they appear in the list. When things go away, they disappear from the list.

And because we have that live update in the network view, that has got to flow through to all other aspects of the system as well. If I unplug the Ethernet cable, the services go away. If I plug it back in, they come back again. If I turn Wi-Fi off, the services go away. So handling that disconnect reconnect is something you'll want to do for a good user experience. Bonjour handles that for you. You need to monitor network configuration changes.

And I'll give you just one example of a more subtle issue. I can be on a Wi-Fi network called Linksys, and my IP address is 192.168.0.2. And I switch to a different Wi-Fi network called Linksys, and my IP address is 192.168.0.2. But it's not the same network. Detecting that case and actually correctly flushing the stale services and displaying the new ones is a tricky thing to do.

One of the things that Bonjour does for you. Along the lines of disconnecting and reconnecting, there's power management, there's sleep and wake. When I put my machine to sleep, it's no longer reachable on the network. Bonjour will send goodbye packets for you. Without your application doing anything, Bonjour will send goodbye packets.

Saying, these services are no longer available. When I wake it up, it will re-announce those services are present on the network again. Or... If you have an Apple TV or an airport base station or time capsule on the network, that offers a sleep proxy service. So when you put your iMac to sleep, instead of sending goodbye packets, it will transfer all your Bonjour records over to the sleep proxy saying, this is me, this is my identity, this is my role on the network. If anybody wants me, wake me up.

These are all things that you get when you use the Bonjour APIs, which took us a long time to build and would take you guys a long time to replicate. So with that, I want to show you a little demo of a new feature in Mountain Lion, which is... AirPlay screen mirroring. And here I have my Apple TV.

And I have an IP router here. And I have a couple of Wi-Fi access points. And I have a problem here because I have two access points with two different Wi-Fi networks with two different subnets and these devices are not on the same subnet. And normally that would be a problem, but I would like to invite Bill Hoppin, VP of Business Development at Arrowhive, to come up and explain how we're going to solve this problem.

Thanks a lot, Stuart. Thank you, Bill. Hi, everybody. I'm Bill Hoppin with Arrowhive Networks. We make Wi-Fi access points, and we end up connecting a lot of iOS and OS X devices to our access points. We're also seeing a ton of Apple TV getting deployed in big businesses, small businesses, even schools. The challenge is the Apple TVs are typically connected to a different part of the network, a different subnet. And so that means when the iPads and the Macs are connected to the Wi-Fi, they don't have access to the Apple TV.

It's a real bummer because, you know, you see that Apple TV over there. It's the best possible way to display anything on the planet. You can't have access to it. So at Arrowhive, we created this thing called a Bonjour Gateway. And what it is is basically a protocol that selectively makes Bonjour services available across the subnets, more broadly available across the deployment. And selectively is pretty key because if you make all these Bonjour services available everywhere in the network, you'd have a Bonjour services list about a mile long. You'd need a new display to look at them all.

You know, we don't want to do that. We want to do it selectively. So that's what we've done. And what it does is it allows these Macs and iPads to actually do the display mirroring, the mountain line mirroring over to the Apple TV. We also did it in a way where our product can plug in any network, no matter whose Wi-Fi is there, no matter what the configuration. And as long as one of the Arrowhive Bonjour-enabled products there will go open up this Bonjour Gateway and allow you to access these services across subnets.

So we think it's really cool. We're happy to make it available to all Apple customers all over the planet by making it sort of plug and play into any network. It's beta code that you'll see here. It's not going to be here today, but it's going to be production solid, ready to go the end of July. So take a look at arrowhive.com for more details. And thanks very much. Thank you, Bill.

Let's give this a try. So you'll see my Apple TV here is on the network Apple plus Arrowhive. And my Mac here is on Apple Arrowhive 2. You're seeing the Mac not through the projector here. This is through airplane mirroring with the Apple TV. The Apple TV is on.

The Apple plus Arrowhive network. The Mac is on a different subnet. Yet they're still discovering each other and communicating just fine. I think a lot of enterprise customers are going to be very happy with this. Thanks for this great addition to the Bonjour family, Bill. Thank you. Thank you.

And I'm happy to say it's not just Error Hive. Aruba and Zerus have also announced similar products that do this. So if this is something you need, I invite you to check out all three of these product offerings. And with that, I think we need to add one more thing to our list of reasons not to invent your own protocol. With Bonjour, you get automatic cross-subnet proxying with these services. And with that, I'd like to invite Roary McGuire to come up on stage and go into some more details on programming specifics.

Thank you, Stuart. So how do you as developers make your user experience even better? Well, let's go right into it. These are the API layers that you'll be using as developers to utilize Bonjour. Your app is over here and it can plug into three different layers of API. You can plug into NSNet services up at the Cocoa layer. You can plug into CFNet services at the CF layer. And if you really want to get down and dirty, you can plug into the DNSSD.h, the C layer API.

But instead of just showing you how to use Bonjour, we're also going to go through today how to actually open up listening sockets and how to make sure that your entire application from temp to stern is actually working in terms of networking. So in order to do that, we're also going to talk about the layers of the TCP stack, right, that you can plug into. At the Cocoa layer, we have NSInputStream and NSOutputStream.

At the CF layer, we have CFStream and CFSocket. And if you want to get down and dirty, we have the actual BSD layer, right, Socket, Bind, and Listen. And you'll actually have to use all of these layers to open up your listener, but I'm going to go through how to do that, right, so that you don't have to figure it all out for yourself.

So, what's the first thing that you do on the server side? The first thing you're going to do on the server side is actually create your socket, bind it, and then tell it to listen. These are actually the API calls. It's called socket, bind, and listen. That's going to give you a BSD layer file descriptor. It's an integer. Once you get that, that's a little too dirty. It's really down low.

Wrap it in a CF socket ref. This is going to make it a lot easier to deal with. You won't have to call select. You can actually use your CF run loop, which is toll-free bridge to your NS run loop, so that you can actually get accept events in your server.

So then you're going to take -- you're going to use the Bonjour layer to actually advertise your service. And you're going to make sure that you call it with the correct port, right? Your users don't have to type ports. Your users don't have to type IP addresses. But when you're developing your application, you have to make sure that you pass the correct port to Bonjour so that it can advertise the correct port so that your users don't have to type it. I'll go into a little more detail when I get to the code slides about this.

Once you're done actually initing that service, you're going to want to call publish. This is what actually advertises your service on the network. This is what sends those couple of advertisement packets that you saw a little bit earlier in the presentation. So what about the client side? On the client side, you're going to want to browse. You're going to want to search for services of a particular type in a domain. This is the API that you'll call in NSNet Service Browser.

You're going to get callbacks to your delegate, did find service. Let's say there's three services on the network. Let's say that we're making a mood ring application and there are three servers on the network that provide this mood ring application, this mood ring service. You're going to get three of these callbacks. Then you're going to want to let your user select one of them.

This is important. Like Stuart said, Bonjour separates browsing from resolving. You're actually going to want to let your user select the service instance they want to connect to. Don't just connect to all of them. Let your user select which one you want to connect to. Now there's some extra APIs in Bonjour that will allow you to give more information about the services so that you don't have to actually connect and get other information.

So once you've connected, what do you want to do? You actually -- or, sorry, once your user is selected, you want to connect, right? And again, like Stuart said, these APIs are going to make it really easy. You don't have to separate the resolve call and the connect call. You're going to get the NS input stream and NS output stream from your NSNet service.

You're going to schedule them in a run loop, right? Networking is difficult. You're going to want to make sure that you do things asynchronously. Do things asynchronously, right? Don't block on the main thread. It's not a good idea. And then you're going to call it open. Open on these things is actually what both resolves and connects.

So what about back on the server side? What happens when the client actually connects? Well, your CF socket ref object that's wrapping your file descriptor will actually give you an accept callback. And I'll actually go over the accept callbacks. You don't have to write your own. That is going to actually give you back an NS input stream and an NS output stream on the server side as well. Once you have that, they're connected. Right? Everything you put in the output stream on the server side gets to the input stream on the client side and vice versa.

So, what about the actual code, right? Server side. The first thing you want to do is bind listen, right? You create the socket up at the top. And you bind it and then you listen. Note that this is the IPv4 socket. You are going to want to pass port number zero in your sock adder structure.

This asks the kernel to give you an arbitrary port number. It doesn't matter what port number you have. Bonjour is going to take care of that for you so your user doesn't have to type it in. But you have to ask the kernel to give you an arbitrary one. Otherwise if you ask for the same one every time, maybe somebody else asks for that one and you are not going to be able to get it. So just let the kernel give you whatever it has available and then advertise that through Bonjour.

You're also going to want to create a separate IPv6 socket. And to this one, you're going to want to specify the port number that you got for the IPv4 socket. In Bonjour, you can't specify different port numbers for IPv4 and IPv6, so what you do is you tell the kernel, "Give me the same port number in IPv6." So what about hooking up the IPv4 socket into a CF socket? You're going to call CF socket create with native on the V4 socket.

And then you're going to call the same call on the V6 socket, right? So you'll have two CF socket ref objects, one for your V4 socket, one for your V6 socket. But notice you pass the same listening socket callback to both of those calls. And this is what it looks like. This is the code to actually get the accept callback when somebody connects to your server and actually wrap it in NSInputStream, NSOutputStream.

So keep in mind, right, hopefully all of you are already using automatic reference counting or you're going to be using it soon. Automatic reference counting is really cool. But at the CF layer, when you pass it up to automatic reference counting up in the Cocoa layer, you have to make sure to call this CF bridging release, right, to make sure that you tell the compiler, "I'm passing the retain that I got when I created this CF object up to the Cocoa layer that's going to automatically release it when you're not using it anymore." Okay, so what about the actual Bonjour call and register? So, let me go through the parameters in a little bit more detail here. The domain you're going to use is the empty string domain.

This instructs the Bonjour system to use all the domains that it has available to it. A lot of times you're only going to have .local, which is the multicast domain over the link local, like Stuart was talking about. But if your users are using Back to My Mac or if your IT guys have set up Bonjour wide area, then this will also give you potentially those domains, right? So use the empty string domain. The next thing is the type. This is the unique service identifier that Stuart was talking about. This uniquely identifies what your service does and the protocol it uses to do it. In our case of making a mood ring app, we're going to use mood ring.

and then the name. Again, you're going to want to use the empty string name. This will use the default name of your system. So in the Mac, it's in the sharing pref pane and on iOS, it's the name that you give the device in, say, iTunes. Now, you can use a different name here if you want to, and this is full Unicode character support.

If you really want to call your service something in Klingon, you can. And the port number here is also important. That arbitrary port number that you got from the kernel is what you're going to want to register here so that your client will actually connect to the correct port.

So what about register callbacks? When your service actually gets registered, when it gets down into the MDNS responder daemon and it sends out the advertised packets, you'll get this did publish callback. If you had specified the empty string domain, this is how you're going to find out what the name actually is so you can display it to the user.

Say, okay, this is the one, this is Rory's cool mood rig. And so on your client, that's the one you're going to want to choose. or it's clockback or something in Klingon. You also might get a did not publish. Make sure you handle errors. Again, networking is not easy. You're going to get errors from time to time. You're going to want to make sure that you handle those correctly.

So what about the client? On the client, you're going to want to browse for services. You don't have to deal with the lower layers in CF or in the BSD layers. You just create one of these NSNet service browser object, and you browse for the services of your type. In this case, we're doing mood ring.

You don't want to search for other people's services. You want to search for your own so that when the user selects one, they'll actually connect to your service. And again, you want to specify the empty string domain so that, say, if you're on the Mac, you can take advantage of Back to My Mac.

So what about browse callbacks? There's a couple of different browse callbacks. One is did find service. You're going to get one of these for each of the service instances that are found on the network. Now, there's a little bit of a UI hint here. Because you get one of these callbacks for each of the services that's on the network, you're going to want to pay attention to this more coming flag. Essentially, it tells you don't update your UI until this is false. Because you might flutter your UI a bunch with a bunch of things that come in, especially at the beginning.

Also, we have did remove service. Bonjour is dynamic. Things are coming and going all the time, and you're going to get these did remove service calls. You're going to want to make sure that you update your UI accordingly, and don't forget the more coming flag. You're going to want to make sure that you remove this service from your model and then update your UI when more coming is false.

So what about resolving and connecting? Well, it's actually pretty easy. All you do is you ask the service that the user selected for its input stream and its output stream, schedule them in a run loop, and open. It's that simple. Now, if you're using the kind of use case that Stuart was talking about earlier with a printer where your user has selected the service instance that it wants to connect to once, and then you're going to want to connect to that in multiple instances of your application or in multiple invocations of your application, you can construct an NSNetService object with a name and a type and a domain, and then just get the input stream, output stream, schedule it in a run loop, and open.

Schedule it in a run loop. Networking is hard. It's asynchronous. Don't do stuff on your main run loop. Don't do stuff on your main thread. So, that's the end of the coding section. What about some tips and reminders to make sure that your users get the best experience that they can? First is about Bonjour and iOS multitasking. We've done a lot of work to make sure that multitasking is a great experience for our customers. Your customers and our customers. We've done a lot of things in terms of making things efficient. When an application goes into the background, it may actually get frozen.

and stop running. Your code at some point will stop running when your application goes into the background. Before that happens, you'll get an application did inner background call in your application delegate. That doesn't mean that you're about to stop right now. It means that your application is in the background and it's going to stop at some point. Now, some of you might know that you can -- sorry, you should stop listening and registering at this point, right? If you're listening on a socket, and if you've registered with Bonjour, you're going to want to stop those operations when you get application did inner background.

And the reason you're going to want to do that is because you don't actually know when your application stops. The call that you get that says your application is going to stop, it's actually it may stop, is application did inner background. Once your application stops, if you're still registered with Bonjour and you're still listening on something, your client might try to connect and it won't be able to because your code is stuck. It's frozen. It's not just in the background running. It's in the background. background and not running.

So you might know that you can request a task completion. That really only extends the amount of time that your application is going to keep going before it stops. But at some point, your application is going to stop. What happens when your application is actually stopped? Well, your Bonjour operations may be canceled.

If you have a browse going or if you have a registration going because you didn't actually stop it when you were told that you were going in the background, they're going to be broken. The IPC calls down to the Bonjour daemon are going to be broken. Again, your code is not running. You don't know this yet. Right? This really depends on how long your application has been in the background.

If your user, say, hits the home button, switches to a different application, gets something, does something, comes right back, your application may have been running the entire time in the background. And even if it did get frozen for a little bit, your Bonjour operations may actually still be going. The same is true for your connections. If you have listening ports, those listening ports may actually have stopped listening. The kernel is going to reclaim resources to save battery power and to make user experience better. At some point, though, your code is going to start running again.

and you haven't gotten a callback yet. The callback happens some point after your code starts running, right? Otherwise you can't get the callback unless you're actually running. So the important thing to take away here is that you need to handle errors. When? When do you need to handle errors? Starting from the time that you actually did enter the background.

You have no idea when your application is actually going to stop running because your notification was at the beginning here. Any time after that is when you want to deal with the aftermath of canceled Bonjour operations and reclaimed sockets. This is going to lead to much better user experience. Applications tend to get this wrong because they don't understand that application did enter background is the call.

That's what tells you this is maybe going to happen. It might not always happen depending on how long your application was in the background, but you have to deal with errors. So at any time following that callback, all of your Bonjour operations and other networking may become broken. Your registrations might be gone, your discovery may have stopped. And a little suggestion. If you were browsing, you had your browse UI up for the user to actually select something.

If the browse was terminated, then the user had probably switched out of your app for a non-trivial amount of time. So at that point, you might want to actually dismiss that browse dialog, and when the user comes back to your app, bring the UI back up again. If you hadn't been gone that long, then keep the browse UI up, right? Because maybe they switched out and switched back again.

There's a really good tech note, tech note 2277 on networking and multitasking. I can't really recommend this one enough. It's a really good article on more of the intricate details about this. So what's going to happen if your browse was canceled? You're going to get this did not search callback from your NSNet service browser.

Another good tip, asynchronous. This one I really, I've talked about it a couple times already, networking is hard. Let me give you an example. Blocking calls are so bad you will get jettisoned. The DNS timeout on iOS is 30 seconds. The watchdog timer that kills your app is 20 seconds. So what happens if you block your main thread for 30 seconds? Well, at 20 seconds, you get jettisoned. That's bad user experience. Make sure that you use asynchronous calls.

The NS APIs, and especially Grand Central Dispatch, are excellent for this. There's a session on Friday about Grand Central Dispatch blocks and some other type code. It's a great programming model. I absolutely love GCD. I really think it's the best thing since sliced bread. It's excellent. And it's a good way to do networking because everything is asynchronous.

Another couple things to talk about are make sure you use live dynamic UI. Again, do we have a flashlight? Ten seconds? No. We don't have a flashlight for ten seconds. You have a live dynamic UI. There's no need for a refresh button. But make sure you consider your user experience. Make sure that they understand that this is a live UI. Right? That's going to be key for your user experience. It is a live UI, so make sure that your users understand it.

Also, don't do open-ended browsing. Don't keep browsing in the background. Don't browse while the user isn't actively going to select one of those service instances. There's no need to. It puts packets on the network that don't actually need to be there. Also, make sure that you stop browsing when that UI goes away.

That actually was a bug in some code that I found recently where we would destroy the NSView object that was showing this thing and it was still browsing. And that wasn't good. Make sure that you clean up your browse when your user is no longer seeing that UI.

This one's very important. Resolve and connect only to the service that your user chooses. Don't connect to every service. It's better described graphically. So you can think of Bonjour services in a particular type as being a table on the network, right? There's a bunch of application service instances out there for, say, your mood ring service or a printing service. When you browse, you get a little bit of information about all of the services, right? The name.

When you resolve, you get a lot of information about one service. Notice that we didn't have to fill in the whole table. If you were to actually resolve everything you got in the browse callback, you would fill in the whole table. That's not efficient on the network, right? It's going to be bad for battery life. It's going to be bad for your user experience.

So what about saving services you found? Again, if you're using the kind of MO where your user's going to select an instance once and then connect that instance multiple times for multiple implications, what are you going to want to store? Well, as Stuart said before, you're not going to want to store the IP address, right? IP addresses can change. You're also not going to want to store the port number because your port numbers will change because hopefully every time your server starts, you're asking the kernel for an arbitrary port number, so don't store the port number.

Don't even save the host name in the port number because the host name can actually change. What identifies the service is the service name, type, and domain that Stuart talked about a little bit earlier. So the right way is late binding, right? It doesn't matter what the IP address is until you actually need it.

It doesn't matter what the port number is until you actually need it. The service is identified by the three-tuple of the name, type, domain. That's what you're going to want to save, and that's what you're going to want to put into your... ...NSNetService object to actually get the NSInputStream, OutputStream, put it on your run loop, and open it.

So for some more information, we have a couple of evangelists that will be happy to answer your questions. There's some good documentation on the Bonjour developer web page. There's a couple of samples out there. A new sample since last year's WWDC is something called Remote Currency. It's a great sample to deal with networking. Of course, there's always the developer forms.

There's the Networking Best Practices section, which was actually just before this one in this room. So when the sessions come out on podcast, that's an excellent session to go back and see. It talks about intricacies of TCP and how networking works and how networking is hard to do and make sure that you know about the APIs that will make your user experience better. There's also the GCD session on Friday in Pacific Heights at 9:00. So in summary, Networking is hard, right? Networking is not easy to do. Bonjour makes it easier.

Your UI should update live. You don't need a refresh button. You definitely don't need a flashlight. Use late binding. Your name type domain tuple is what you want to store if you're going to be storing information about the service. After receiving application data in your background, expect and handle errors, right? And make sure that you register your service types. It's free. It's easy. It will make sure that you don't conflict with other people. Thank you very much.