Greetings, my name is Quinn "The Eskimo", and I work in Apple's developer technical support group answering questions from developers like you about networking file system threads and other core OS related matters.
Welcome to Network Apps for iPhone OS, and you'll note this is an iPhone OS, not iOS, because we're talking about stuff that already exists, not the stuff to be released in the next few days.
We're going to start off today with a question.
Why are we here?
I don't know why you guys are here; I suspect it might be because, at least, some of you are sleeping off lunch in the back.
But most of you I expect are here because you have network applications in the Store and you'd like to figure out how to make those applications better, or because you have, an application and you're planning to add networking, or you're planning to create a new application that uses networking.
But there's a flip side to this question, which is why am I here.
Now I've worked in DTS for about 15 years now, and in the last few years, we've seen a massive increase in the number of networking questions that I receive.
And, so the reason why I am here is to try and stop those questions, and its, altruism is dead, as they say.
Now the, in order to solve a problem you really need to understand it, and so to understand why we're here I sort of sat down and thought well, why I am here and why are you guys asking questions, and the first answer was this guy here.
This is the iPhone, and if you think about it networking is central to the iPhone, it's in the name, and it's not just in the name once, it's in the name twice, and networking is central to the iPhone and that, there's a lot of interest in the iPhone and it's generated a lot of questions.
But it's not just the iPhone, networking is central to every product that Apple ships; from the lowliest iPod Touch to the beefy Xserve.
Networking is an essential part of their functionality, but there's more to it than that.
It's not just that networking is central, so we get a lot to these products, and so we get a lot of questions, but it's also that networking is hard.
It's a fundamentally hard topic.
Everything runs asynchronously, you can't control the environment.
Networking is a difficult thing to do right, and so we get a lot of questions, because networking is difficult and so my goal here is to sort of explain the problem and explain the architecture that you can adopt to get a good solution.
So we're going to start, again, with the problem and this is what I call my spinning pizza of network death.
Listed around the pizza are slices of network horror that you have to deal with.
I'm going to go around the spinning pizza looking at each slice in turn, and sort of explaining the problem, so that we can then understand why that we need to architect solutions for these problems.
And to start, we are going to go look at packet problems.
And packet problems are sort of the traditional problems in networking.
It's corrupt packets, dropped packets, reordered packets and so on.
And these aren't, isn't really a huge problem these days.
People working on machines like you see there, in the 70's came up with solutions to these problems, and the primary solution is TCP.
TCP is a fabulous piece of design.
It allows you to pour a stream of data into one end of the Internet and get it out the other end in a completely reliable fashion, what you get in is what you get out.
Unless the network just is completely broken, and in that case, the connection tears, so it's a fundamental piece of any network solution, is TCP.
So the end result of that is packet problems aren't really an issue.
Every platform has TCP and you can just use it, and that's good.
But in this other, not a, not necessarily interesting solution, problem, and that's bandwidth.
Bandwidth, most people have a good understanding of Bandwidth.
It's the amount of data that you can get through the network at any given unit of time, and it's got to the point where ISP's will say, you know 8 megabytes per second, and so bandwidth isn't really an issue.
Most people who program on the network realize that the network has a fundamentally limit to the amount of bandwidth it has and they can cope with that.
The only real "gotcha" with bandwidth is cost, in some places.
I was visiting my family in Australia and this was the case, where the bandwidth is, you pay for every packet you send and so the only real "gotcha" there is that you have be careful about that.
In contrast to bandwidth, latency is a real challenge.
Lots of people programming for networking don't really understand the issue of latency and how critical latency is to network performance.
Now to illustrate this, I've created my silly little social networking application here, it's called qBook, it's, as I like I to like say, the social networking application for the anti-social, which is me.
Now if you look at this display, you can see that it's got a list of friends, and for each friend, it's got a thumbnail, and so when you translate that to a network architecture it might be, well, you make a request with the list of friends, and then you make a request for each thumbnail for the friends.
And so, how this might look in a timeline is this, you make little request of the list of friends and you get the results, and you thumbnail one, thumbnail two and thumbnail three.
Now each of these requests take a certain amount of time and that's the latency.
And it's important to realize that the latency is only minimally related to bandwidth.
For example, if you transfer data across the wider Internet, you might expect a latency of 200 milliseconds, and that's the same latency for a tiny packet as it is for a huge packet, so latency is sort of a fixed feature of the network.
And so you really need to do, to improve the performance of your network products, you really need to work on hiding this latency and doing the best to minimize that.
And if you think about this diagram here, you can easily see how you could recode it to do this.
Where you make a requested listed of friends, and once you've got list of friends, you know all the thumbnails you need, and so you dispatch request immediately for one, two and three, and then they come back, you know after a certain amount of time.
And so now you've sort of doubled the performance of your networking, and if you think about this, if you're requesting ten thumbnails, you would have likely increased the performance by about five times.
So, clearly, latency hiding is a critical part of performance.
But it's not just that either.
If you imagine iPhone OS, often you find yourself running on cellular networks.
And with the cellular technologies we have today, latency is rather extreme.
It typically adds about 200 milliseconds to the round trip time, so if you think about 200 milliseconds across the wider Internet, if you're on a cellular phone, that's 400 milliseconds, so the maximum number of requests and responses that you can receive, in any given second is about 2.
So, and that's completely independent to the bandwidth, you can add more and more bandwidth, but the latency never drops, and so to illustrate this, look what happens when you stretch out the latency by double.
Now if you consider real time, which is the time the user is waiting, the amount of time that the user has to wait in the serial case, is much greater and this is a real good illustration of why latency is so critical to network performance.
Now, in addition to this, all of these techniques to hide latency have their issues.
We're going to go back to the small diagram here, because it's easier to see, but imagine, this is really the ideal world, you've requested thumbnail one, two and three, you get them back in that order.
That's really not what happens on the Internet.
What happens is you get something like this, where you make the request for the friend list, you get that result and you request thumbnails one, two and three and you get them back in the order two, one, three, and, in fact, three may never come back, apparently it's gone off with a fairy somewhere.
So, it's important to understand what's going on here.
We've introduced parallelism into our program in order to hide latency, but by adding parallelism into our program, we've complicated the program, because now we have to deal with requests completing out of order.
And so this is sort of just a fundamental truth of networking.
You just, you can't do anything about latency, you just have to plan for it.
And that's planning at both the protocol level, which is how you dispatch requests across the network, and it's also planning at the architectural level, how do you structure your program to deal with these parallel requests and to get the responses out of order and so on.
So that pretty much wraps it up for latency.
The next issue I wanted to look at was service discovery.
Now service discovery divides into one of two cams, if you have a centralized server design where there's one server out there on the Internet, then service discovery is very easy.
You take your DNS name, you hard wire into all your clients, clients connect to the server by result of the DNS name, that's simple.
But service discovery, in a peer-to-peer environment, is much trickier.
And for that, at Apple, we have a technology called Bonjour.
Now there was a session on Bonjour earlier today, it's too big for me to cover in this session here, so if you're interested, you'll just have to go grab the session on the off video, and you can learn all about how to do peer-to-peer service discovery using Bonjour, it's fabulous stuff, Monsieur always give good preso as well, so it's well worth the effort.
Our next item here is asymmetric connectivity.
Back when the Internet was first created, every host could connect to every other host on the net, it was entirely, peer-to-peer was perfectly reasonable, but it's not how it works today.
If you imagine a common network setup, here we have an iPad and an iPhone attached to a network that's controlled by NAT, a Network Address Translation box, that goes across the wider Internet to a Firewall, which then gets you through to the server, and connectivity typically runs in this direction.
Everyone's pretty much aware of this, clients always connect to servers, and that's good.
What doesn't work well is this, where the server tries to connect back to the client, it generally, it's possible to do this, there are techniques you can use for NAT tunneling and so on, but it generally is very painful.
So, if you do want to do the, make your life easier, it's generally best to try and get your clients to connect to your servers.
But another wrinkle on this is this here, where you have two clients, both on the same network, that can't necessarily talk to each other.
We see this in Wi-Fi hotspots, we all see this on cellular networks where there are two clients on the same network, behind the same NAT, but they're segregated from each other by the security policy of the network.
So, that's asymmetric connectivity, and it's just something you have to watch out for, when you plan your networking.
And finally, well not finally, because we're going to do security, and that's the big one, we have the issue of mobility, which is sort of a generic term that Apple uses to cover all the sorts of things that require for an application to deal with a dynamic network.
If you think about, again, when the Internet was first invented, well actually we're going to look at this question here, which I get quite a bit, which is what's the IP address of a device?
And it's sort of one those bogus questions, it made sense back when devices looked like that, giant backs, everything was hard wired, everything had a single IP address or a small number of IP addresses, and they didn't change much, they were the same from day to day and from week to week and month to month.
And it's not just that the IP addresses that stayed the same; the level of connectivity stayed the same.
They might have been connected by very slow networks, but those networks tended to work the same from day to day.
In contrast, iPhones don't work that way, iPhones have lots of IP addresses, they have lots of network interfaces, the IP addresses can come and go from minute to minute and likewise the connectivity can come and go from minute to minute.
If you're, if the user is on their iPhone and they step into an elevator and the doors close, well the metal walls of the elevator prevent the radio signals entering and suddenly you have no connectivity at all, and for the next minute or two, your application has no connectivity, and then a couple of minutes later, the elevator doors open, and the user gets out and they've got connectivity back again.
And you have to design your applications to cope with environments like that, highly dynamic environments.
There's all sorts of things you can do here.
You can do things like doing automatic retry's, where if something fails, you don't just tell the user about it, you say, let's try it again and see if it works the second time, up to some limit obviously.
You also want to do things like resume transfers, if you've downloaded 90% of a file and network connectivity goes away, you really want to make sure that the download continues from where you left off, not downloads the entire 90% again.
And similarly there's this notion of persistent state, where if the user quits the application, you want to really try and maintain a view of what's out there on the network so that you don't have to hit the network in order to regenerate that view.
So, there's all so sorts of things that you can do to deal with mobility, but the key thing is to think about it carefully.
And finally, as I mentioned, the security.
This is a big slice of pie because it contains a lot of issues and it's often very daunting, I see comments like this.
I don't care about security, because, because my application is just a game, or because my applications only used on local network, so whatever, and whenever I see these comments, I give them the big Fail stamp.
You have to care about security.
The threats out there on the Internet are extreme, and there's no doubt about that, you see it every day on the news.
And in addition to that, the data that the user gives to you, and puts in your trust as an application developer can be extremely confidential and you can't tell whether the data is going to be confidential or not.
And so, to illustrate this point, I went through my personal iPhone and I looked at the applications on it and I sort of ignored all the Apple applications and I ignored all the applications that didn't do networking, and I came up with this list of applications, and so some of them, obviously need security, things like instant messaging, clearly I want my messages to be private, and in addition to that I don't want anyone spoofing my messages.
And other obvious ones, just like my Shopping application has my credit card, or my banking application has my bank account, but there's non-obvious ones as well.
If your writing a to-do list application, what you're thinking about is creating a to-do list and how the user edits them and so on, you're not really thinking about networking, but when your users come to you and say, "Well I would really like to sync the to-do list."
They don't realize that you might respond to that by producing an insecure syncing mechanism, and then the to-do list is going in the clear over the network.
Now for most users, to-do lists aren't that secret, you know go shopping or whatever, but I can imagine some users have very secure or very sensitive to-do lists, yeah, launch iPhone 4, for example.
So, there's a case where you just don't know whether the user's data is confidential or not.
And you really have to do deal with security, even though you might not think so.
Another example is my favorite TV remote control example.
If you're building a TV remote control application, it's one of those I don't care about security because it's only on the local network, and it's like, no, I can think of at least two reasons why I would like, a user might like to hide the contents of their TV.
And not only hide it from in general, but specifically hide it from people on the local network.
You will have to fill in the blanks there.
But there's this idea of, you know this data isn't sensitive, you just don't know that, and so my watchwords here are secure by default.
Add the security to start off with, plan for it in advance, don't just say, "Oh, I don't need security because."
Now to break down security, there's a number of different sections in security; there's authentication and authorization, and authentication and authorization are commonly mixed up, so we are actually going to deal with those together.
First, some definitions, authentication is about who's at the other end of the network.
Who am I talking to, and that an essential part of any sort of network communication.
If you think about it, networking is all about transferring data, you're going send data to someone or you're going to get data from someone.
If you don't know who's at the other end of the wire, then sending them data that might be potentially confidential is a problem, and similarly, if you don't know who's at the other end of the data accepting malicious data from them is your problem, so authentication is critical.
There's also authorization, and that's deciding once you know who's at the other end of the wire, what can they do, can they upload this photo, can they access this database record, and so on.
And so with those definitions in hand, we're going to look at the common cases of authentication and authorization, and the most critical one is Client Authenticates Server.
If you're writing a network client and you're talking to a server, you absolutely must know that the server that you're talking to is the server you expected to be talking too.
There are a variety of networks, there's the, you know, free public Wi-Fi network for example, where the servers on that network, just can't be trusted, and in fact, pretty much with an iPhone, which goes out into the real world, you can't trust any network.
So you have to have Client Authenticates Server authentication.
The next most common one is where the server has to authorize the client.
It has to say, "Well, this client can do this or can do that."
And clearly to do that, the server also has to authenticate the client, but that's sort of a side effect of the real desire to authorize the client.
And finally, there's the case where sometimes the clients need to authorize the server.
It's fairly rare, but it does happen.
A web browser is a good example.
If a server says to the client, "Here, have this cookie."
The client has to make an authorization decision as to whether it's going to hold onto the cookie or not and for how long.
And the next item here is privacy.
I want to stress here that we're talking about on the wire privacy.
This is a talk for network application developers and so for example, the privacy of the user's data on your server is not really, what I'm talking about here.
I'm talking about the privacy of the user's data as it goes across the network, in fact, I've talked about privacy a lot already, I think I sort of made the point there, so I'm going to skip that on and move straight on to malicious attack.
Oh, what to say about malicious attack; malicious attack is a tricky one.
It's very hard to defend against, it's a complicated topic, and it's way beyond the scope of what I can cover here.
Fortunately, there's an entire session about this sort of thing, called Creating Secure Applications in iPhone OS.
So, that wraps up the spinning pizza of network death, we've looked at all the slices, we sort of understand the problem, and it's well, what are we going to do about that problem?
And, so we've established that networking is hard, so what are we going to do about it, the answer is, we need good architecture.
Architecture is critical to solving network problems.
Apple can add more and more networking APIs to the system, but unless you architect application properly, it won't make a difference.
You have to design your application well, and it's not really a question of API's.
And also in this first talk, I'm just going to cover security using the Transport Layer Security mechanism just as a little aside at the end of the talk, because security really is that important.
In my second talk, I'm going to cover more practical things; asynchronous programming, network debugging and a short list of the more common mistakes I see.
But we're going to start here with architecture.
I was thinking about architecture and I was thinking about San Francisco, I was thinking about what's the best combination of those two, and it's the bridge, I love the bridge.
When I might come to San Francisco, I really like to try and catch up with the bridge it's fabulous.
So I took the bridge architecture and I turned it into my second cheesy graphic for today.
And each component of the bridge is a different component of the architecture I want to talk about.
To start with is the User Interface, you know, why we built the bridge in the first place, was so people could drive across it.
The wires of the On-The-Wire-Architecture, obviously, and then the two towers are sort of the fundamental bits of architecture.
The Platform Architecture, which is what iPhone OS does for you, and the In-Memory architecture, which is how to structure your application.
So we're going to start with User Interface, and people who know me will know what am I doing up on stage talking about User Interface, clearly not qualified.
But, it is really important to get your User Interface right.
The thing I'd like to say here is, don't make promises that the network can't deliver.
The network is not infinitely fast or infinitely reliable or infinitely responsive in the case of latency.
Your goal, as an application developer, is often to hide the networks details from a developer.
You're trying to make it so that the networking is seamless in your application.
But if you do that too well, then you hide, then you confuse the user into thinking that the network will always work perfectly, and that not the case.
Sometimes the network fails.
So you need to give the user subtle cues as to you're doing something for the network, in some cases unsubtle cues, that you're doing something for the network, so that they understand that if the network goes away, that thing won't work.
And so if you look through iPhone applications, you'll see a bunch of places where this happens, but it's worth thinking about them in a little more detail, rather than just sort of accepting them as truth.
The first one of these that I want to look at is placeholders.
We see this on iPhone OS all the time.
Here's my bogus social networking application, again, and in the top cell you see a placeholder for the thumbnail image.
Why is that placeholder there?
Why do we need placeholders?
And the answer is it's the latency hiding mechanism, the application can get the list of friends, but it can't get all the thumbnails immediately, and so instead of, I mean as we saw before, thumbnail three was off with the fairies and we don't know why it's not come back, we will eventually time it out and retry, but we want to show the user something and we don't want to do something like, hide the entire display of the friends list, just because we've missed one of these images.
So you need to think a little bit about why the placeholders are there.
Another example I'd like to talk about is the misnotion of solicited and unsolicited operations.
Network operations like to divide into these two categories.
Solicited operations are the ones the user has specifically requested, they've said launch your application and click the log in button or they've clicked on a user in the list of users and want to see all the user's details.
Unsolicited operations are those that happen as sort of a side effect of solicited operations.
An example of that might be downloading a thumbnail.
The user didn't really ask for the thumbnails, the user asked for the overall list, and you've given them the overall list, and the thumbnails are sort of the secondary stuff that's going on in the background.
These affect your User Interface, because, for example, solicited operations you really want to show progress, and you really want to show a cancellation dialogue and you want to inform the users where things have gone wrong.
In contrast, unsolicited operations, the user didn't really ask for them, so it's like, eh, what do you do?
And a good example of that is the placeholder, well you just show a placeholder, and if the connection fails, you might show a broken image as opposed to just the empty placeholder.
You don't really need to put up a big alert saying, we couldn't download that thumbnail, it's like the user doesn't care.
It's also critical to remember that a given operation can be either solicited or unsolicited depending on the context.
If I click the sync button, that's a solicited operation, but if the application syncs every hour, then that's an unsolicited operation and your error display needs to work appropriately in your progress display and so on.
Modality, I've got the good and bad examples here.
I used my own application for this so that I wouldn't be picking on anybody.
So here you see the application on the left, highly modal, it's syncing the list, put up the big grey progress bar, with the big spinner, and the user can't do anything.
The application on the right is very un-modal.
It's syncing in the background, it's got a little bit of status information there and the user can keep using the application.
My model here is the Apple application's.
If you use Safari, it doesn't, if you load one page and it's busily loading off the network, it doesn't stop you from making another page and loading something else, you know, it doesn't stop you from going to the bookmarks and so on.
You can keep using the application, even though it's doing something and that's sort of a critical design goal for any sort of networking application.
And my last item here is errors, and again, I have good and bad examples.
Throwing out error dialogue in the user's face is kind of annoying, especially for unsolicited operations.
For solicited operations, there's more excuse, yeah, but in general it's much better to try to get the error dialogues to be non-modal, although the error's not an error dialogue at that point, but the error information, display it alongside the progress information, and try and make it non-modal.
There's another crime here too, which is this second line of text, Connection Reset by Peer.
You may understand this, a small fraction of the audience I'm sure understands TCP at a deep level and knows what Connection Reset by Peer means.
But your users have no idea.
That doesn't belong on a screen.
This is the network as firewall classified.
And so with that, we've covered the sort of things I wanted to talk about User Interface, we're next going to move on to On-The-Wire-Architecture.
There's two fundamental On-The-Wire-Architectures, I sort of talked about these a little bit, but I want to make them explicit.
There's a centralized server design where there is a server out there on the wider Internet and all the clients connect to it, and then there's this peer-to-peer model, and the real question is which one do you chose if you're starting from scratch.
I have my algorithm here for doing this.
To start with, if you're building an application that talks a specific protocol, if you build, then you don't get a choice; you have to conform to whatever the application used.
So, for example, if you're doing a Twitter client, you have to speak to a different protocol and that's always centralized server, no choice there.
My next step is, if it's compatible with centralized server, use centralized server, generally centralized server is going to be easier, and I'm going to talk a few points about why it's going to be easier on the next slide, for the moment, you're just going to have to trust me on that one.
And finally, some architectures are only compatible with peer-to-peer designs.
A real-time networking game for example, you know if you playing a tank game, doing it with centralized server is going to be tricky because of the latencies involved, sometimes it's possible to do, but sometimes it's just impossible, especially if you're playing over cellular.
So, if that's your only choice, then that's your only choice and you have to use peer-to-peer.
Now looking at centralized server, why is it easier?
And the answer is because of all the networking problems I listed in the first section of this talk, centralized server makes the bunch of them much easier.
Service discovery, as I mentioned, it's just DNS resolution in a centralized server design.
Asymmetric connectivity, as we showed, it's much easier for all your clients to connect to one server out there on the Internet.
Security is much much easier in centralized server, because the key security mechanism, Transport Layer Security, was really designed for use in centralized server models and so on-the-wire security is not a problem at all.
And authentication, it's still some issue, you still have to deal with it a little bit, but you get server, I'm sorry, client authenticate server authentication for free, so that makes life much easier.
In contrast, mobility is only a little bit easier.
Dealing with mobility, you still have to deal with a mobile client even if the server is fixed, so that's not a big win.
And malicious attack is a problem no matter how you, what sort of architecture you use.
So the summary of this is that centralized server will make your life easier, and if you can get away with it, I would recommend you go in that direction.
Once you've decided on your overall design, you then have to work on your protocol choice, what actual data are you going to send over the wire.
There's three options here, which I sort of often see, but there's actually a fourth here, which is that in some cases, you don't get a choice, which is again, if you're doing a Twitter client, you've got to do Twitter protocol, no argument there.
But if you do get a choice, then you have really a choice between sort of reusing existing protocol, rolling your own protocol, or extending an existing one.
Now if you reuse an existing protocol, there's certain advantages.
The first of which is there's less design.
Designing a network protocol is tricky.
Designing a good one is really quite tricky and so if you can skip the design work, that's great.
In addition to that, if you reuse an existing protocol, you may end up running less code.
The chances are, if the protocol exists somewhere else, then someone has written code for it, and it's either in the operating system or you can grab a library from open source or from some third party vendor, and that will definitely make less work for you.
In contrast, rolling your own protocol gives you the maximum flexibility.
You can design your protocol to give you really good advantages, one of which is latency hiding, you can build latency hiding right into your protocol, that's a good thing.
But, of course, it's extra work, both in design and implementation.
And it carries what I call a network risk iPhones often find themselves on networks that are managed by, let's say security conscious network administrators, and they'll prevent network protocols that they don't know from escaping the network, the firewall will just stop outgoing connections, and that causes a problem if you're designing your own protocol.
Now one of my favorite choices here is actually extending an existing one.
And the protocol to extend is most commonly HTTP.
HTTP has good security features, it has good support in the OS and it's relatively easy to extend, so it's generally a good choice for designing your own protocol.
And so a quick summary here is, if you have to design your own protocol, then try doing extending HTTP, if you can.
Try to avoid rolling your own protocol.
Now, along those lines, my top five tips for rolling your own protocol.
Number 5 is CPU architecture neutral.
If you send multi-byte quantities over the network, integers let's say, make sure that they're CPU architecture neutral, they're at a constant size and a constant byte order, and do it before you start, rather than trying to retro-fit it later.
Number 4 is of course, latency.
Now I've talked a lot about latency, it's a critical part of network performance, if you're designing your own protocol, one of the key benefits is that you get to hide latency, do the extra work to do that.
Number 3, Transport Layer Security.
I'm going to talk about Transport Layer Security a bit later in this talk, but it is the only security, on-the-wire security built into iPhone OS and designing your own on-the-wire security protocol is a really bad choice, on-the-wire security protocols should be left to security experts.
It's very tricky to get right.
And bringing your own in-the-wire security protocol porting SSH or something like that, is a lot of work.
So, if you can use Transport Layer Security, try to do so.
Number 2, TCP not UDP.
Lots of people think, yeah, I know how TCP works, I can do it myself, and I'll do it better.
Trust me, that's not the case.
You may do it better in some very restricted environments, like your office, but it will not work better across the wider Internet.
This habeen, you know, a subject of research for decades and what's in TCP is about as good as you can get.
So, don't design your own, unless you're way out in the security, in the network protocol guru level of competency, certainly not me.
And finally my Number 1 tip is, of course, don't.
So that covers On-The-Wire-Architecture, now we're going to look at the first tower here, which is the Platform Architecture; what iPhone OS does for you.
Here's our architecture stack, I'm sure you've seen diagrams like this.
The one you'll note, the key feature of this one is, sort of this applications box at the top.
If you're a network developer, of course, UIKit fits up there somewhere, we don't highlight it on the box, because we just don't care.
But down at the bottom, there's Darwin, which is the fundamental networking on iPhone OS.
It's a C API, the networking API for moving packets is called BSD sockets, there's also a Bonjour API down here called dns_sd, it's the closest to the kernel so it will give you the best performance, but I advise you not to get hung up on performance too much.
In my experience, network performance is not about, you know, can I save a few milliseconds going down to the kernel, it's about optimizing your on-the-wire traffic and you win from optimizing your on-the-wire traffic, not from, you know working at the BSD sockets level.
So, performance is not a good reason to use this API, unless you're on Mac OS X server and you've got 2 gigabytes, you know, 10-gigabyte Ethernet card installed, then it's an issue, but on iPhone, no.
In contrast, cross platform is a good reason to be using this API.
BSD sockets is available on virtually every platform, and the dns_sd API is available on Mac OS X, iPhone OS, iOS, I guess, it's available on Windows, and it's available on a variety of other platforms as well.
So, if you've got cross platform code, this is a good place to be working.
The biggest issues with working at this level are the cellular interface, by far the biggest one is the cellular interface.
There's no way to bring up the cellular interface if it's down, at this level, so it's a bit tricky to use sockets on iPhone OS at the moment.
The other issue, which is less of an issue today, is ground loop integration.
Integrating sockets into a ground loop based application, which is all Mac OS X and iPhone applications, is a bit tricky and you have to jump through some hoops.
One key advantage of grand central dispatch in this context, is that grand central dispatch makes it much easier to integrate with the ground loop from sockets code.
But the reality is, I generally recommend you move up in the stack.
Always recommend you move up.
And the next stop is CFNetwork, which is also a C API, and it solves the key problems with sockets, of cellular activation and ground loop integration.
And it also, in addition to doing Bonjour and TCP, it also supports other high level protocols and this is the first place where you can get support for TLS, and it supports an FTP and HTTP and HTTPS, so it's great.
But the real issue here is, if you're working at this level, you might as well just move up to the next level, and that's Foundation, it gives you everything, or almost everything CFNetwork gives you.
In a nice Objective-C package, which is ideal for Cocoa applications, its ground loops and delegates and all the stuff you know from Cocoa.
And again, it gives you most of the protocols except for a few edge cases.
So, the take home point here is, Foundation networking, use it, love it.
Another take home point, another thing I wanted to cover here is this particular factoid.
The Mac OS X and iPhone OS networking stacks are virtually identical.
So, if you're running code for iPhone OS, you can pretty much port it to Mac OS X and vice versa just by recompiling it, and it's a very useful feature.
And if you want to do applications that run on both, well, that have ends running on both.
And that sums up Platform Architecture.
We're going to look at In-Memory Architecture, and that's how you structure your objects to work well, how you architect them to deal with a networking, the issues proposed by networking.
If you've done any Cocoa programming, you'll be familiar with his whole Model-View-Controller thing.
And it's not obvious where you fit your networking in to this model, well enter into the view, no don't do that.
My recommendation here is, do your networking in the model.
There's good reasons for this, but if you think about it at a high level, your model is all about data, it's the data that you're managing.
And similarly, networking is all about data, you're either sending or receiving data across the network, so these are a good fit, in some regards.
But they are especially good fit because doing it in the other places, generally ends up really badly, things don't go well.
And to illustrate this, we have my bogus social networking application again, and here you can see we're downloading this thumbnail for the end that's got a placeholder there.
What happens if we download that in the view?
Well, the view is on the screen at the moment, but what happens when the user scrolls the table view off, that cell off the top of the screen, well, depending on table view reuse goes, that table view cell may get reused, and it can't continue downloading the thumbnail because that would get you the wrong thumbnail, so you end up having to cancel the network operation and then the user scrolls that cell back on the screen and then you have to un-cancel and start it all over again.
Clearly that's not the replace you want to do the thumbnails downloads.
Similarly, if you do the work in the Controller, then we are looking at the list of friends.
If you tap on one of the friends and it brings up a big picture of that friend, it has to go and get that off the network, then if you tap on it, and then tap back, and then tap down again, what happens?
Well, the View Controller gets disposed of, or gets created, disposed of and created again, and if it's cancelling the network operation when it's disposed of, then again, you've wasted a whole bunch of bandwidth.
So, to repeat, it's the work, do the networking in the model, because the model object can persist for as long as, well you need to persist in order to do the work.
Now I'm going to show a concrete example of this, and again it builds on this notion of thumbnails.
You'll see the big grey box again which is sort of the rest of the application, we're focused on the model, and in this case we are now focused on the object called the thumbnails, and that's how the rest of the application interacts with the networking.
There's a thumbnail object, and that object has a property, which is the current thumbnail image.
Now if the rest of the application requests the image from the thumbnail, well what happens?
The thumbnail doesn't have an image to hand back, so it kicks off a request to the server to go and get the image, and then what it does is it returns this placeholder and the rest of the application get a placeholder, and the rest of the application doesn't care, that as far as it's concerned is the image for that user, or for that thumbnail.
And it uses that placeholder and all is good, until the server responds with the actual real contents, and now the thumbnail object has a real image, and it just kicks off a notification to the high-level software to say, "Hey, I've changed my image."
Now I'd like to stress that this isn't "Hey the network operation has finished."
Or "Hey, I've completed this, you know, complicated thing."
It's "Hey the thumbnail has changed."
And in fact, the thumbnail could change for a variety of reason.
You might be on a social networking application, the thumbnail might have just changed on the server and the network has detected that and returned a new thumbnail.
But as far as the rest of the application is concerned, it's just a change in the thumbnail image, and then it just goes and fetches the new image and displays that, and life is good.
Another advantage of dealing with networking at this level, is the notion persistence.
The thumbnail object knows what data it's displaying.
It knows it's dealing with images, and more to the point it knows that the image, if it hands back a stale image, that's not the end of the world, and so when the rest of the application, if you just launched the application and you haven't really fired up the networking yet, and the rest of the application says, "Give me a thumbnail."
Then the thumbnail image, then the thumbnail can go get it off disk, the last one we saw and handed back, because it knows that giving the user a stale thumbnail isn't the end of the world.
So, it's a good way to do caching, because you can set the cache policy at the model level, and so a different model object, like the list of friends, where stale data might be more worrying, couldn't have a different cache policy.
So, persistent state is a good reason to do networking in the model.
So, to summarize, we do networking in the model because it isolates the rest of the application from the networking.
As far as the rest of the application is concerned, there are just model objects and changes to model objects.
In addition to that, another good advantage is persistence.
The model objects can persist and in fact they can persist with core data, you can make this thumbnail object a managed object and everything sort of just works, it's kind of like magic.
If you do do persistence at this level, make sure that you disabling caching at the NSURL connection level, because you don't really want to be caching at NSURL connection level and caching at the model level.
It's a good way to handle external changes, like I said, if the image changes on the social networking site, the rest of the application doesn't care why it changed, it just knows that it did change.
It's also a good way to do testing.
Testing network applications is very difficult, because the network behavior changes from minute to minute, but if you disconnect the rest of the application from the model, then you can put in a new model that just goes through some sequence of steps, set steps and then you can test that the rest of the application handles those properly.
So, it's a good way to test the higher levels of your software, just by connecting your model to a dummy model that just goes through a set of transforms.
So, that networking in the model, before we leave that topic, I wanted to cover that green arrow there, which is the notification.
How does the model tell the rest of the application that things have changed.
Now there are three basic ways of doing this in Cocoa.
There's this notion of Delegation, and then there's NSNotification , and there's Key Value Observing.
Delegation isn't always the best choice here, because it's very hard to do, delegation just does one-to-one messaging.
There's only one delegate for a given object and so if two people are observing the same property, as is quite common for things like thumbnails, you can't really do that in the delegation model.
In contrast, NSNotification and KVO are both one to many, so you can have many observers, which is good.
I tend to use KVO, I'm a big fan of KVO, because it's very fine grained, so you can learn about very specific changes in the model.
But the reality is NSNotification is pretty much just as good, so there's no reason not to use, it's just sort of one of those personal preferences.
So that's how, typically how you tell the high levels of your application that something has changed deep down in the model, because of the networking, but it doesn't need to know about the networking.
And with that, we've wrapped up the whole architecture business.
We started with the User Interface, which is why we built the application in the first place.
We want to make sure that the User Interface reflects to the user the realities of networking.
We then looked at On-The-Wire Architecture, and how centralized server makes your application much easier, and also how reusing an existing protocol and maybe extending it a little bit, is a big win.
We looked at Platform Architecture, and the take home message there is that Foundation is your friend and use it.
And then we looked at In-Memory Architecture; which is how to structure your model objects to reflect the realities of networking to the rest of your application.
And with that, a short digression into security.
And specifically security by Transport Layer Security.
Now Transport Layer Security is the evolution of SSL.
Lots of people say, "This network connection is secured by SSL."
And they don't really mean that, they really mean it's secured by TLS.
If it was secured by SSL, we might be worried.
It's the only On-The-Wire security protocol in iPhone OS, so it's the one I recommend, obviously.
It works best with the centralized server model.
How you might, how you organize this is you go to a certificate, you set up your server on the Internet, and then you go to your certificate authority, verifying or whoever, and you say "I want an identity for this server."
And they give you an identity it's stored on the server, and from then on, any client out there on the wider Internet can automatically get client authenticate server authentication based on DNS names.
And it also automatically gets On-The-Wire privacy so that's the vast bulk of the really hard security problems just solved by this one simple design decision.
In contrast, using Transport Layer Security in a peer-to-peer environment is as [inaudible] would say, "Tricky".
Transport Layer Security supports peer-to-peer, because it's part of the protocol.
But it's hard to get to from the iPhone OS APIs, it's even hard to get through frankly from the Mac OS X APIs and so using it in a peer-to-peer model becomes quite tricky and really if there's one reason to favor centralized server over peer-to-peer, it's this.
You can't live without security and Transport Layer Security works best for centralized server.
As far as accessing Transport Layer Security within iPhone OS, there is no Transport Layer Security that's accessible at the dial-up level.
The secure transport mechanism, which is available on Mac OS X, public API Mac OS X is not a public API on iPhone OS, so you just can't use it.
And OpenSSL, which is also available on Mac OS X, is not actually on iPhone OS at all.
Now you can bring your own copy of OpenSSL if you want, it's open source, you can compile it and link it into your application, that's quite a bit of work, and if you really want to make your life easy, the best way to do that is to stick to using the TLS that's built into the system, and that means using CFSocketStream.
CFSocketStream you can enable TLS just by setting a few properties, and everything just works.
You just treat like it a different type of stream.
But as before, if you're working at this level, at the CF Level, you might as well work it in at the NSStream level, CFSocketStream and NSStream toll-free bridged, so you can create, or can configure a socket stream using whatever fancy Transport Layer Security options you need, and then just treat it as a NSStream in the rest of your application and that's a good thing.
Also in the Foundation level, there's NSURL connection, which is about accessing URL's.
And normally, if you give it at HTTP URL, it will do normal HTTP.
If you give it an HTTPS URL, it will automatically enable Transport Layer Security for you, so it's trivial to access TLS from the NSURL connection level.
And that, is more or less that.
Networking is hard, there's no beating about the bush, networking is a difficult problem, there's a lot of environmental issues that make it difficult, there's a lot of asynchrony issues that make it difficult.
The best way to make networking easier is not about APIs, it's about architecture, its design your application well from day one, and the most critical thing there is actually design your User Interface.
Don't let you User Interface sort of paint you into a corner where you have to do something synchronously, because that won't work in the long term.
You really want to have User Interface accept asynchronous operations as part of its design, so with things like placeholders and non-modal user interface.
Work at the Foundation layer if you can.
There are good reasons to go down to lower layers, it's fine to do so, it's not, nothing bad about it, but if you can work at Foundation, it's going to make your life easier.
And finally, put your networking in the model and try and isolate the networking in the model deep down in your application so it doesn't get its claws into the rest of your application.
And last, but not least, TLS is your friend, it will make security much easier and security is critical.
Now, but wait, there's more, in fact, there is of course a whole another talk more, in that talk I'm going to cover asynchronous programming, which is a lot of content, and I'm going to look at ground loops and depth.
I'm also going to look at network debugging, what you can do to make your network debugging easier, sort of plan in advance to make your networking better, make your debugging experience better.
I'm also going to go through a short list of common mistakes.
For more information, you can contact me directly if you'd like.
You can also contact Paul Danbold, who's our Networking Evangelist.
There's tons of documentation on our website.
The Apple Developer forums, there's a Core OS section there where I hang out and answer networking questions.
Sample Code, again the Mac OS X and iPhone OS networking architectures are virtually identical, so if there's a sample that's only in Mac OS X, it's well worth looking to see whether it will work on iPhone OS because in a lot of cases it will.
And sometimes it's just easier to shift a Mac OS X sample that you run from a terminal than build a whole application around it.