📄 rfc817.txt
字号:
Given this architecture, it is not longer necessary to imagine that all
of the TCPs are identical. One TCP could be optimized for high
throughput applications, such as file transfer. Another TCP could be
optimized for small low delay applications such as Telnet. In fact, it
would be possible to produce a TCP which was somewhat integrated with
the Telnet or FTP on top of it. Such an integration is extremely
important, for it can lead to a kind of efficiency which more
traditional structures are incapable of producing. Earlier, this paper
pointed out that one of the important rules to achieving efficiency was
to send the minimum number of packets for a given amount of data. The
idea of protocol layering interacts very strongly (and poorly) with this
14
goal, because independent layers have independent ideas about when
packets should be sent, and unless these layers can somehow be brought
into cooperation, additional packets will flow. The best example of
this is the operation of server telnet in a character at a time remote
echo mode on top of TCP. When a packet containing a character arrives
at a server host, each layer has a different response to that packet.
TCP has an obligation to acknowledge the packet. Either server telnet
or the application layer above has an obligation to echo the character
received in the packet. If the character is a Telnet control sequence,
then Telnet has additional actions which it must perform in response to
the packet. The result of this, in most implementations, is that
several packets are sent back in response to the one arriving packet.
Combining all of these return messages into one packet is important for
several reasons. First, of course, it reduces the number of packets
being sent over the net, which directly reduces the charges incurred for
many common carrier tariff structures. Second, it reduces the number of
scheduling actions which will occur inside both hosts, which, as was
discussed above, is extremely important in improving throughput.
The way to achieve this goal of packet sharing is to break down the
barrier between the layers of the protocols, in a very restrained and
careful manner, so that a limited amount of information can leak across
the barrier to enable one layer to optimize its behavior with respect to
the desires of the layers above and below it. For example, it would
represent an improvement if TCP, when it received a packet, could ask
the layer above whether or not it would be worth pausing for a few
milliseconds before sending an acknowledgement in order to see if the
15
upper layer would have any outgoing data to send. Dallying before
sending the acknowledgement produces precisely the right sort of
optimization if the client of TCP is server Telnet. However, dallying
before sending an acknowledgement is absolutely unacceptable if TCP is
being used for file transfer, for in file transfer there is almost never
data flowing in the reverse direction, and the delay in sending the
acknowledgement probably translates directly into a delay in obtaining
the next packets. Thus, TCP must know a little about the layers above
it to adjust its performance as needed.
It would be possible to imagine a general purpose TCP which was
equipped with all sorts of special mechanisms by which it would query
the layer above and modify its behavior accordingly. In the structures
suggested above, in which there is not one but several TCPs, the TCP can
simply be modified so that it produces the correct behavior as a matter
of course. This structure has the disadvantage that there will be
several implementations of TCP existing on a single machine, which can
mean more maintenance headaches if a problem is found where TCP needs to
be changed. However, it is probably the case that each of the TCPs will
be substantially simpler than the general purpose TCP which would
otherwise have been built. There are some experimental projects
currently under way which suggest that this approach may make designing
of a TCP, or almost any other layer, substantially easier, so that the
total effort involved in bringing up a complete package is actually less
if this approach is followed. This approach is by no means generally
accepted, but deserves some consideration.
16
The general conclusion to be drawn from this sort of consideration
is that a layer boundary has both a benefit and a penalty. A visible
layer boundary, with a well specified interface, provides a form of
isolation between two layers which allows one to be changed with the
confidence that the other one will not stop working as a result.
However, a firm layer boundary almost inevitably leads to inefficient
operation. This can easily be seen by analogy with other aspects of
operating systems. Consider, for example, file systems. A typical
operating system provides a file system, which is a highly abstracted
representation of a disk. The interface is highly formalized, and
presumed to be highly stable. This makes it very easy for naive users
to have access to disks without having to write a great deal of
software. The existence of a file system is clearly beneficial. On the
other hand, it is clear that the restricted interface to a file system
almost inevitably leads to inefficiency. If the interface is organized
as a sequential read and write of bytes, then there will be people who
wish to do high throughput transfers who cannot achieve their goal. If
the interface is a virtual memory interface, then other users will
regret the necessity of building a byte stream interface on top of the
memory mapped file. The most objectionable inefficiency results when a
highly sophisticated package, such as a data base management package,
must be built on top of an existing operating system. Almost
inevitably, the implementors of the database system attempt to reject
the file system and obtain direct access to the disks. They have
sacrificed modularity for efficiency.
The same conflict appears in networking, in a rather extreme form.
17
The concept of a protocol is still unknown and frightening to most naive
programmers. The idea that they might have to implement a protocol, or
even part of a protocol, as part of some application package, is a
dreadful thought. And thus there is great pressure to hide the function
of the net behind a very hard barrier. On the other hand, the kind of
inefficiency which results from this is a particularly undesirable sort
of inefficiency, for it shows up, among other things, in increasing the
cost of the communications resource used up to achieve the application
goal. In cases where one must pay for one's communications costs, they
usually turn out to be the dominant cost within the system. Thus, doing
an excessively good job of packaging up the protocols in an inflexible
manner has a direct impact on increasing the cost of the critical
resource within the system. This is a dilemma which will probably only
be solved when programmers become somewhat less alarmed about protocols,
so that they are willing to weave a certain amount of protocol structure
into their application program, much as application programs today weave
parts of database management systems into the structure of their
application program.
An extreme example of putting the protocol package behind a firm
layer boundary occurs when the protocol package is relegated to a front-
end processor. In this case the interface to the protocol is some other
protocol. It is difficult to imagine how to build close cooperation
between layers when they are that far separated. Realistically, one of
the prices which must be associated with an implementation so physically
modularized is that the performance will suffer as a result. Of course,
a separate processor for protocols could be very closely integrated into
18
the mainframe architecture, with interprocessor co-ordination signals,
shared memory, and similar features. Such a physical modularity might
work very well, but there is little documented experience with this
closely coupled architecture for protocol support.
6. Efficiency of Protocol Processing
To this point, this document has considered how a protocol package
should be broken into modules, and how those modules should be
distributed between free standing machines, the operating system kernel,
and one or more user processes. It is now time to consider the other
half of the efficiency question, which is what can be done to speed the
execution of those programs that actually implement the protocols. We
will make some specific observations about TCP and IP, and then conclude
with a few generalities.
IP is a simple protocol, especially with respect to the processing
of normal packets, so it should be easy to get it to perform
efficiently. The only area of any complexity related to actual packet
processing has to do with fragmentation and reassembly. The reader is
referred to RFC 815, titled "IP Datagram Reassembly Algorithms", for
specific consideration of this point.
Most costs in the IP layer come from table look up functions, as
opposed to packet processing functions. An outgoing packet requires two
translation functions to be performed. The internet address must be
translated to a target gateway, and a gateway address must be translated
to a local network number (if the host is attached to more than one
19
network). It is easy to build a simple implementation of these table
look up functions that in fact performs very poorly. The programmer
should keep in mind that there may be as many as a thousand network
numbers in a typical configuration. Linear searching of a thousand
entry table on every packet is extremely unsuitable. In fact, it may be
worth asking TCP to cache a hint for each connection, which can be
handed down to IP each time a packet is sent, to try to avoid the
overhead of a table look up.
TCP is a more complex protocol, and presents many more
opportunities for getting things wrong. There is one area which is
generally accepted as causing noticeable and substantial overhead as
part of TCP processing. This is computation of the checksum. It would
be nice if this cost could be avoided somehow, but the idea of an end-
to-end checksum is absolutely central to the functioning of TCP. No
host implementor should think of omitting the validation of a checksum
on incoming data.
Various clever tricks have been used to try to minimize the cost of
computing the checksum. If it is possible to add additional microcoded
instructions to the machine, a checksum instruction is the most obvious
candidate. Since computing the checksum involves picking up every byte
of the segment and examining it, it is possible to combine the operation
of computing the checksum with the operation of copying the segment from
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -