1.3
Network Software
The first computer networks were
designed with the hardware as the main concern and the software as an
afterthought. This strategy no longer works. Network software is now highly
structured. In the following sections we examine the software structuring
technique in some detail. The method described here forms the keystone of the
entire book and will occur repeatedly later on.
To reduce their design complexity,
most networks are organized as a stack of layers or levels, each one built upon
the one below it. The number of layers, the name of each layer, the contents of
each layer, and the function of each layer differ from network to network. The
purpose of each layer is to offer certain services to the higher layers,
shielding those layers from the details of how the offered services are
actually implemented. In a sense, each layer is a kind of virtual machine,
offering certain services to the layer above it.
This concept is actually a familiar
one and used throughout computer science, where it is variously known as
information hiding, abstract data types, data encapsulation, and
object-oriented programming. The fundamental idea is that a particular piece of
software (or hardware) provides a service to its users but keeps the details of
its internal state and algorithms hidden from them.
Layer n on one machine carries on a
conversation with layer n on another machine. The rules and conventions used in
this conversation are collectively known as the layer n protocol. Basically, a protocol
is an agreement between the communicating parties on how communication is to
proceed. As an analogy, when a woman is introduced to a man, she may choose to
stick out her hand. He, in turn, may decide either to shake it or kiss it,
depending, for example, on whether she is an American lawyer at a business
meeting or a European princess at a formal ball. Violating the protocol will
make communication more difficult, if not completely impossible.
A five-layer network is illustrated
in Fig. 1-13. The entities comprising the
corresponding layers on different machines are called peers. The peers may be
processes, hardware devices, or even human beings. In other words, it is the
peers that communicate by using the protocol.
In reality, no data are directly
transferred from layer n on one machine to layer n on another machine. Instead,
each layer passes data and control information to the layer immediately below
it, until the lowest layer is reached. Below layer 1 is the physical medium
through which actual communication occurs. In Fig. 1-13, virtual communication is shown by
dotted lines and physical communication by solid lines.
Between each pair of adjacent layers
is an interface. The interface defines which primitive operations and services
the lower layer makes available to the upper one. When network designers decide
how many layers to include in a network and what each one should do, one of the
most important considerations is defining clean interfaces between the layers.
Doing so, in turn, requires that each layer perform a specific collection of
well-understood functions. In addition to minimizing the amount of information
that must be passed between layers, clear-cut interfaces also make it simpler
to replace the implementation of one layer with a completely different implementation
(e.g., all the telephone lines are replaced by satellite channels) because all
that is required of the new implementation is that it offer exactly the same
set of services to its upstairs neighbor as the old implementation did. In
fact, it is common that different hosts use different implementations.
A set of layers and protocols is
called a network architecture. The specification of an architecture must
contain enough information to allow an implementer to write the program or
build the hardware for each layer so that it will correctly obey the
appropriate protocol. Neither the details of the implementation nor the
specification of the interfaces is part of the architecture because these are
hidden away inside the machines and not visible from the outside. It is not
even necessary that the interfaces on all machines in a network be the same,
provided that each machine can correctly use all the protocols. A list of
protocols used by a certain system, one protocol per layer, is called a protocol
stack. The subjects of network architectures, protocol stacks, and the
protocols themselves are the principal topics of this book.
An analogy may help explain the idea
of multilayer communication. Imagine two philosophers (peer processes in layer
3), one of whom speaks Urdu and English and one of whom speaks Chinese and
French. Since they have no common language, they each engage a translator (peer
processes at layer 2), each of whom in turn contacts a secretary (peer
processes in layer 1). Philosopher 1 wishes to convey his affection for oryctolagus
cuniculus to his peer. To do so, he passes a message (in English) across the
2/3 interface to his translator, saying ''I like rabbits,'' as illustrated in Fig. 1-14. The translators have agreed on a
neutral language known to both of them, Dutch, so the message is converted to
''Ik vind konijnen leuk.'' The choice of language is the layer 2 protocol and
is up to the layer 2 peer processes.
The translator then gives the
message to a secretary for transmission, by, for example, fax (the layer 1
protocol). When the message arrives, it is translated into French and passed
across the 2/3 interface to philosopher 2. Note that each protocol is
completely independent of the other ones as long as the interfaces are not
changed. The translators can switch from Dutch to say, Finnish, at will,
provided that they both agree, and neither changes his interface with either
layer 1 or layer 3. Similarly, the secretaries can switch from fax to e-mail or
telephone without disturbing (or even informing) the other layers. Each process
may add some information intended only for its peer. This information is not
passed upward to the layer above.
Now consider a more technical
example: how to provide communication to the top layer of the five-layer
network in Fig. 1-15. A message, M, is produced by an
application process running in layer 5 and given to layer 4 for transmission.
Layer 4 puts a header in front of the message to identify the message and passes
the result to layer 3. The header includes control information, such as
sequence numbers, to allow layer 4 on the destination machine to deliver
messages in the right order if the lower layers do not maintain sequence. In
some layers, headers can also contain sizes, times, and other control fields.
In many networks, there is no limit
to the size of messages transmitted in the layer 4 protocol, but there is
nearly always a limit imposed by the layer 3 protocol. Consequently, layer 3
must break up the incoming messages into smaller units, packets, prepending a
layer 3 header to each packet. In this example, M is split into two parts, M1
and M2.
Layer 3 decides which of the outgoing
lines to use and passes the packets to layer 2. Layer 2 adds not only a header
to each piece, but also a trailer, and gives the resulting unit to layer 1 for
physical transmission. At the receiving machine the message moves upward, from
layer to layer, with headers being stripped off as it progresses. None of the
headers for layers below n are passed up to layer n.
The important thing to understand
about Fig. 1-15 is the relation between the virtual and
actual communication and the difference between protocols and interfaces. The
peer processes in layer 4, for example, conceptually think of their
communication as being ''horizontal,'' using the layer 4 protocol. Each one is
likely to have a procedure called something like SendToOtherSide and GetFromOtherSide,
even though these procedures actually communicate with lower layers across the
3/4 interface, not with the other side.
The peer process abstraction is
crucial to all network design. Using it, the unmanageable task of designing the
complete network can be broken into several smaller, manageable design
problems, namely, the design of the individual layers.
Although Sec. 1.3 is called ''Network 1.3,'' it is worth pointing out that the
lower layers of a protocol hierarchy are frequently implemented in hardware or
firmware. Nevertheless, complex protocol algorithms are involved, even if they
are embedded (in whole or in part) in hardware.
Some of the key design issues that
occur in computer networks are present in several layers. Below, we will
briefly mention some of the more important ones.
Every layer needs a mechanism for
identifying senders and receivers. Since a network normally has many computers,
some of which have multiple processes, a means is needed for a process on one
machine to specify with whom it wants to talk. As a consequence of having
multiple destinations, some form of addressing is needed in order to specify a
specific destination.
Another set of design decisions
concerns the rules for data transfer. In some systems, data only travel in one
direction; in others, data can go both ways. The protocol must also determine
how many logical channels the connection corresponds to and what their
priorities are. Many networks provide at least two logical channels per
connection, one for normal data and one for urgent data.
Error control is an important issue
because physical communication circuits are not perfect. Many error-detecting
and error-correcting codes are known, but both ends of the connection must
agree on which one is being used. In addition, the receiver must have some way
of telling the sender which messages have been correctly received and which
have not.
Not all communication channels
preserve the order of messages sent on them. To deal with a possible loss of
sequencing, the protocol must make explicit provision for the receiver to allow
the pieces to be reassembled properly. An obvious solution is to number the
pieces, but this solution still leaves open the question of what should be done
with pieces that arrive out of order.
An issue that occurs at every level
is how to keep a fast sender from swamping a slow receiver with data. Various
solutions have been proposed and will be discussed later. Some of them involve
some kind of feedback from the receiver to the sender, either directly or
indirectly, about the receiver's current situation. Others limit the sender to
an agreed-on transmission rate. This subject is called flow control.
Another problem that must be solved
at several levels is the inability of all processes to accept arbitrarily long
messages. This property leads to mechanisms for disassembling, transmitting,
and then reassembling messages. A related issue is the problem of what to do
when processes insist on transmitting data in units that are so small that
sending each one separately is inefficient. Here the solution is to gather
several small messages heading toward a common destination into a single large
message and dismember the large message at the other side.
When it is inconvenient or expensive
to set up a separate connection for each pair of communicating processes, the
underlying layer may decide to use the same connection for multiple, unrelated
conversations. As long as this multiplexing and demultiplexing is done transparently,
it can be used by any layer. Multiplexing is needed in the physical layer, for
example, where all the traffic for all connections has to be sent over at most
a few physical circuits.
When there are multiple paths
between source and destination, a route must be chosen. Sometimes this decision
must be split over two or more layers. For example, to send data from London to
Rome, a high-level decision might have to be made to transit France or Germany
based on their respective privacy laws. Then a low-level decision might have to
made to select one of the available circuits based on the current traffic load.
This topic is called routing.
Layers can offer two different types
of service to the layers above them: connection-oriented and connectionless. In
this section we will look at these two types and examine the differences
between them.
Connection-oriented service is
modeled after the telephone system. To talk to someone, you pick up the phone,
dial the number, talk, and then hang up. Similarly, to use a
connection-oriented network service, the service user first establishes a
connection, uses the connection, and then releases the connection. The
essential aspect of a connection is that it acts like a tube: the sender pushes
objects (bits) in at one end, and the receiver takes them out at the other end.
In most cases the order is preserved so that the bits arrive in the order they
were sent.
In some cases when a connection is
established, the sender, receiver, and subnet conduct a negotiation about
parameters to be used, such as maximum message size, quality of service
required, and other issues. Typically, one side makes a proposal and the other
side can accept it, reject it, or make a counterproposal.
In contrast, connectionless service
is modeled after the postal system. Each message (letter) carries the full
destination address, and each one is routed through the system independent of
all the others. Normally, when two messages are sent to the same destination,
the first one sent will be the first one to arrive. However, it is possible
that the first one sent can be delayed so that the second one arrives first.
Each service can be characterized by
a quality of service. Some services are reliable in the sense that they never
lose data. Usually, a reliable service is implemented by having the receiver
acknowledge the receipt of each message so the sender is sure that it arrived.
The acknowledgement process introduces overhead and delays, which are often
worth it but are sometimes undesirable.
A typical situation in which a
reliable connection-oriented service is appropriate is file transfer. The owner
of the file wants to be sure that all the bits arrive correctly and in the same
order they were sent. Very few file transfer customers would prefer a service
that occasionally scrambles or loses a few bits, even if it is much faster.
Reliable connection-oriented service
has two minor variations: message sequences and byte streams. In the former
variant, the message boundaries are preserved. When two 1024-byte messages are
sent, they arrive as two distinct 1024-byte messages, never as one 2048-byte
message. In the latter, the connection is simply a stream of bytes, with no
message boundaries. When 2048 bytes arrive at the receiver, there is no way to
tell if they were sent as one 2048-byte message, two 1024-byte messages, or
2048 1-byte messages. If the pages of a book are sent over a network to a
phototypesetter as separate messages, it might be important to preserve the
message boundaries. On the other hand, when a user logs into a remote server, a
byte stream from the user's computer to the server is all that is needed.
Message boundaries are not relevant.
As mentioned above, for some
applications, the transit delays introduced by acknowledgements are
unacceptable. One such application is digitized voice traffic. It is preferable
for telephone users to hear a bit of noise on the line from time to time than
to experience a delay waiting for acknowledgements. Similarly, when
transmitting a video conference, having a few pixels wrong is no problem, but
having the image jerk along as the flow stops to correct errors is irritating.
Not all applications require
connections. For example, as electronic mail becomes more common, electronic
junk is becoming more common too. The electronic junk-mail sender probably does
not want to go to the trouble of setting up and later tearing down a connection
just to send one item. Nor is 100 percent reliable delivery essential,
especially if it costs more. All that is needed is a way to send a single
message that has a high probability of arrival, but no guarantee. Unreliable
(meaning not acknowledged) connectionless service is often called datagram
service, in analogy with telegram service, which also does not return an
acknowledgement to the sender.
In other situations, the convenience
of not having to establish a connection to send one short message is desired,
but reliability is essential. The acknowledged datagram service can be provided
for these applications. It is like sending a registered letter and requesting a
return receipt. When the receipt comes back, the sender is absolutely sure that
the letter was delivered to the intended party and not lost along the way.
Still another service is the request-reply
service. In this service the sender transmits a single datagram containing a
request; the reply contains the answer. For example, a query to the local
library asking where Uighur is spoken falls into this category. Request-reply
is commonly used to implement communication in the client-server model: the
client issues a request and the server responds to it. Figure 1-16 summarizes the types of services
discussed above.
The concept of using unreliable
communication may be confusing at first. After all, why would anyone actually
prefer unreliable communication to reliable communication? First of all,
reliable communication (in our sense, that is, acknowledged) may not be
available. For example, Ethernet does not provide reliable communication.
Packets can occasionally be damaged in transit. It is up to higher protocol
levels to deal with this problem. Second, the delays inherent in providing a
reliable service may be unacceptable, especially in real-time applications such
as multimedia. For these reasons, both reliable and unreliable communication
coexist.
A service is formally specified by a
set of primitives (operations) available to a user process to access the
service. These primitives tell the service to perform some action or report on
an action taken by a peer entity. If the protocol stack is located in the
operating system, as it often is, the primitives are normally system calls.
These calls cause a trap to kernel mode, which then turns control of the
machine over to the operating system to send the necessary packets.
The set of primitives available
depends on the nature of the service being provided. The primitives for
connection-oriented service are different from those of connectionless service.
As a minimal example of the service primitives that might be provided to implement
a reliable byte stream in a client-server environment, consider the primitives
listed in Fig. 1-17.
These primitives might be used as
follows. First, the server executes LISTEN to indicate that it is prepared to
accept incoming connections. A common way to implement LISTEN is to make it a
blocking system call. After executing the primitive, the server process is
blocked until a request for connection appears.
Next, the client process executes
CONNECT to establish a connection with the server. The CONNECT call needs to
specify who to connect to, so it might have a parameter giving the server's
address. The operating system then typically sends a packet to the peer asking
it to connect, as shown by (1) in Fig. 1-18. The client process is suspended until
there is a response. When the packet arrives at the server, it is processed by
the operating system there. When the system sees that the packet is requesting
a connection, it checks to see if there is a listener. If so, it does two
things: unblocks the listener and sends back an acknowledgement (2). The
arrival of this acknowledgement then releases the client. At this point the
client and server are both running and they have a connection established. It is
important to note that the acknowledgement (2) is generated by the protocol
code itself, not in response to a user-level primitive. If a connection request
arrives and there is no listener, the result is undefined. In some systems the
packet may be queued for a short time in anticipation of a LISTEN.
The obvious analogy between this
protocol and real life is a customer (client) calling a company's customer
service manager. The service manager starts out by being near the telephone in
case it rings. Then the client places the call. When the manager picks up the
phone, the connection is established.
The next step is for the server to
execute RECEIVE to prepare to accept the first request. Normally, the server
does this immediately upon being released from the LISTEN, before the
acknowledgement can get back to the client. The RECEIVE call blocks the server.
Then the client executes SEND to
transmit its request (3) followed by the execution of RECEIVE to get the reply.
The arrival of the request packet at
the server machine unblocks the server process so it can process the request.
After it has done the work, it uses SEND to return the answer to the client
(4). The arrival of this packet unblocks the client, which can now inspect the
answer. If the client has additional requests, it can make them now. If it is
done, it can use DISCONNECT to terminate the connection. Usually, an initial
DISCONNECT is a blocking call, suspending the client and sending a packet to
the server saying that the connection is no longer needed (5). When the server
gets the packet, it also issues a DISCONNECT of its own, acknowledging the
client and releasing the connection. When the server's packet (6) gets back to
the client machine, the client process is released and the connection is
broken. In a nutshell, this is how connection-oriented communication works.
Of course, life is not so simple.
Many things can go wrong here. The timing can be wrong (e.g., the CONNECT is
done before the LISTEN), packets can get lost, and much more. We will look at
these issues in great detail later, but for the moment, Fig. 1-18 briefly summarizes how client-server
communication might work over a connection-oriented network.
Given that six packets are required
to complete this protocol, one might wonder why a connectionless protocol is
not used instead. The answer is that in a perfect world it could be, in which
case only two packets would be needed: one for the request and one for the
reply. However, in the face of large messages in either direction (e.g., a
megabyte file), transmission errors, and lost packets, the situation changes.
If the reply consisted of hundreds of packets, some of which could be lost
during transmission, how would the client know if some pieces were missing? How
would the client know whether the last packet actually received was really the
last packet sent? Suppose that the client wanted a second file. How could it
tell packet 1 from the second file from a lost packet 1 from the first file
that suddenly found its way to the client? In short, in the real world, a
simple request-reply protocol over an unreliable network is often inadequate.
Services and protocols are distinct concepts,
although they are frequently confused. This distinction is so important,
however, that we emphasize it again here. A service is a set of primitives
(operations) that a layer provides to the layer above it. The service defines
what operations the layer is prepared to perform on behalf of its users, but it
says nothing at all about how these operations are implemented. A service
relates to an interface between two layers, with the lower layer being the
service provider and the upper layer being the service user.
A protocol, in contrast, is a set of
rules governing the format and meaning of the packets, or messages that are
exchanged by the peer entities within a layer. Entities use protocols to
implement their service definitions. They are free to change their protocols at
will, provided they do not change the service visible to their users. In this
way, the service and the protocol are completely decoupled.
In other words, services relate to
the interfaces between layers, as illustrated in Fig. 1-19. In contrast, protocols relate to the
packets sent between peer entities on different machines. It is important not
to confuse the two concepts.
An analogy with programming
languages is worth making. A service is like an abstract data type or an object
in an object-oriented language. It defines operations that can be performed on
an object but does not specify how these operations are implemented. A protocol
relates to the implementation of the service and as such is not visible to the
user of the service.
Many older
protocols did not distinguish the service from the protocol. In effect, a
typical layer might have had a service primitive SEND PACKET with the user
providing a pointer to a fully assembled packet. This arrangement meant that
all changes to the protocol were immediately visible to the users. Most network
designers now regard such a design as a serious blunder.
No comments:
Post a Comment
silahkan membaca dan berkomentar