Transcript
>>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.
[Laughter]
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.
[Laughter]
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.
[Laughter]
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.
[Laughter]
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.
[Laughter]
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.
[Laughter]
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.