TCP/IP(协议)


第1章 概 述 1.1 引言 很多不同的厂家生产各种型号的计算机,它们运行完全不同的操作系统,但 T C P / I P协议 族允许它们互相进行通信。这一点很让人感到吃惊,因为它的作用已远远超出了起初的设想。 T C P / I P起源于6 0年代末美国政府资助的一个分组交换网络研究项目,到 9 0年代已发展成为计 算机之间最常应用的组网形式。它是一个真正的开放系统,因为协议族的定义及其多种实现 可以不用花钱或花很少的钱就可以公开地得到。它成为被称作“全球互联网”或“因特网 ( I n t e r n e t )”的基础,该广域网(WA N)已包含超过1 0 0万台遍布世界各地的计算机。 本章主要对T C P / I P协议族进行概述,其目的是为本书其余章节提供充分的背景知识。如 果读者要从历史的角度了解有关 T C P / I P的早期发展情况,请参考文献 [ Lynch 1993]。 1.2 分层 网络协议通常分不同层次进行开发,每一层分别 负责不同的通信功能。一个协议族,比如 T C P / I P,是 一组不同层次上的多个协议的组合。 T C P / I P通常被认 为是一个四层协议系统,如图 1 - 1所示。 每一层负责不同的功能: 1) 链路层,有时也称作数据链路层或网络接口层, 通常包括操作系统中的设备驱动程序和计算机 中对应的网络接口卡。它们一起处理与电缆(或其他任何传输媒介)的物理接口细节。 2) 网络层,有时也称作互联网层,处理分组在网络中的活动,例如分组的选路。在 T C P / I P协议族中,网络层协议包括 I P协议(网际协议),I C M P协议(I n t e r n e t互联网控 制报文协议),以及I G M P协议(I n t e r n e t组管理协议)。 3 ) 运输层主要为两台主机上的应用程序提供端到端的通信。在 T C P / I P协议族中,有两个 互不相同的传输协议:T C P(传输控制协议)和U D P(用户数据报协议)。 T C P为两台主机提供高可靠性的数据通信。它所做的工作包括把应用程序交给它的数据分 成合适的小块交给下面的网络层,确认接收到的分组,设置发送最后确认分组的超时时钟 等。由于运输层提供了高可靠性的端到端的通信,因此应用层可以忽略所有这些细节。 而另一方面,U D P则为应用层提供一种非常简单的服务。它只是把称作数据报的分组 从一台主机发送到另一台主机,但并不保证该数据报能到达另一端。任何必需的可靠 性必须由应用层来提供。 这两种运输层协议分别在不同的应用程序中有不同的用途,这一点将在后面看到。 4 ) 应用层负责处理特定的应用程序细节。几乎各种不同的 T C P / I P实现都会提供下面这些 通用的应用程序: 图1-1 TCP/IP协议族的四个层次 应用层 运输层 网络层 链路层 设备驱动程序及接口卡 Telnet、FTP和e-mail等 TCP和UDP IP、ICMP和IGMP• Telnet 远程登录。 • FTP 文件传输协议。 • SMTP 简单邮件传送协议。 • SNMP 简单网络管理协议。 另外还有许多其他应用,在后面章节中将介绍其中的一部分。 假设在一个局域网( L A N)如以太网中有两台主机,二者都运行 F T P协议,图1 - 2列出了 该过程所涉及到的所有协议。 图1-2 局域网上运行FTP的两台主机 这里,我们列举了一个 F T P客户程序和另一个F T P服务器程序。大多数的网络应用程序都 被设计成客户—服务器模式。服务器为客户提供某种服务,在本例中就是访问服务器所在主 机上的文件。在远程登录应用程序 Te l n e t中,为客户提供的服务是登录到服务器主机上。 在同一层上,双方都有对应的一个或多个协议进行通信。例如,某个协议允许 T C P层进 行通信,而另一个协议则允许两个 I P层进行通信。 在图1 - 2的右边,我们注意到应用程序通常是一个用户进程,而下三层则一般在(操作系 统)内核中执行。尽管这不是必需的,但通常都是这样处理的,例如 U N I X操作系统。 在图1 - 2中,顶层与下三层之间还有另一个关键的不同之处。应用层关心的是应用程序的 细节,而不是数据在网络中的传输活动。下三层对应用程序一无所知,但它们要处理所有的 通信细节。 在图1 - 2中列举了四种不同层次上的协议。 F T P是一种应用层协议, T C P是一种运输层协 议,I P是一种网络层协议,而以太网协议则应用于链路层上。 T C P / I P协议族是一组不同的协 议组合在一起构成的协议族。尽管通常称该协议族为 T C P / I P,但T C P和I P只是其中的两种协 议而已(该协议族的另一个名字是 I n t e r n e t协议族(Internet Protocol Suite))。 网络接口层和应用层的目的是很显然的— 前者处理有关通信媒介的细节(以太网、令牌 环网等),而后者处理某个特定的用户应用程序( F T P、Te l n e t等)。但是,从表面上看,网络 层和运输层之间的区别不那么明显。为什么要把它们划分成两个不同的层次呢?为了理解这 一点,我们必须把视野从单个网络扩展到一组网络。 2使用TCP/IP详解,卷1:协议 应用层 FTP 客户 运输层 网络层 链路层 以太网驱 动程序 以太网驱 动程序 以太网 以太网协议 IP协议 TCP协议 FTP协议 FTP 服务器 用户进程 内核 处理通信细节 处理应用 程序细节在8 0年代,网络不断增长的原因之一是大家都意识到只有一台孤立的计算机构成的“孤 岛”没有太大意义,于是就把这些孤立的系统组在一起形成网络。随着这样的发展,到了 9 0 年代,我们又逐渐认识到这种由单个网络构成的新的更大的“岛屿”同样没有太大的意义。 于是,人们又把多个网络连在一起形成一个网络的网络,或称作互连网 ( i n t e r n e t )。一个互连 网就是一组通过相同协议族互连在一起的网络。 构造互连网最简单的方法是把两个或多个网络通过路由器进行连接。它是一种特殊的用 于网络互连的硬件盒。路由器的好处是为不同类型的物理网络提供连接:以太网、令牌环网、 点对点的链接和F D D I(光纤分布式数据接口)等等。 这些盒子也称作I P路由器(IP Router),但我们这里使用路由器( R o u t e r )这个术语。 从历史上说,这些盒子称作网关( g a t e w a y),在很多T C P / I P文献中都使用这个术语。 现在网关这个术语只用来表示应用层网关:一个连接两种不同协议族的进程(例如, TCP/IP和IBM的SNA),它为某个特定的应用程序服务(常常是电子邮件或文件传输)。 图1 - 3是一个包含两个网络的互连网:一个以太网和一个令牌环网,通过一个路由器互相 连接。尽管这里是两台主机通过路由器进行通信,实际上以太网中的任何主机都可以与令牌 环网中的任何主机进行通信。 在图 1 - 3中,我们可以划分出端系统( End system)(两边的两台主机)和中间系统 (Intermediate system)(中间的路由器)。应用层和运输层使用端到端( En d - t o - e n d)协议。在 图中,只有端系统需要这两层协议。但是,网络层提供的却是逐跳( Ho p - b y - h o p)协议,两 个端系统和每个中间系统都要使用它。 图1-3 通过路由器连接的两个网络 在T C P / I P协议族中,网络层 I P提供的是一种不可靠的服务。也就是说,它只是尽可能快 地把分组从源结点送到目的结点,但是并不提供任何可靠性保证。而另一方面, T C P在不可 靠的I P层上提供了一个可靠的运输层。为了提供这种可靠的服务, T C P采用了超时重传、发 送和接收端到端的确认分组等机制。由此可见,运输层和网络层分别负责不同的功能。 从定义上看,一个路由器具有两个或多个网络接口层(因为它连接了两个或多个网络)。 第1章 概 述使用3 FTP 客户 FTP协议 FTP 服务器 TCP协议 IP协议 以太网协议以太网驱 动程序 以太网 以太网驱 动程序 令牌环驱 动程序 令牌环驱 动程序 令 牌 环 令牌环协议 I P协议 路由器任何具有多个接口的系统,英文都称作是多接口的 ( m u l t i h o m e d )。一个主机也可以有多个接口, 但一般不称作路由器 , 除非它的功能只是单纯地把分组从一个接口传送到另一个接口。同样, 路由器并不一定指那种在互联网中用来转发分组的特殊硬件盒。大多数的 T C P / I P实现也允许 一个多接口主机来担当路由器的功能,但是主机为此必须进行特殊的配置。在这种情况下, 我们既可以称该系统为主机(当它运行某一应用程序时,如 F T P或Te l n e t),也可以称之为路 由器(当它把分组从一个网络转发到另一个网络时)。在不同的场合下使用不同的术语。 互联网的目的之一是在应用程序中隐藏所有的物理细节。虽然这一点在图 1 - 3由两个网络 组成的互联网中并不很明显,但是应用层不能关心(也不关心)一台主机是在以太网上,而 另一台主机是在令牌环网上,它们通过路由器进行互连。随着增加不同类型的物理网络,可 能会有2 0个路由器,但应用层仍然是一样的。物理细节的隐藏使得互联网功能非常强大,也 非常有用。 连接网络的另一个途径是使用网桥。网桥是在链路层上对网络进行互连,而路由器则是 在网络层上对网络进行互连。网桥使得多个局域网( L A N)组合在一起,这样对上层来说就 好像是一个局域网。 TCP /IP倾向于使用路由器而不是网桥来连接网络,因此我们将着重介绍路由器。文献 [Perlman 1992]的第1 2章对路由器和网桥进行了比较。 1.3 TCP/IP的分层 在T C P / I P协议族中,有很多种协议。图 1 - 4给出了本书将要讨论的其他协议。 图1-4 TCP/IP协议族中不同层次的协议 4使用TCP/IP详解,卷1:协议 用户 进程 用户 进程 用户 进程 用户 进程 应用层 运输层 网络层 链路层硬件 接口 媒体T C P和U D P是两种最为著名的运输层协议,二者都使用 I P作为网络层协议。 虽然T C P使用不可靠的 I P服务,但它却提供一种可靠的运输层服务。本书第 1 7~2 2章将 详细讨论 T C P的内部操作细节。然后,我们将介绍一些 T C P的应用,如第 2 6章中的Te l n e t和 R l o g i n、第2 7章中的F T P以及第2 8章中的S M T P等。这些应用通常都是用户进程。 U D P为应用程序发送和接收数据报。一个数据报是指从发送方传输到接收方的一个信息 单元(例如,发送方指定的一定字节数的信息)。但是与T C P不同的是,U D P是不可靠的,它 不能保证数据报能安全无误地到达最终目的。本书第 11章将讨论U D P,然后在第1 4章(D N S : 域名系统),第1 5章(T F T P:简单文件传送协议),以及第 1 6章(BO OT P:引导程序协议) 介绍使用U D P的应用程序。S N M P也使用了U D P协议,但是由于它还要处理许多其他的协议, 因此本书把它留到第2 5章再进行讨论。 I P是网络层上的主要协议,同时被 T C P和U D P使用。T C P和U D P的每组数据都通过端系统 和每个中间路由器中的I P层在互联网中进行传输。在图1 - 4中,我们给出了一个直接访问I P的应 用程序。这是很少见的,但也是可能的(一些较老的选路协议就是以这种方式来实现的。当然 新的运输层协议也有可能使用这种方式)。第3章主要讨论I P协议,但是为了使内容更加有针对 性,一些细节将留在后面的章节中进行讨论。第9章和第1 0章讨论I P如何进行选路。 I C M P是I P协议的附属协议。I P层用它来与其他主机或路由器交换错误报文和其他重要信息。 第6章对I C M P的有关细节进行讨论。尽管I C M P主要被I P使用,但应用程序也有可能访问它。我 们将分析两个流行的诊断工具,P i n g和Tr a c e r o u t e(第7章和第8章),它们都使用了I C M P。 I G M P是I n t e r n e t组管理协议。它用来把一个 U D P数据报多播到多个主机。我们在第 1 2章中 描述广播(把一个 U D P数据报发送到某个指定网络上的所有主机)和多播的一般特性,然后 在第1 3章中对I G M P协议本身进行描述。 A R P(地址解析协议)和R A R P(逆地址解析协议)是某些网络接口(如以太网和令牌环 网)使用的特殊协议,用来转换 I P层和网络接口层使用的地址。我们分别在第 4章和第5章对 这两种协议进行分析和介绍。 1.4 互联网的地址 互联网上的每个接口必须有一个唯一的 I n t e r n e t地址(也称作 I P地址)。I P地址长32 bit。 I n t e r n e t地址并不采用平面形式的地址空间,如 1、2、3等。I P地址具有一定的结构,五类不同 的互联网地址格式如图1 - 5所示。 图1-5 五类互联网地址 第1章 概 述使用5 A类 7位 14位 21位 8位 16位 24位 网 络 号 网 络 号 网 络 号 主 机 号 主 机 号 主 机 号 28位 多 播 组 号 27位 (留 待 后 用) B类 C类 D类 E类这些3 2位的地址通常写成四个十进制的数,其中 每个整数对应一个字节。这种表示方法称作“点分十 进制表示法(Dotted decimal notation)”。例如,作者 的系统就是一个B类地址,它表示为:1 4 0 . 2 5 2 . 1 3 . 3 3。 区分各类地址的最简单方法是看它的第一个十进 制整数。图 1 - 6列出了各类地址的起止范围,其中第 一个十进制整数用加黑字体表示。 需要再次指出的是,多接口主机具有多个 I P地址,其中每个接口都对应一个 I P地址。 由于互联网上的每个接口必须有一个唯一的 I P地址,因此必须要有一个管理机构为接入互 联网的网络分配I P地址。这个管理机构就是互联网络信息中心( Internet Network Information C e n t r e),称作I n t e r N I C。I n t e r N I C只分配网络号。主机号的分配由系统管理员来负责。 I n t e r n e t注册服务( I P地址和D N S域名)过去由N I C来负责,其网络地址是n i c . d d n . m i l。 1 9 9 3年4月1日,I n t e r N I C成立。现在,N I C只负责处理国防数据网的注册请求,所有其他 的I n t e r n e t用户注册请求均由I n t e r N I C负责处理,其网址是:r s . i n t e r n i c . n e t。 事实上I n t e r N I C由三部分组成:注册服务(r s . i n t e r n i c . n e t),目录和数据库服 务(d s . i n t e r n i c . n e t),以及信息服务(i s . i n t e r n i c . n e t)。有关I n t e r N I C的其他 信息参见习题1 . 8。 有三类I P地址:单播地址(目的为单个主机)、广播地址(目的端为给定网络上的所有主 机)以及多播地址(目的端为同一组内的所有主机)。第1 2章和第1 3章将分别讨论广播和多播 的更多细节。 在3 . 4节中,我们在介绍I P选路以后将进一步介绍子网的概念。图 3 - 9给出了几个特殊的 I P 地址:主机号和网络号为全 0或全1。 1.5 域名系统 尽管通过I P地址可以识别主机上的网络接口,进而访问主机,但是人们最喜欢使用的还 是主机名。在 T C P / I P领域中,域名系统( D N S)是一个分布的数据库,由它来提供 I P地址和 主机名之间的映射信息。我们在第 1 4章将详细讨论D N S。 现在,我们必须理解,任何应用程序都可以调用一个标准的库函数来查看给定名字的主机 的I P地址。类似地,系统还提供一个逆函数— 给定主机的I P地址,查看它所对应的主机名。 大多数使用主机名作为参数的应用程序也可以把 I P地址作为参数。例如,在第 4章中当我 们用Te l n e t进行远程登录时,既可以指定一个主机名,也可以指定一个 I P地址。 1.6 封装 当应用程序用 T C P传送数据时,数据被送入协议栈中,然后逐个通过每一层直到被当作 一串比特流送入网络。其中每一层对收到的数据都要增加一些首部信息(有时还要增加尾部 信息),该过程如图 1 - 7所示。T C P传给I P的数据单元称作 T C P报文段或简称为 T C P段(T C P s e g m e n t)。I P传给网络接口层的数据单元称作 I P数据报(IP datagram)。通过以太网传输的比特 流称作帧(Fr a m e )。 6使用TCP/IP详解,卷1:协议 图1-6 各类IP地址的范围 类型 范 围 到 到 到 到 到图1 - 7中帧头和帧尾下面所标注的数字是典型以太网帧首部的字节长度。在后面的章节中 我们将详细讨论这些帧头的具体含义。 以太网数据帧的物理特性是其长度必须在 4 6~1 5 0 0字节之间。我们将在 4 . 5节遇到最小长 度的数据帧,在2 . 8节中遇到最大长度的数据帧。 所有的I n t e r n e t标准和大多数有关T C P / I P的书都使用o c t e t这个术语来表示字节。使 用这个过分雕琢的术语是有历史原因的,因为T C P / I P的很多工作都是在D E C - 1 0系统上 进行的,但是它并不使用8 bit的字节。由于现在几乎所有的计算机系统都采用8 bit的字 节,因此我们在本书中使用字节(byte)这个术语。 更准确地说,图1 - 7中I P和网络接口层之间传送的数据单元应该是分组( p a c k e t)。 分组既可以是一个I P数据报,也可以是I P数据报的一个片(f r a g m e n t)。我们将在11 . 5节 讨论IP数据报分片的详细情况。 图1-7 数据进入协议栈时的封装过程 U D P数据与T C P数据基本一致。唯一的不同是 U D P传给I P的信息单元称作 U D P数据报 (UDP datagram),而且U D P的首部长为8字节。 回想1 . 3节中的图1 - 4,由于T C P、U D P、I C M P和I G M P都要向I P传送数据,因此I P必须在 生成的I P首部中加入某种标识,以表明数据属于哪一层。为此, I P在首部中存入一个长度为 8 b i t的数值,称作协议域。 1表示为I C M P协议,2表示为I G M P协议,6表示为T C P协议,1 7表 示为U D P协议。 类似地,许多应用程序都可以使用 T C P或U D P来传送数据。运输层协议在生成报文首部 时要存入一个应用程序的标识符。 T C P和U D P都用一个1 6 b i t的端口号来表示不同的应用程序。 T C P和U D P把源端口号和目的端口号分别存入报文首部中。 网络接口分别要发送和接收 I P、A R P和R A R P数据,因此也必须在以太网的帧首部中加入 第1章 概 述使用7 用户数据 用户数据 应用数据 应用数据 应用数据 以太网 以太网 驱动程序 TCP段 IP数据报 TCP首部 TCP首部 以太网帧 46~1500字节 IP首部 IP首部以太网 首部 以太网 尾部 TCP首部 A p p l 首部 应用程序某种形式的标识,以指明生成数据的网络层协议。为此,以太网的帧首部也有一个 16 bit的帧 类型域。 1.7 分用 当目的主机收到一个以太网数据帧时,数据就开始从协议栈中由底向上升,同时去掉各 层协议加上的报文首部。每层协议盒都要去检查报文首部中的协议标识,以确定接收数据的 上层协议。这个过程称作分用( D e m u l t i p l e x i n g),图1 - 8显示了该过程是如何发生的。 图1-8 以太网数据帧的分用过程 为协议I C M P和I G M P定位一直是一件很棘手的事情。在图1 - 4中,把它们与I P放在 同一层上,那是因为事实上它们是I P的附属协议。但是在这里,我们又把它们放在I P层 的上面,这是因为ICMP和IGMP报文都被封装在IP数据报中。 对于A R P和R A R P,我们也遇到类似的难题。在这里把它们放在以太网设备驱动程 序的上方,这是因为它们和I P数据报一样,都有各自的以太网数据帧类型。但在图 2 - 4 中,我们又把A R P作为以太网设备驱动程序的一部分,放在 I P层的下面,其原因在逻 辑上是合理的。 这些分层协议盒并不都是完美的。 当进一步描述T C P的细节时,我们将看到协议确实是通过目的端口号、源 I P地址和源端口 号进行解包的。 1.8 客户-服务器模型 大部分网络应用程序在编写时都假设一端是客户,另一端是服务器,其目的是为了让服 务器为客户提供一些特定的服务。 可以将这种服务分为两种类型:重复型或并发型。重复型服务器通过以下步骤进行交互: 8使用TCP/IP详解,卷1:协议 应用程序 应用程序 应用程序 应用程序 根据 T C P或U D P首 部中的端口号进行 分用 根据 I P首部中的协 议值进行分用 根据以太网首部中 的帧类型进行分用 以太网 驱动程序 进入的帧I1. 等待一个客户请求的到来。 I2. 处理客户请求。 I3. 发送响应给发送请求的客户。 I4. 返回I 1步。 重复型服务器主要的问题发生在 I 2状态。在这个时候,它不能为其他客户机提供服务。 相应地,并发型服务器采用以下步骤: C1. 等待一个客户请求的到来。 C2. 启动一个新的服务器来处理这个客户的请求。在这期间可能生成一个新的进程、任务 或线程,并依赖底层操作系统的支持。这个步骤如何进行取决于操作系统。生成的新服务器 对客户的全部请求进行处理。处理结束后,终止这个新服务器。 C3. 返回C 1步。 并发服务器的优点在于它是利用生成其他服务器的方法来处理客户的请求。也就是说, 每个客户都有它自己对应的服务器。如果操作系统允许多任务,那么就可以同时为多个客户 服务。 对服务器,而不是对客户进行分类的原因是因为对于一个客户来说,它通常并不能够辨 别自己是与一个重复型服务器或并发型服务器进行对话。 一般来说,T C P服务器是并发的,而 U D P服务器是重复的,但也存在一些例外。我们将 在11 . 1 2节对U D P对其服务器产生的影响进行详细讨论,并在 1 8 . 11节对T C P对其服务器的影响 进行讨论。 1.9 端口号 前面已经指出过, T C P和U D P采用16 bit的端口号来识别应用程序。那么这些端口号是如 何选择的呢? 服务器一般都是通过知名端口号来识别的。例如,对于每个 T C P / I P实现来说,F T P服务 器的T C P端口号都是2 1,每个Te l n e t服务器的T C P端口号都是2 3,每个T F T P (简单文件传送协 议)服务器的U D P端口号都是6 9。任何T C P / I P实现所提供的服务都用知名的 1~1 0 2 3之间的端 口号。这些知名端口号由 I n t e r n e t号分配机构(Internet Assigned Numbers Authority, IANA) 来管理。 到1 9 9 2年为止,知名端口号介于1~2 5 5之间。2 5 6~1 0 2 3之间的端口号通常都是由 U n i x系统占用,以提供一些特定的U n i x服务— 也就是说,提供一些只有U n i x系统才 有的、而其他操作系统可能不提供的服务。现在IANA管理1~1023之间所有的端口号。 I n t e r n e t扩展服务与U n i x特定服务之间的一个差别就是Te l n e t和R l o g i n。它们二者都 允许通过计算机网络登录到其他主机上。Te l n e t是采用端口号为2 3的T C P / I P标准且几乎 可以在所有操作系统上进行实现。相反,R l o g i n最开始时只是为U n i x系统设计的(尽管 许多非Unix系统现在也提供该服务),因此在80年代初,它的有名端口号为513。 客户端通常对它所使用的端口号并不关心,只需保证该端口号在本机上是唯一的就可以 了。客户端口号又称作临时端口号(即存在时间很短暂)。这是因为它通常只是在用户运行该 客户程序时才存在,而服务器则只要主机开着的,其服务就运行。 大多数T C P / I P实现给临时端口分配 1 0 2 4~5 0 0 0之间的端口号。大于 5 0 0 0的端口号是为其 第1章 概 述使用9他服务器预留的(I n t e r n e t上并不常用的服务)。我们可以在后面看见许多这样的给临时端口分 配端口号的例子。 Solaris 2.2是一个很有名的例外。通常T C P和U D P的缺省临时端口号从3 2 7 6 8开始。 在E.4节中,我们将详细描述系统管理员如何对配置选项进行修改以改变这些缺省项。 大多数U n i x系统的文件/e t c / s e r v i c e s都包含了人们熟知的端口号。为了找到 Te l n e t服 务器和域名系统的端口号,可以运行以下语句: 保留端口号 U n i x系统有保留端口号的概念。只有具有超级用户特权的进程才允许给它自己分配一个 保留端口号。 这些端口号介于 1~1 0 2 3之间,一些应用程序(如有名的 R l o g i n,2 6 . 2节)将它作为客户 与服务器之间身份认证的一部分。 1.10 标准化过程 究竟是谁控制着 T C P / I P协议族,又是谁在定义新的标准以及其他类似的事情?事实上, 有四个小组在负责I n t e r n e t技术。 1) Internet协会(I S O C,Internet Society)是一个推动、支持和促进 I n t e r n e t不断增长和发 展的专业组织,它把I n t e r n e t作为全球研究通信的基础设施。 2) Internet体系结构委员会(I A B,Internet Architecture Board)是一个技术监督和协调的 机构。它由国际上来自不同专业的 1 5个志愿者组成,其职能是负责 I n t e r n e t标准的最后编辑和 技术审核。I A B隶属于I S O C。 3) Internet工程专门小组(I E T F,Internet Engineering Task Force)是一个面向近期标准的组 织,它分为9个领域(应用、寻径和寻址、安全等等)。I E T F开发成为I n t e r n e t标准的规范。为帮 助IETF主席,又成立了Internet工程指导小组(IESG, Internet Engineering Steering Group)。 4) Internet研究专门小组(IR I F,Internet Research Task Force)主要对长远的项目进行研究。 I RT F和I E T F都隶属于I A B。文献[Crocker 1993]提供了关于I n t e r n e t内部标准化进程更为详 细的信息,同时还介绍了它的早期历史。 1.11 RFC 所有关于I n t e r n e t的正式标准都以R F C(Request for Comment)文档出版。另外,大量的 R F C并不是正式的标准,出版的目的只是为了提供信息。 R F C的篇幅从1页到2 0 0页不等。每 一项都用一个数字来标识,如 RFC 11 2 2,数字越大说明R F C的内容越新。 所有的R F C都可以通过电子邮件或用 F T P从I n t e r n e t上免费获取。如果发送下面这份电子 邮件,就会收到一份获取R F C的方法清单: 10使用TCP/IP详解,卷1:协议 称它使用TCP端口号23 称它使用UDP端口号53和TCP端口号53To: rfc-info@ISI.EDU Subject: getting rfcs help: ways_to_get_rfcs 最新的R F C索引总是搜索信息的起点。这个索引列出了 R F C被替换或局部更新的时间。 下面是一些重要的R F C文档: 1 ) 赋值R F C(Assigned Numbers RFC)列出了所有I n t e r n e t协议中使用的数字和常数。至 本书出版时为止,最新 R F C的编号是 1340 [Reynolds和Postel 1992]。所有著名的 I n t e r n e t端口号都列在这里。 当这个R F C被更新时(通常每年至少更新一次),索引清单会列出RFC 1340被替换的时间。 2) I n t e r n e t正式协议标准,目前是 RFC 1600[Postel 1994]。这个R F C描述了各种I n t e r n e t协 议的标准化现状。每种协议都处于下面几种标准化状态之一:标准、草案标准、提议 标准、实验标准、信息标准和历史标准。另外,对每种协议都有一个要求的层次、必 需的、建议的、可选择的、限制使用的或者不推荐的。 与赋值R F C一样,这个R F C也定期更新。请随时查看最新版本。 3 ) 主机需求R F C,11 2 2和1123[Braden 1989a, 1989b]。RFC 11 2 2针对链路层、网络层和运 输层;RFC 11 2 3针对应用层。这两个 R F C对早期重要的R F C文档作了大量的纠正和解 释。如果要查看有关协议更详细的细节内容,它们通常是一个入口点。它们列出了协 议中关于“必须”、“应该”、“可以”、“不应该”或者“不能”等特性及其实现细节。 文献[Borman 1993b]提供了有关这两个R F C的实用内容。RFC 1127[Braden 1989c]对工 作小组开发主机需求R F C过程中的讨论内容和结论进行了非正式的总结。 4) 路由器需求R F C,目前正式版是RFC 1009[Braden and Postel 1987],但一个新版已接近 完成[Almquist 1993]。它与主机需求R F C类似,但是只单独描述了路由器的需求。 1.12 标准的简单服务 有一些标准的简单服务几乎每种实现都要提供。在本书中我们将使用其中的一些服务程 序,而客户程序通常选择 Te l n e t。图1 - 9描述了这些服务。从该图可以看出,当使用 T C P和 U D P提供相同的服务时,一般选择相同的端口号。 图1-9 大多数实现都提供的标准的简单服务 第1章 概 述使用11 名 字 T C P端口号 U D P端口号 R F C 描 述 e c h o 7 7 8 6 2 服务器返回客户发送的所有内容 d i s c a r d 9 9 8 6 3 服务器丢弃客户发送的所有内容 d a y t i m e 1 3 1 3 8 6 7 服务器以可读形式返回时间和日期 c h a r g e n 1 9 1 9 8 6 4 当客户发送一个数据报时, T C P服务器发 送一串连续的字符流,直到客户中断连接。 U D P服务器发送一个随机长度的数据报 t i m e 3 7 3 7 8 6 8 服务器返回一个二进制形式的 32 bit 数, 表示从U T C时间1 9 0 0年1月1日午夜至今的秒 数如果仔细检查这些标准的简单服务以及其他标准的 T C P / I P服务(如Te l n e t、F T P、 S M T P等)的端口号时,我们发现它们都是奇数。这是有历史原因的,因为这些端口号 都是从N C P端口号派生出来的(N C P,即网络控制协议,是A R PA N E T的运输层协议, 是T C P的前身)。N C P是单工的,不是全双工的,因此每个应用程序需要两个连接,需 预留一对奇数和偶数端口号。当 T C P和U D P成为标准的运输层协议时,每个应用程序 只需要一个端口号,因此就使用了NCP中的奇数。 1.13 互联网 在图1 - 3中,我们列举了一个由两个网络组成的互联网— 一个以太网和一个令牌环网。 在1 . 4节和1 . 9节中,我们讨论了世界范围内的互联网— I n t e r n e t,以及集中分配I P地址的需要 (I n t e r N I C),还讨论了知名端口号( I A N A)。i n t e r n e t这个词第一个字母是否大写决定了它具 有不同的含义。 i n t e r n e t意思是用一个共同的协议族把多个网络连接在一起。而 I n t e r n e t指的是世界范围内 通过T C P / I P互相通信的所有主机集合(超过 1 0 0万台)。I n t e r n e t是一个i n t e r n e t,但i n t e r n e t不等 于I n t e r n e t。 1.14 实现 既成事实标准的 T C P / I P软件实现来 自于位于伯克利的加利福尼亚大学的计 算机系统研究小组。从历史上看,软件 是随同4.x BSD系统(Berkeley Software D i s t r i b u t i o n)的网络版一起发布的。它 的源代码是许多其他实现的基础。 图1 - 1 0列举了各种 B S D版本发布的 时间,并标注了重要的 T C P / I P特性。列 在左边的B S D网络版,其所有的网络源 代码可以公开得到:包括协议本身以及 许多应用程序和工具(如Te l n e t和F T P)。 在本书中,我们将使用“伯克利派 生系统”来指 SunOS 4.x、S V R 4以及 AIX 3.2等那些基于伯克利源代码开发的 系统。这些系统有很多共同之处,经常 包含相同的错误。 起初关于I n t e r n e t的很多研究现在仍 然在伯克利系统中应用— 新的拥塞控制算法( 2 1 . 7节)、多播(1 2 . 4节)、“长肥管道”修改 (2 4 . 3节)以及其他类似的研究。 1.15 应用编程接口 使用T C P / I P协议的应用程序通常采用两种应用编程接口( A P I):s o c k e t和T L I(运输层接 12使用TCP/IP详解,卷1:协议 图1-10 不同的BSD版及其重要的TCP/IP特性 第一个广泛可用的 TCP/IP版本 TCP性能得到改善 慢启动,拥塞避免, 快速重传 快速恢复,TCP头部预测, SLIP头部压缩, 路由表修改 多播, 长肥管道修改 又称为Net/3 BSD网络软件2.0版 (1991):Net/2 BSD网络软件1.0版 (1989):Net/1口:Transport Layer Interface)。前者有时称作“Berkeley socket”,表明它是从伯克利版发展 而来的。后者起初是由 AT & T开发的,有时称作 X T I(X / O p e n运输层接口),以承认X / O p e n这 个自己定义标准的国际计算机生产商所做的工作。 X T I实际上是T L I的一个超集。 本书不是一本编程方面的书,但是偶尔会引用一些内容来说明 T C P / I P的特性,不管大多 数的 A P I(s o c k e t)是否提供它们。所有关于 s o c k e t和T L I的编程细节请参阅文献 [ S t e v e n s 1 9 9 0 ]。 1.16 测试网络 图1 - 11是本书中所有的例子运行的测试网络。为阅读时参考方便,该图还复制在本书扉 页前的插页中。 图1-11 本书中所有例子运行的测试网络,所有的IP地址均从140.252开始编址 在这个图中(作者的子网),大多数的例子都运行在下面四个系统中。图中所有的 I P地址 属于B类地址,网络号为 1 4 0 . 2 5 2。所有的主机名属于 . t u c . n o a o . e d u这个域(n o a o代表 National Optical Astronomy Observatories,t u c代表Tu c s o n)。例如,右下方的系统有一个完 整的名字: s v r 4 . t u c . n o a o . e d u,其I P地址是:1 4 0 . 2 5 2 . 1 3 . 3 4。每个方框上方的名称是该 主机运行的操作系统。这一组系统和网络上的主机及路由器运行于不同的 T C P / I P实现。 需要指出的是,n o a o . e d u这个域中的网络和主机要比图 1 - 11中的多得多。这里列出来的 只是本书中将要用到的系统。 在3 . 4节中,我们将描述这个网络所用到的子网形式。在 4 . 6节中将介绍s u n与n e t b之间 的拨号S L I P的有关细节。2 . 4节将详细讨论S L I P。 1.17 小结 本章快速地浏览了TCP/IP协议族,介绍了在后面的章节中将要详细讨论的许多术语和协议。 第1章 概 述使用13 路由器 以太网 调制解 调器 调制解 调器 (拨号) 以太网T C P / I P协议族分为四层:链路层、网络层、运输层和应用层,每一层各有不同的责任。 在T C P / I P中,网络层和运输层之间的区别是最为关键的:网络层( I P)提供点到点的服务, 而运输层(T C P和U D P)提供端到端的服务。 一个互联网是网络的网络。构造互联网的共同基石是路由器,它们在 I P层把网络连在一 起。第一个字母大写的I n t e r n e t是指分布在世界各地的大型互联网,其中包括 1万多个网络和超 过1 0 0万台主机。 在一个互联网上,每个接口都用 I P地址来标识,尽管用户习惯使用主机名而不是 I P地址。 域名系统为主机名和 I P地址之间提供动态的映射。端口号用来标识互相通信的应用程序。服 务器使用知名端口号,而客户使用临时设定的端口号。 习题 1.1 请计算最多有多少个A类、B类和C类网络号。 1.2 用匿名F T P(见2 7 . 3节)从主机n i c . m e r i t . e d u上获取文件n s f n e t / s t a t i s t i c s / h i s t o r y . n e t c o u n t。该文件包含在N S F N E T网络上登记的国内和国外的网络数。画一 坐标系,横坐标代表年,纵坐标代表网络总数的对数值。纵坐标的最大值是习题 1 . 1的结 果。如果数据显示一个明显的趋势,请估计按照当前的编址体制推算,何时会用完所有 的网络地址(3 . 1 0节讨论解决该难题的建议)。 1.3 获取一份主机需求R F C拷贝[Braden 1989a],阅读有关应用于T C P / I P协议族每一层的稳健 性原则。这个原则的参考对象是什么? 1.4 获取一份最新的赋值R F C拷贝。“quote of the day”协议的有名端口号是什么?哪个 R F C 对该协议进行了定义? 1.5 如果你有一个接入 T C P / I P互联网的主机帐号,它的主 I P地址是多少?这台主机是否接入 了I n t e r n e t?它是多接口主机吗? 1.6 获取一份RFC 1000的拷贝,了解R F C这个术语从何而来。 1.7 与I n t e r n e t协会联系,i s o c @ i s o c . o r g或者+1 703 648 9888,了解有关加入的情况。 1.8 用匿名F T P从主机i s . i n t e r n i c . n e t处获取文件a b o u t - i n t e r n i c / i n f o r m a t i o n - a b o u t - t h e - i n t e r n i c。 14使用TCP/IP详解,卷1:协议第2章 链 路 层 2.1 引言 从图1 - 4中可以看出,在T C P / I P协议族中,链路层主要有三个目的:(1)为I P模块发送和 接收I P数据报;(2)为A R P模块发送A R P请求和接收A R P应答;(3)为R A R P发送R A R P请 求和接收R A R P应答。T C P / I P支持多种不同的链路层协议,这取决于网络所使用的硬件,如以 太网、令牌环网、F D D I(光纤分布式数据接口)及 R S-2 3 2串行线路等。 在本章中,我们将详细讨论以太网链路层协议,两个串行接口链路层协议( S L I P和P P P), 以及大多数实现都包含的环回( l o o p b a c k)驱动程序。以太网和 S L I P是本书中大多数例子使 用的链路层。对 M T U(最大传输单元)进行了介绍,这个概念在本书的后面章节中将多次遇 到。我们还讨论了如何为串行线路选择 M T U。 2.2 以太网和IEEE 802封装 以太网这个术语一般是指数字设备公司( Digital Equipment Corp.)、英特尔公司( I n t e l C o r p .)和X e r o x公司在1 9 8 2年联合公布的一个标准。它是当今 T C P / I P采用的主要的局域网技 术。它采用一种称作 C S M A / C D的媒体接入方法,其意思是带冲突检测的载波侦听多路接入 (Carrier Sense, Multiple Access with Collision Detection)。它的速率为10 Mb/s,地址为48 bit。 几年后,I E E E(电子电气工程师协会) 8 0 2委员会公布了一个稍有不同的标准集,其中 8 0 2 . 3针对整个C S M A / C D网络,8 0 2 . 4针对令牌总线网络,8 0 2 . 5针对令牌环网络。这三者的共 同特性由8 0 2 . 2标准来定义,那就是8 0 2网络共有的逻辑链路控制( L L C)。不幸的是,8 0 2 . 2和 8 0 2 . 3定义了一个与以太网不同的帧格式。文献 [Stallings 1987]对所有的IEEE 802标准进行了 详细的介绍。 在T C P / I P世界中,以太网I P数据报的封装是在RFC 894[Hornig 1984]中定义的,IEEE 802 网络的I P数据报封装是在RFC 1042[Postel and Reynolds 1988]中定义的。主机需求R F C要求每 台I n t e r n e t主机都与一个10 Mb/s的以太网电缆相连接: 1) 必须能发送和接收采用RFC 894(以太网)封装格式的分组。 2) 应该能接收与RFC 894混合的RFC 1042(IEEE 802)封装格式的分组。 3) 也许能够发送采用RFC 1042格式封装的分组。如果主机能同时发送两种类型的分组数 据,那么发送的分组必须是可以设置的,而且默认条件下必须是 RFC 894分组。 最常使用的封装格式是 RFC 894定义的格式。图2 - 1显示了两种不同形式的封装格式。图 中每个方框下面的数字是它们的字节长度。 两种帧格式都采用48 bit(6字节)的目的地址和源地址( 8 0 2 . 3允许使用16 bit的地址,但 一般是48 bit地址)。这就是我们在本书中所称的硬件地址。A R P和R A R P协议(第4章和第5章) 对32 bit的I P地址和48 bit的硬件地址进行映射。 接下来的2个字节在两种帧格式中互不相同。在 8 0 2标准定义的帧格式中,长度字段是指它后续数据的字节长度,但不包括 C R C检验码。以太网的类型字段定义了后续数据的类型。 在8 0 2标准定义的帧格式中,类型字段则由后续的子网接入协议( Sub-network Access P r o t o c o l,S N A P)的首部给出。幸运的是, 8 0 2定义的有效长度值与以太网的有效类型值无一 相同,这样,就可以对两种帧格式进行区分。 在以太网帧格式中,类型字段之后就是数据;而在 8 0 2帧格式中,跟随在后面的是 3字节 的802.2 LLC和5字节的802.2 SNAP。目的服务访问点( Destination Service Access Point, D S A P)和源服务访问点(Source Service Access Point, SSAP)的值都设为0 x a a。Ct r l字段的 值设为3。随后的3个字节o rg code都置为0。再接下来的2个字节类型字段和以太网帧格式一样 (其他类型字段值可以参见 RFC 1340 [Reynolds and Postel 1992])。 C R C字段用于帧内后续字节差错的循环冗余码检验(检验和)(它也被称为F C S或帧检验 序列)。 8 0 2 . 3标准定义的帧和以太网的帧都有最小长度要求。 8 0 2 . 3规定数据部分必须至少为 3 8字 节,而对于以太网,则要求最少要有 4 6字节。为了保证这一点,必须在不足的空间插入填充 (p a d)字节。在开始观察线路上的分组时将遇到这种最小长度的情况。 在本书中,我们在需要的时候将给出以太网的封装格式,因为这是最为常见的封装格式。 16使用TCP/IP详解,卷1:协议 目的地址 源地址 长度 类型 数 据 数据报 38~1492 46~1500 46~1500 38~1492 请求/应答 请求/应答 46~1500字节 数 据 数据报 请求/应答 请求/应答 类型 0800 类型 0806 类型 8035 类型 0800 类型 0806 类型 8035 类型源地址目的地址 以太网封装 图2-1 IEEE 802.2/802.3(RFC 1042)和以太网的封装格式(RFC 894)2.3 尾部封装 RFC 893[Leffler and Karels 1984]描述了另一种用于以太网的封装格式,称作尾部封装 (trailer encapsulation)。这是一个早期B S D系统在DEC VA X机上运行时的试验格式,它通过 调整I P数据报中字段的次序来提高性能。在以太网数据帧中,开始的那部分是变长的字段 (I P首部和T C P首部)。把它们移到尾部(在 C R C之前),这样当把数据复制到内核时,就可以 把数据帧中的数据部分映射到一个硬件页面,节省内存到内存的复制过程。 T C P数据报的长 度是5 1 2字节的整数倍,正好可以用内核中的页表来处理。两台主机通过协商使用 A R P扩展协 议对数据帧进行尾部封装。这些数据帧需定义不同的以太网帧类型值。 现在,尾部封装已遭到反对,因此我们不对它举任何例子。有兴趣的读者请参阅 RFC 893 以及文献[ L e ffler et al. 1989]的11 . 8节。 2.4 SLIP:串行线路IP S L I P的全称是Serial Line IP。它是一种在串行线路上对 I P数据报进行封装的简单形式,在 RFC 1055[Romkey 1988]中有详细描述。S L I P适用于家庭中每台计算机几乎都有的 R S - 2 3 2串 行端口和高速调制解调器接入 I n t e r n e t。 下面的规则描述了S L I P协议定义的帧格式: 1) IP数据报以一个称作 E N D(0 x c 0)的特殊字符结束。同时,为了防止数据报到来之前 的线路噪声被当成数据报内容,大多数实现在数据报的开始处也传一个 E N D字符(如果有线 路噪声,那么E N D字符将结束这份错误的报文。这样当前的报文得以正确地传输,而前一个 错误报文交给上层后,会发现其内容毫无意义而被丢弃)。 2) 如果I P报文中某个字符为 E N D,那么就要连续传输两个字节 0 x d b和0 x d c来取代它。 0 x d b这个特殊字符被称作S L I P的E S C字符,但是它的值与A S C I I码的E S C字符(0 x 1 b)不同。 3) 如果I P报文中某个字符为 S L I P的E S C字符,那么就要连续传输两个字节 0 x d b和0 x d d来 取代它。 图2 - 2中的例子就是含有一个 E N D字符和一个E S C字符的I P报文。在这个例子中,在串行 线路上传输的总字节数是原 I P报文长度再加4个字节。 图2-2 SLIP报文的封装 S L I P是一种简单的帧封装方法,还有一些值得一提的缺陷: 1) 每一端必须知道对方的I P地址。没有办法把本端的I P地址通知给另一端。 2) 数据帧中没有类型字段(类似于以太网中的类型字段)。如果一条串行线路用于 S L I P, 那么它不能同时使用其他协议。 第2章 链 路 层使用17 IP数据报3 ) S L I P没有在数据帧中加上检验和(类似于以太网中的 C R C字段)。如果S L I P传输的报 文被线路噪声影响而发生错误,只能通过上层协议来发现(另一种方法是,新型的调制解调 器可以检测并纠正错误报文)。这样,上层协议提供某种形式的 C R C就显得很重要。在第 3章 和第1 7章中,我们将看到 I P首部和T C P首部及其数据始终都有检验和。在第 11章中,将看到 U D P首部及其数据的检验和却是可选的。 尽管存在这些缺点,S L I P仍然是一种广泛使用的协议。 S L I P的历史要追溯到1 9 8 4年,Rick Adams第一次在4 . 2 B S D系统中实现。尽管它本 身的描述是一种非标准的协议,但是随着调制解调器的速率和可靠性的提高, S L I P越 来越流行。现在,它的许多产品可以公开获得,而且很多厂家都支持这种协议。 2.5 压缩的SLIP 由于串行线路的速率通常较低( 19200 b/s或更低),而且通信经常是交互式的(如 Te l n e t 和R l o g i n,二者都使用T C P),因此在S L I P线路上有许多小的T C P分组进行交换。为了传送 1个 字节的数据需要2 0个字节的I P首部和2 0个字节的T C P首部,总数超过4 0个字节(1 9 . 2节描述了 R l o g i n会话过程中,当敲入一个简单命令时这些小报文传输的详细情况)。 既然承认这些性能上的缺陷,于是人们提出一个被称作 C S L I P(即压缩S L I P)的新协议, 它在RFC 1144[Jacobson 1990a]中被详细描述。C S L I P一般能把上面的4 0个字节压缩到3或5个 字节。它能在C S L I P的每一端维持多达1 6个T C P连接,并且知道其中每个连接的首部中的某些 字段一般不会发生变化。对于那些发生变化的字段,大多数只是一些小的数字和的改变。这 些被压缩的首部大大地缩短了交互响应时间。 现在大多数的S L I P产品都支持C S L I P。作者所在的子网(参见封面内页)中有两条 SLIP链路,它们均是CSLIP链路。 2.6 PPP:点对点协议 P P P,点对点协议修改了S L I P协议中的所有缺陷。P P P包括以下三个部分: 1) 在串行链路上封装 I P数据报的方法。 P P P既支持数据为 8位和无奇偶检验的异步模式 (如大多数计算机上都普遍存在的串行接口),还支持面向比特的同步链接。 2) 建立、配置及测试数据链路的链路控制协议( L C P:Link Control Protocol)。它允许通 信双方进行协商,以确定不同的选项。 3) 针对不同网络层协议的网络控制协议( N C P:Network Control Protocol)体系。当前 R F C定义的网络层有I P、O S I网络层、D E C n e t以及A p p l e Ta l k。例如,IP NCP允许双方商定是 否对报文首部进行压缩,类似于 C S L I P(缩写词N C P也可用在T C P的前面)。 RFC 1548[Simpson 1993]描述了报文封装的方法和链路控制协议。 RFC 1332[McGregor 1 9 9 2 ]描述了针对I P的网络控制协议。 P P P数据帧的格式看上去很像 I S O的H D L C(高层数据链路控制)标准。图 2 - 3是P P P数据 帧的格式。 每一帧都以标志字符0 x 7 e开始和结束。紧接着是一个地址字节,值始终是 0 x ff,然后是一 个值为0 x 0 3的控制字节。 18使用TCP/IP详解,卷1:协议图2-3 PPP数据帧的格式 接下来是协议字段,类似于以太网中类型字段的功能。当它的值为 0 x 0 0 2 1时,表示信息 字段是一个I P数据报;值为0 x c 0 2 1时,表示信息字段是链路控制数据;值为 0 x 8 0 2 1时,表示 信息字段是网络控制数据。 C R C字段(或F C S,帧检验序列)是一个循环冗余检验码,以检测数据帧中的错误。 由于标志字符的值是 0 x 7 e,因此当该字符出现在信息字段中时, P P P需要对它进行转义。 在同步链路中,该过程是通过一种称作比特填充 (bit stuff i n g )的硬件技术来完成的[ Ta n e n b a u m 1 9 8 9 ]。在异步链路中,特殊字符 0 x 7 d用作转义字符。当它出现在 P P P数据帧中时,那么紧接 着的字符的第6个比特要取其补码,具体实现过程如下: 1) 当遇到字符0 x 7 e时,需连续传送两个字符: 0 x 7 d和0 x 5 e,以实现标志字符的转义。 2) 当遇到转义字符0 x 7 d时,需连续传送两个字符: 0 x 7 d和0 x 5 d,以实现转义字符的转义。 3 ) 默认情况下,如果字符的值小于 0 x 2 0(比如,一个A S C I I控制字符),一般都要进行转 义。例如,遇到字符0 x 0 1时需连续传送0 x 7 d和0 x 2 1两个字符(这时,第 6个比特取补码后变为 1,而前面两种情况均把它变为 0)。 这样做的原因是防止它们出现在双方主机的串行接口驱动程序或调制解调器中,因为有 时它们会把这些控制字符解释成特殊的含义。另一种可能是用链路控制协议来指定是否需要 对这3 2个字符中的某一些值进行转义。默认情况下是对所有的 3 2个字符都进行转义。 与S L I P类似,由于P P P经常用于低速的串行链路,因此减少每一帧的字节数可以降低应用 程序的交互时延。利用链路控制协议,大多数的产品通过协商可以省略标志符和地址字段, 并且把协议字段由 2个字节减少到 1个字节。如果我们把 P P P的帧格式与前面的 S L I P的帧格式 (图2 - 2)进行比较会发现, P P P只增加了 3个额外的字节: 1个字节留给协议字段,另 2个给 C R C字段使用。另外,使用I P网络控制协议,大多数的产品可以通过协商采用 Van Jacobson报 文首部压缩方法(对应于C S L I P压缩),减小I P和T C P首部长度。 总的来说,P P P比S L I P具有下面这些优点:(1) PPP支持在单根串行线路上运行多种协议, 不只是I P协议;(2) 每一帧都有循环冗余检验; (3) 通信双方可以进行 I P地址的动态协商(使用 I P网络控制协议); (4) 与C S L I P类似,对T C P和I P报文首部进行压缩; (5) 链路控制协议可以 对多个数据链路选项进行设置。为这些优点付出的代价是在每一帧的首部增加 3个字节,当建 立链路时要发送几帧协商数据,以及更为复杂的实现。 尽管P P P比S L I P有更多的优点,但是现在的S L I P用户仍然比P P P用户多。随着产品 越来越多,产家也开始逐渐支持PPP,因此最终PPP应该取代SLIP。 第2章 链 路 层使用19 标志 地址 控制 协议 协议 协议 协议 网络控制数据 链路控制数据 IP数据报 最多1500字节 信 息 标志2.7 环回接口 大多数的产品都支持环回接口( Loopback Interface),以允许运行在同一台主机上的客户 程序和服务器程序通过 T C P / I P进行通信。A类网络号1 2 7就是为环回接口预留的。根据惯例, 大多数系统把I P地址1 2 7 . 0 . 0 . 1分配给这个接口,并命名为 l o c a l h o s t。一个传给环回接口的 I P数 据报不能在任何网络上出现。 我们想象,一旦传输层检测到目的端地址是环回地址时,应该可以省略部分传输层和所 有网络层的逻辑操作。但是大多数的产品还是照样完成传输层和网络层的所有过程,只是当 I P数据报离开网络层时把它返回给自己。 图2 - 4是环回接口处理I P数据报的简单过程。 图2-4 环回接口处理IP数据报的过程 图中需要指出的关键点是: 1) 传给环回地址(一般是1 2 7 . 0 . 0 . 1)的任何数据均作为I P输入。 2) 传给广播地址或多播地址的数据报复制一份传给环回接口,然后送到以太网上。这是 因为广播传送和多播传送的定义(第 1 2章)包含主机本身。 3 ) 任何传给该主机I P地址的数据均送到环回接口。 看上去用传输层和 I P层的方法来处理环回数据似乎效率不高,但它简化了设计,因为环 回接口可以被看作是网络层下面的另一个链路层。网络层把一份数据报传送给环回接口,就 像传给其他链路层一样,只不过环回接口把它返回到 I P的输入队列中。 在图2 - 4中,另一个隐含的意思是送给主机本身 I P地址的I P数据报一般不出现在相应的网 络上。例如,在一个以太网上,分组一般不被传出去然后读回来。某些 B S D以太网的设备驱 动程序的注释说明,许多以太网接口卡不能读回它们自己发送出去的数据。由于一台主机必 20使用TCP/IP详解,卷1:协议 IP输出 函数 IP输入 函数 放入IP输入 队列中 放入IP输入 队列中 是 否 是 目的IP地址是否与接 口IP地址相同? 否,用ARP获 取目的主机的 以太网地址 环回驱动程序 目的I P地址是否与广播 地址或多播地址相同? 发送 以太网 接收 以太网驱 动程序 基于以太网帧 类型进行分用须处理发送给自己的I P数据报,因此图2 - 4所示的过程是最为简单的处理办法。 4 . 4 B S D系统定义了变量u s e l o o p b a c k,并初始化为1。但是,如果这个变量置为 0, 以太网驱动程序就会把本地分组送到网络,而不是送到环回接口上。它也许不能工作, 这取决于所使用的以太网接口卡和设备驱动程序。 2.8 最大传输单元MTU 正如在图2 - 1看到的那样,以太网和8 0 2 . 3对数据帧的长度都有一个限制,其最大值分别是 1 5 0 0和1 4 9 2字节。链路层的这个特性称作 M T U,最大传输单元。不同类型的网络大 多数都有一个上限。 如果 I P层有一个数据报要传,而且数 据的长度比链路层的 M T U还大,那么 I P层 就需要进行分片( f r a g m e n t a t i o n),把数据 报分成若干片,这样每一片都小于 M T U。 我们将在11 . 5节讨论I P分片的过程。 图2 - 5列出了一些典型的 M T U值,它们 摘自RFC 1191[Mogul and Deering 1990]。点到点的链路层(如S L I P和P P P)的M T U并非指的 是网络媒体的物理特性。相反,它是一个逻辑限制,目的是为交互使用提供足够快的响应时 间。在2 . 1 0节中,我们将看到这个限制值是如何计算出来的。 在3 . 9节中,我们将用n e t s t a t命令打印出网络接口的M T U。 2.9 路径MTU 当在同一个网络上的两台主机互相进行通信时,该网络的 M T U是非常重要的。但是如果 两台主机之间的通信要通过多个网络,那么每个网络的链路层就可能有不同的 M T U。重要的 不是两台主机所在网络的 M T U的值,重要的是两台通信主机路径中的最小 M T U。它被称作路 径M T U。 两台主机之间的路径 M T U不一定是个常数。它取决于当时所选择的路由。而选路不一定 是对称的(从A到B的路由可能与从B到A的路由不同),因此路径M T U在两个方向上不一定是 一致的。 RFC 1191[Mogul and Deering 1990]描述了路径M T U的发现机制,即在任何时候确定路径 M T U的方法。我们在介绍了 I C M P和I P分片方法以后再来看它是如何操作的。在 11 . 6节中,我 们将看到I C M P的不可到达错误就采用这种发现方法。在 11 . 7节中,还会看到,t r a c e r o u t e程序 也是用这个方法来确定到达目的节点的路径 M T U。在11 . 8节和2 4 . 2节,将介绍当产品支持路 径M T U的发现方法时,U D P和T C P是如何进行操作的。 2.10 串行线路吞吐量计算 如果线路速率是9600 b/s,而一个字节有8 bit,加上一个起始比特和一个停止比特,那么 线路的速率就是960 B/s(字节/秒)。以这个速率传输一个1 0 2 4字节的分组需要1066 ms。如果 第2章 链 路 层使用21 图2-5 几种常见的最大传输单元(MTU) 超通道 以太网 网 络 MTU字节 点对点(低时延) s令牌环(IBM) s令牌环(IEEE 802.5)用S L I P链接运行一个交互式应用程序,同时还运行另一个应用程序如 F T P发送或接收1 0 2 4字 节的数据,那么一般来说就必须等待一半的时间( 533 ms)才能把交互式应用程序的分组数 据发送出去。 假定交互分组数据可以在其他“大块”分组数据发送之前被发送出去。大多数的 S L I P实 现确实提供这类服务排队方法,把交互数据放在大块的数据前面。交互通信一般有 Te l n e t、 R l o g i n以及F T P的控制部分(用户的命令,而不是数据)。 这种服务排队方法是不完善的。它不能影响已经进入下游(如串行驱动程序)队 列的非交互数据。同时,新型的调制解调器具有很大的缓冲区,因此非交互数据可能 已经进入该缓冲区了。 对于交互应用来说,等待 533 ms是不能接受的。关于人的有关研究表明,交互响应时间 超过1 0 0~200 ms就被认为是不好的 [Jacobson 1990a]。这是发送一份交互报文出去后,直到 接收到响应信息(通常是出现一个回显字符)为止的往返时间。 把S L I P的M T U缩短到2 5 6就意味着链路传输一帧最长需要 266 ms,它的一半是 133 ms (这是一般需要等待的时间)。这样情况会好一些,但仍然不完美。我们选择它的原因(与 6 4 或1 2 8相比)是因为大块数据提供良好的线路利用率(如大文件传输)。假设C S L I P的报文首 部是5个字节,数据帧总长为 2 6 1个字节,2 5 6个字节的数据使线路的利用率为 9 8 . 1 %,帧头占 了1 . 9 %,这样的利用率是很不错的。如果把 M T U降到2 5 6以下,那么将降低传输大块数据的 最大吞吐量。 在图2 - 5列出的M T U值中,点对点链路的M T U是2 9 6个字节。假设数据为2 5 6字节,T C P和 I P首部占4 0个字节。由于M T U是I P向链路层查询的结果,因此该值必须包括通常的 T C P和I P 首部。这样就会导致I P如何进行分片的决策。I P对于C S L I P的压缩情况一无所知。 我们对平均等待时间的计算(传输最大数据帧所需时间的一半)只适用于 S L I P链路(或 P P P链路)在交互通信和大块数据传输这两种情况下。当只有交互通信时,如果线路速率是 9600 b/s,那么任何方向上的 1字节数据(假设有 5个字节的压缩帧头)往返一次都大约需要 12.5 ms。它比前面提到的100~200 ms要小得多。需要注意的是,由于帧头从 4 0个字节压缩到 5个字节,使得1字节数据往返时间从85 ms 减到12.5 ms。 不幸的是,当使用新型的纠错和压缩调制解调器时,这样的计算就更难了。这些调制解 调器所采用的压缩方法使得在线路上传输的字节数大大减少,但纠错机制又会增加传输的时 间。不过,这些计算是我们进行合理决策的入口点。 在后面的章节中,我们将用这些串行线路吞吐量的计算来验证数据从串行线路上通过的 时间。 2.11 小结 本章讨论了 I n t e r n e t协议族中的最底层协议,链路层协议。我们比较了以太网和 I E E E 8 0 2 . 2 / 8 0 2 . 3的封装格式,以及 S L I P和P P P的封装格式。由于 S L I P和P P P经常用于低速的链路, 二者都提供了压缩不常变化的公共字段的方法。这使交互性能得到提高。 大多数的实现都提供环回接口。访问这个接口可以通过特殊的环回地址,一般为 1 2 7 . 0 . 0 . 1。也可以通过发送I P数据报给主机所拥有的任一 I P地址。当环回数据回到上层的协议 栈中时,它已经过传输层和 I P层完整的处理过程。 22使用TCP/IP详解,卷1:协议我们描述了很多链路都具有的一个重要特性, M T U,相关的一个概念是路径 M T U。根据 典型的串行线路M T U,对S L I P和C S L I P链路的传输时延进行了计算。 本章的内容只覆盖了当今 T C P / I P所采用的部分数据链路公共技术。 T C P / I P成功的原因之 一是它几乎能在任何数据链路技术上运行。 习题 2.1 如果你的系统支持 n e t s t a t( 1 )命令(参见 3 . 9节),那么请用它确定系统上的接口及其 M T U。 第2章 链 路 层使用23第3章 IP:网际协议 3.1 引言 I P是T C P / I P协议族中最为核心的协议。所有的 T C P、U D P、I C M P及I G M P数据都以I P数据 报格式传输(见图 1 - 4)。许多刚开始接触 T C P / I P的人对I P提供不可靠、无连接的数据报传送 服务感到很奇怪,特别是那些具有 X . 2 5或S N A背景知识的人。 不可靠(u n r e l i a b l e)的意思是它不能保证 I P数据报能成功地到达目的地。 I P仅提供最好 的传输服务。如果发生某种错误时,如某个路由器暂时用完了缓冲区, I P有一个简单的错误 处理算法:丢弃该数据报,然后发送 I C M P消息报给信源端。任何要求的可靠性必须由上层来 提供(如T C P)。 无连接(c o n n e c t i o n l e s s)这个术语的意思是 I P并不维护任何关于后续数据报的状态信息。 每个数据报的处理是相互独立的。这也说明, I P数据报可以不按发送顺序接收。如果一信源 向相同的信宿发送两个连续的数据报(先是 A,然后是B),每个数据报都是独立地进行路由 选择,可能选择不同的路线,因此 B可能在A到达之前先到达。 在本章,我们将简要介绍 I P首部中的各个字段,讨论 I P路由选择和子网的有关内容。还 要介绍两个有用的命令: i f c o n f i g和n e t s t a t。关于I P首部中一些字段的细节,将留在以 后使用这些字段的时候再进行讨论。 RFC 791[Postel 1981a]是I P的正式规范文件。 3.2 IP首部 I P数据报的格式如图3 - 1所示。普通的I P首部长为2 0个字节,除非含有选项字段。 图3-1 IP数据报格式及首部中的各字段 4位 版本 4位首部 长度 8位服务类型 (TOS) 16位总长度(字节数) 13位片偏移 16位首部检验和 3位 标志16位标识 8位协议 32位源IP地址 32位目的IP地址 选项(如果有) 数 据 8位生存时间 20字节分析图3 - 1中的首部。最高位在左边,记为 0 bit;最低位在右边,记为31 bit。 4个字节的32 bit值以下面的次序传输:首先是 0~7 bit,其次8~15 bit,然后1 6~23 bit, 最后是24~31 bit。这种传输次序称作big endian字节序。由于T C P / I P首部中所有的二进制整数 在网络中传输时都要求以这种次序,因此它又称作网络字节序。以其他形式存储二进制整数 的机器,如little endian格式,则必须在传输数据之前把首部转换成网络字节序。 目前的协议版本号是4,因此I P有时也称作I P v 4。3 . 1 0节将对一种新版的I P协议进行讨论。 首部长度指的是首部占 32 bit字的数目,包括任何选项。由于它是一个 4比特字段,因此 首部最长为6 0个字节。在第8章中,我们将看到这种限制使某些选项如路由记录选项在当今已 没有什么用处。普通I P数据报(没有任何选择项)字段的值是 5。 服务类型(TO S)字段包括一个3 bit的优先权子字段(现在已被忽略),4 bit的TO S子字 段和1 bit未用位但必须置0。4 bit的TO S分别代表:最小时延、最大吞吐量、最高可靠性和最 小费用。4 bit中只能置其中1 bit。如果所有4 bit均为0,那么就意味着是一般服务。 RFC 1340 [Reynolds and Postel 1992]描述了所有的标准应用如何设置这些服务类型。 RFC 1349 [Almquist 1992]对该R F C进行了修正,更为详细地描述了 TO S的特性。 图3 - 2列出了对不同应用建议的 TO S值。在最后一列中给出的是十六进制值,因为这就是 在后面将要看到的t c p d u m p命令输出。 图3-2 服务类型字段推荐值 Te l n e t和R l o g i n这两个交互应用要求最小的传输时延,因为人们主要用它们来传输少量的 交互数据。另一方面, F T P文件传输则要求有最大的吞吐量。最高可靠性被指明给网络管理 (S N M P)和路由选择协议。用户网络新闻( Usenet news, NNTP)是唯一要求最小费用的应 用。 现在大多数的T C P / I P实现都不支持TO S特性,但是自4.3BSD Reno以后的新版系统都对它 进行了设置。另外,新的路由协议如 O S P F和I S - I S都能根据这些字段的值进行路由决策。 在2 . 1 0节中,我们提到S L I P一般提供基于服务类型的排队方法,允许对交互通信 第3章 IP:网际协议使用25 应 用 程 序 最小时延 最大吞吐量 最高可靠性 最小费用 16进 制值 控制 数据 任意块数据 命令阶段 数据阶段 UDP查询 TCP查询 区域传输 差错 查询 任何IGP数据在处理大块数据之前进行处理。由于大多数的实现都不使用 TO S字段,因此这种 排队机制由S L I P自己来判断和处理,驱动程序先查看协议字段(确定是否是一个 T C P 段),然后检查T C P信源和信宿的端口号,以判断是否是一个交互服务。一个驱动程序 的注释这样认为,这种“令人厌恶的处理方法”是必需的,因为大多数实现都不允许 应用程序设置TOS字段。 总长度字段是指整个 I P数据报的长度,以字节为单位。利用首部长度字段和总长度字段, 就可以知道I P数据报中数据内容的起始位置和长度。由于该字段长 1 6比特,所以I P数据报最 长可达6 5 5 3 5字节(回忆图 2 - 5,超级通道的 M T U为6 5 5 3 5。它的意思其实不是一个真正的 M T U— 它使用了最长的I P数据报)。当数据报被分片时,该字段的值也随着变化,这一点将 在11 . 5节中进一步描述。 尽管可以传送一个长达 6 5 5 3 5字节的I P数据报,但是大多数的链路层都会对它进行分片。 而且,主机也要求不能接收超过 5 7 6字节的数据报。由于 T C P把用户数据分成若干片,因此一 般来说这个限制不会影响 T C P。在后面的章节中将遇到大量使用 U D P的应用( R I P,T F T P, B O O T P,D N S,以及S N M P),它们都限制用户数据报长度为 5 1 2字节,小于5 7 6字节。但是, 事实上现在大多数的实现(特别是那些支持网络文件系统 N F S的实现)允许超过 8 1 9 2字节的 I P数据报。 总长度字段是 I P首部中必要的内容,因为一些数据链路(如以太网)需要填充一些数据 以达到最小长度。尽管以太网的最小帧长为 4 6字节(见图2 - 1),但是I P数据可能会更短。如 果没有总长度字段,那么I P层就不知道4 6字节中有多少是I P数据报的内容。 标识字段唯一地标识主机发送的每一份数据报。通常每发送一份报文它的值就会加 1。在 11 . 5节介绍分片和重组时再详细讨论它。同样,在讨论分片时再来分析标志字段和片偏移字 段。 RFC 791 [Postel 1981a]认为标识字段应该由让IP发送数据报的上层来选择。假设有 两个连续的I P数据报,其中一个是由T C P生成的,而另一个是由U D P生成的,那么它们 可能具有相同的标识字段。尽管这也可以照常工作(由重组算法来处理),但是在大多 数从伯克利派生出来的系统中,每发送一个I P数据报,I P层都要把一个内核变量的值加 1,不管交给IP的数据来自哪一层。内核变量的初始值根据系统引导时的时间来设置。 T T L(t i m e - t o - l i v e)生存时间字段设置了数据报可以经过的最多路由器数。它指定了数据 报的生存时间。T T L的初始值由源主机设置(通常为 3 2或6 4),一旦经过一个处理它的路由器, 它的值就减去 1。当该字段的值为 0时,数据报就被丢弃,并发送 I C M P报文通知源主机。第 8 章我们讨论Tr a c e r o u t e程序时将再回来讨论该字段。 我们已经在第 1章讨论了协议字段,并在图 1 - 8中示出了它如何被 I P用来对数据报进行分 用。根据它可以识别是哪个协议向 I P传送数据。 首部检验和字段是根据I P首部计算的检验和码。它不对首部后面的数据进行计算。 I C M P、 I G M P、U D P和T C P在它们各自的首部中均含有同时覆盖首部和数据检验和码。 为了计算一份数据报的 I P检验和,首先把检验和字段置为 0。然后,对首部中每个 16 bit 进行二进制反码求和(整个首部看成是由一串 16 bit的字组成),结果存在检验和字段中。当 收到一份I P数据报后,同样对首部中每个 16 bit进行二进制反码的求和。由于接收方在计算过 26使用TCP/IP详解,卷1:协议程中包含了发送方存在首部中的检验和,因此,如果首部在传输过程中没有发生任何差错, 那么接收方计算的结果应该为全 1。如果结果不是全1(即检验和错误),那么I P就丢弃收到的 数据报。但是不生成差错报文,由上层去发现丢失的数据报并进行重传。 I C M P、I G M P、U D P和T C P都采用相同的检验和算法,尽管 T C P和U D P除了本身的首部和 数据外,在I P首部中还包含不同的字段。在 RFC 1071[Braden, Borman and Patridge 1988]中有 关于如何计算I n t e r n e t检验和的实现技术。由于路由器经常只修改 T T L字段(减1),因此当路 由器转发一份报文时可以增加它的检验和,而不需要对 I P整个首部进行重新计算。 R F C 1141[Mallory and Kullberg 1990]为此给出了一个很有效的方法。 但是,标准的BSD实现在转发数据报时并不是采用这种增加的办法。 每一份I P数据报都包含源 I P地址和目的 I P地址。我们在 1 . 4节中说过,它们都是 32 bit的 值。 最后一个字段是任选项,是数据报中的一个可变长的可选信息。目前,这些任选项定义 如下: • 安全和处理限制(用于军事领域,详细内容参见 RFC 1108[Kent 1991]) • 记录路径(让每个路由器都记下它的 I P地址,见7 . 3节) • 时间戳(让每个路由器都记下它的 I P地址和时间,见7 . 4节) • 宽松的源站选路(为数据报指定一系列必须经过的 I P地址,见8 . 5节) • 严格的源站选路(与宽松的源站选路类似,但是要求只能经过指定的这些地址,不能 经过其他的地址)。 这些选项很少被使用,并非所有的主机和路由器都支持这些选项。 选项字段一直都是以 32 bit作为界限,在必要的时候插入值为 0的填充字节。这样就保证 I P首部始终是32 bit的整数倍(这是首部长度字段所要求的)。 3.3 IP路由选择 从概念上说, I P路由选择是简单的,特别对于主机来说。如果目的主机与源主机直接相 连(如点对点链路)或都在一个共享网络上(以太网或令牌环网),那么I P数据报就直接送到 目的主机上。否则,主机把数据报发往一默认的路由器上,由路由器来转发该数据报。大多 数的主机都是采用这种简单机制。 在本节和第9章中,我们将讨论更一般的情况,即 I P层既可以配置成路由器的功能,也可 以配置成主机的功能。当今的大多数多用户系统,包括几乎所有的 U n i x系统,都可以配置成 一个路由器。我们可以为它指定主机和路由器都可以使用的简单路由算法。本质上的区别在 于主机从不把数据报从一个接口转发到另一个接口,而路由器则要转发数据报。内含路由器 功能的主机应该从不转发数据报,除非它被设置成那样。在 9 . 4小节中,我们将进一步讨论配 置的有关问题。 在一般的体制中,I P可以从T C P、U D P、I C M P和I G M P接收数据报(即在本地生成的数据 报)并进行发送,或者从一个网络接口接收数据报(待转发的数据报)并进行发送。 I P层在 内存中有一个路由表。当收到一份数据报并进行发送时,它都要对该表搜索一次。当数据报 来自某个网络接口时,I P首先检查目的I P地址是否为本机的I P地址之一或者I P广播地址。如果 确实是这样,数据报就被送到由 I P首部协议字段所指定的协议模块进行处理。如果数据报的 第3章 IP:网际协议使用27目的不是这些地址,那么( 1)如果I P层被设置为路由器的功能,那么就对数据报进行转发 (也就是说,像下面对待发出的数据报一样处理);否则( 2)数据报被丢弃。 路由表中的每一项都包含下面这些信息: • 目的I P地址。它既可以是一个完整的主机地址,也可以是一个网络地址,由该表目中的标 志字段来指定(如下所述)。主机地址有一个非0的主机号(见图1 - 5),以指定某一特定的 主机,而网络地址中的主机号为0,以指定网络中的所有主机(如以太网,令牌环网)。 • 下一站(或下一跳)路由器( next-hop router)的I P地址,或者有直接连接的网络 I P地 址。下一站路由器是指一个在直接相连网络上的路由器,通过它可以转发数据报。下 一站路由器不是最终的目的,但是它可以把传送给它的数据报转发到最终目的。 • 标志。其中一个标志指明目的 I P地址是网络地址还是主机地址,另一个标志指明下一 站路由器是否为真正的下一站路由器,还是一个直接相连的接口(我们将在 9 . 2节中 详细介绍这些标志)。 • 为数据报的传输指定一个网络接口。 I P路由选择是逐跳地(h o p - b y - h o p)进行的。从这个路由表信息可以看出, I P并不知道到 达任何目的的完整路径(当然,除了那些与主机直接相连的目的)。所有的I P路由选择只为数 据报传输提供下一站路由器的 I P地址。它假定下一站路由器比发送数据报的主机更接近目的, 而且下一站路由器与该主机是直接相连的。 I P路由选择主要完成以下这些功能: 1) 搜索路由表,寻找能与目的 I P地址完全匹配的表目(网络号和主机号都要匹配)。如果 找到,则把报文发送给该表目指定的下一站路由器或直接连接的网络接口(取决于标 志字段的值)。 2) 搜索路由表,寻找能与目的网络号相匹配的表目。如果找到,则把报文发送给该表目 指定的下一站路由器或直接连接的网络接口(取决于标志字段的值)。目的网络上的所 有主机都可以通过这个表目来处置。例如,一个以太网上的所有主机都是通过这种表 目进行寻径的。 这种搜索网络的匹配方法必须考虑可能的子网掩码。关于这一点我们在下一节中进行 讨论。 3) 搜索路由表,寻找标为“默认( d e f a u l t)”的表目。如果找到,则把报文发送给该表目 指定的下一站路由器。 如果上面这些步骤都没有成功,那么该数据报就不能被传送。如果不能传送的数据报来自 本机,那么一般会向生成数据报的应用程序返回一个“主机不可达”或“网络不可达”的错误。 完整主机地址匹配在网络号匹配之前执行。只有当它们都失败后才选择默认路由。默认 路由,以及下一站路由器发送的 I C M P间接报文(如果我们为数据报选择了错误的默认路由), 是I P路由选择机制中功能强大的特性。我们在第 9章对它们进行讨论。 为一个网络指定一个路由器,而不必为每个主机指定一个路由器,这是 I P路由选择机制 的另一个基本特性。这样做可以极大地缩小路由表的规模,比如 I n t e r n e t上的路由器有只有几 千个表目,而不会是超过1 0 0万个表目。 举例 首先考虑一个简单的例子:我们的主机 b s d i有一个I P数据报要发送给主机 s u n。双方都在 28使用TCP/IP详解,卷1:协议同一个以太网上(参见扉页前图)。数据报的传输过程如图3 - 3所示。 当I P从某个上层收到这份数据报后,它搜索路由表,发现目的 I P地址(1 4 0 . 2 5 2 . 1 3 . 3 3)在 一个直接相连的网络上(以太网 1 4 0 . 2 5 2 . 1 3 . 0)。于是,在表中找到匹配网络地址(在下一节 中,我们将看到,由于以太网的子网掩码的存在,实际的网络地址是 1 4 0 . 2 5 2 . 1 3 . 3 2,但是这 并不影响这里所讨论的路由选择)。 数据报被送到以太网驱动程序,然后 作为一个以太网数据帧被送到 s u n主机上 (见图 2 - 1)。I P数据报中的目的地址是 s u n的I P地址(1 4 0 . 2 5 2 . 1 3 . 3 3),而在链 路层首部中的目的地址是 48 bit的s u n主 机的以太网接口地址。这个 48 bit的以太 网地址是用 A R P协议获得的,我们将在 下一章对此进行描述。 现在来看另一个例子:主机 b s d i有一份I P数据报要传到f t p . u u . n e t主机上,它的I P地 址是1 9 2 . 4 8 . 9 6 . 9。经过的前三个路由器如图 3 - 4所示。首先,主机b s d i搜索路由表,但是没有 找到与主机地址或网络地址相匹配的表目,因此只能用默认的表目,把数据报传给下一站路 由器,即主机s u n。当数据报从b s d i被传到s u n主机上以后,目的 I P地址是最终的信宿机地 址(1 9 2 . 4 8 . 9 6 . 9),但是链路层地址却是s u n主机的以太网接口地址。这与图 3 - 3不同,在那里 数据报中的目的I P地址和目的链路层地址都指的是相同的主机( s u n)。 图3-4 从b s d i 到f t p . u u . n e t (192.48.96.9)的初始路径 第3章 IP:网际协议使用29 图3-3 数据报从主机bsdi到sun的传送过程 目的网络= 140.252,13,0 以太网140.252.13 链路层 首部 目的 目的 IP首 部 下一站= 140.252.104.2 (默认) 下一站= 140.252.13.33 (默认) 链路层 首部 IP 首部 链路层 首部 IP 首部 目的以太网=以太网的140.252.1.4 目的IP=192.48.96.9 下一站= 140.252.1.4 (默认) 下一站= 140.252.1.183 (默认) IP 首部 目的IP=192.48.96.9 目的IP=192.48.96.9 目的以太网=以太网的140.252.13.33 以太网,140.252.13 以太网,140.252.1 调制解 调器 调制解 调器当s u n收到数据报后,它发现数据报的目的 I P地址并不是本机的任一地址,而 s u n已被设 置成具有路由器的功能,因此它把数据报进行转发。经过搜索路由表,选用了默认表目。根 据s u n的默认表目,它把数据报转发到下一站路由器 n e t b,该路由器的地址是1 4 0 . 2 5 2 . 1 . 1 8 3。 数据报是经过点对点 S L I P链路被传送的,采用了图 2 - 2所示的最小封装格式。这里,我们没有 给出像以太网链路层数据帧那样的首部,因为在 S L I P链路中没有那样的首部。 当n e t b收到数据报后,它执行与s u n主机相同的步骤:数据报的目的地址不是本机地址, 而n e t b也被设置成具有路由器的功能,于是它也对该数据报进行转发。采用的也是默认路由 表目,把数据报送到下一站路由器 g a t e w a y(1 4 0 . 2 5 2 . 1 . 4)。位于以太网1 4 0 . 2 5 2 . 1上的主机 n e t b用A R P获得对应于1 4 0 . 2 5 2 . 1 . 4的48 bit以太网地址。这个以太网地址就是链路层数据帧头 上的目的地址。 路由器g a t e w a y也执行与前面两个路由器相同的步骤。它的默认路由表目所指定的下一 站路由器 I P地址是1 4 0 . 2 5 2 . 1 0 4 . 2(我们将在图 8 - 4中证实,使用 Tr a c e r o u t e程序时,它就是 g a t e w a y使用的下一站路由器)。 对于这个例子需要指出一些关键点: 1) 该例子中的所有主机和路由器都使用了默认路由。事实上,大多数主机和一些路由器 可以用默认路由来处理任何目的,除非它在本地局域网上。 2) 数据报中的目的I P地址始终不发生任何变化(在 8 . 5节中,我们将看到,只有使用源路 由选项时,目的I P地址才有可能被修改,但这种情况很少出现)。所有的路由选择决策都是基 于这个目的I P地址。 3) 每个链路层可能具有不同的数据帧首部,而且链路层的目的地址(如果有的话)始终 指的是下一站的链路层地址。在例子中,两个以太网封装了含有下一站以太网地址的链路层 首部,但是S L I P链路没有这样做。以太网地址一般通过 A R P获得。 在第9章,我们在描述了 I C M P之后将再次讨论 I P路由选择问题。我们将看到一些路由表 的例子,以及如何用它们来进行路由决策的。 3.4 子网寻址 现在所有的主机都要求支持子网编址( RFC 950 [Mogul and Postel 1985])。不是把I P地址 看成由单纯的一个网络号和一个主机号组成,而是把主机号再分成一个子网号和一个主机号。 这样做的原因是因为 A类和B类地址为主机号分配了太多的空间,可分别容纳的主机数为 22 4-2和21 6-2。事实上,在一个网络中人们并不安排这么多的主机(各类 I P地址的格式如图1 - 5 所示)。由于全0或全1的主机号都是无效的,因此我们把总数减去 2。 在I n t e r N I C获得某类I P网络号后,就由当地的系统管理员来进行分配,由他(或她)来决 定是否建立子网,以及分配多少比特给子网号和主机号。例如,这里有一个 B类网络地址 (1 4 0 . 2 5 2),在剩下的16 bit中,8 bit用于子网号,8 bit用于主机号,格式如图 3 - 5所示。这样 就允许有2 5 4个子网,每个子网可以有2 5 4台主机。 图3-5 B类地址的一种子网编址 30使用TCP/IP详解,卷1:协议 B类 16位 8位 8位 主机号子网号网络号=140.252许多管理员采用自然的划分方法,即把 B类地址中留给主机的 16 bit中的前8 bit作为子网 地址,后8 b i t作为主机号。这样用点分十进制方法表示的 I P地址就可以比较容易确定子网号。 但是,并不要求A类或B类地址的子网划分都要以字节为划分界限。 大多数的子网例子都是 B类地址。其实,子网还可用于 C类地址,只是它可用的比特数较 少而已。很少出现 A类地址的子网例子是因为 A类地址本身就很少(但是,大多数 A类地址都 是进行子网划分的)。 子网对外部路由器来说隐藏了内部网络组织(一个校园或公司内部)的细节。在我们的 网络例子中,所有的I P地址都有一个B类网络号1 4 0 . 2 5 2。但是其中有超过3 0个子网,多于4 0 0 台主机分布在这些子网中。由一台路由器提供了 I n t e r n e t的接入,如图3 - 6所示。 在这个图中,我们把大多数的路由器编号为 Rn,n是子网号。我们给出了连接这些子网的 路由器,同时还包括了扉页前图中的九个系统。在图中,以太网用粗线表示,点对点链路用 虚线表示。我们没有画出不同子网中的所有主机。例如,在子网 1 4 0 . 2 5 2 . 3上,就超过5 0台主 机,而在子网1 4 0 . 2 5 2 . 1上则超过1 0 0台主机。 与3 0个C类地址相比,用一个包含 3 0个子网的B类地址的好处是,它可以缩小 I n t e r n e t路由 表的规模。B类地址1 4 0 . 2 5 2被划分为若干子网的事实对于所有子网以外的 I n t e r n e t路由器都是 透明的。为了到达 I P地址开始部分为 1 4 0 . 2 5 2的主机,外部路由器只需要知道通往 I P地址 1 4 0 . 2 5 2 . 1 0 4 . 1的路径。这就是说,对于网络 1 4 0 . 2 5 2只需一个路由表目,而如果采用 3 0个C类 地址,则需要 3 0个路由表目。因此,子网划分缩减了路由表的规模(在 1 0 . 8小节中,我们将 介绍一种新技术,即使用C类地址也可以缩减路由表的规模)。 子网对于子网内部的路由器是不透明的。如图 3 - 6所示,一份来自 I n t e r n e t的数据报到达 g a t e w a y,它的目的地址是 1 4 0 . 2 5 2 . 5 7 . 1。路由器g a t e w a y需要知道子网号是 5 7,然后把它 送到k p n o。同样,k p n o必须把数据报送到R 5 5,最后由R 5 5把它送到R 5 7。 图3-6 网络noao.edu(140.252)中的大多数子网安排 第3章 IP:网际协议使用313.5 子网掩码 任何主机在引导时进行的部分配置是指定主机 I P地址。大多数系统把 I P地址存在一个磁 盘文件里供引导时读用。在第 5章我们将讨论一个无盘系统如何在引导时获得 I P地址。 除了I P地址以外,主机还需要知道有多少比特用于子网号及多少比特用于主机号。这是 在引导过程中通过子网掩码来确定的。这个掩码是一个 32 bit的值,其中值为 1的比特留给网 络号和子网号,为0的比特留给主机号。图 3 - 7是一个B类地址的两种不同的子网掩码格式。第 一个例子是n o a o . e d u网络采用的子网划分方法,如图 3 - 5所示,子网号和主机号都是 8 bit宽。 第二个例子是一个B类地址划分成10 bit的子网号和6 bit的主机号。 图3-7 两种不同的B类地址子网掩码的例子 尽管I P地址一般以点分十进制方法表示,但是子网掩码却经常用十六进制来表示,特别 是当界限不是一个字节时,因为子网掩码是一个比特掩码。 给定I P地址和子网掩码以后,主机就可以确定 I P数据报的目的是:( 1)本子网上的主机; (2)本网络中其他子网中的主机;( 3)其他网络上的主机。如果知道本机的 I P地址,那么就知道 它是否为A类、B类或C类地址(从I P地址的高位可以得知),也就知道网络号和子网号之间的分 界线。而根据子网掩码就可知道子网号与主机号之间的分界线。 举例 假设我们的主机地址是 1 4 0 . 2 5 2 . 1 . 1(一个B类地址),而子网掩码为2 5 5 . 2 5 5 . 2 5 5 . 0(其中8 b i t为子网号,8 bit为主机号)。 • 如果目的I P地址是1 4 0 . 2 5 2 . 4 . 5,那么我们就知道 B类网络号是相同的( 1 4 0 . 2 5 2),但是 子网号是不同的(1和4)。用子网掩码在两个I P地址之间的比较如图3 - 8所示。 • 如果目的I P地址是1 4 0 . 2 5 2 . 1 . 2 2,那么B类网络号还是一样的( 1 4 0 . 2 5 2),而且子网号也 是一样的(1),但是主机号是不同的。 • 如果目的I P地址是1 9 2 . 4 3 . 2 3 5 . 6(一个C类地址),那么网络号是不同的,因而进一步的 比较就不用再进行了。 图3-8 使用子网掩码的两个B类地址之间的比较 32使用TCP/IP详解,卷1:协议 16位 8位 8位 8位10位16位 B类 子网掩码 子网掩码 B类 网络号 网络号 子网号 主机号 主机号子网号 B类网络号末尾 指明的子网号末尾 8位8位16位 网络号相符 子网号不相等 B类 B类 子网掩码给定两个I P地址和子网掩码后,I P路由选择功能一直进行这样的比较。 3.6 特殊情况的IP地址 经过子网划分的描述,现在介绍 7个特殊的I P地址,如图3 - 9所示。在这个图中, 0表示所 有的比特位全为0;- 1表示所有的比特位全为 1;n e t i d、s u b n e t i d和h o s t i d分别表示不为全0或全 1的对应字段。子网号栏为空表示该地址没有进行子网划分。 图3-9 特殊情况的IP地址 我们把这个表分成三个部分。表的头两项是特殊的源地址,中间项是特殊的环回地址, 最后四项是广播地址。 表中的头两项,网络号为0,如主机使用B O O T P协议确定本机I P地址时只能作为初始化过 程中的源地址出现。 在1 2 . 2节中,我们将进一步分析四类广播地址。 3.7 一个子网的例子 这个例子是本文中采用的子网,以及如何使用两个不同的子网掩码。具体安排如图 3 - 1 0 所示。 图3-10 作者所在子网中的主机和网络安排 如果把该图与扉页前图相比,就会发现在图 3 - 1 0中省略了从路由器 s u n到上面的以太网之 间的连接细节,实际上它们之间的连接是拨号 S L I P。这个细节不影响本节中讨论的子网划分 第3章 IP:网际协议使用33 IP 地 址 可 以 为 描 述网络号 子网号 主机号 源 端 目的端 0 0 O K 不可能 网络上的主机(参见下面的限制) 0 主机号 O K 不可能 网络上的特定主机(参见下面的限制) 1 2 7 任何值 O K O K 环回地址(2 . 7节) -1 -1 不可能 O K 受限的广播(永远不被转发) n e t i d -1 不可能 O K 以网络为目的向n e t i d广播 n e t i d s u b n e t i d -1 不可能 O K 以子网为目的向n e t i d、s u b n e t i d广播 n e t i d -1 -1 不可能 O K 以所有子网为目的向n e t i d广播 以太网,子网140.252.1 以太网,子网140.252.13.32 作者所在子网140.252.13 SLIP子网问题。我们在4 . 6节讨论A R P代理时将再回头讨论这个细节。 问题是我们在子网 1 3中有两个分离的网络:一个以太网和一个点对点链路(硬件连接的 S L I P链路)(点对点链接始终会带来问题,因为它一般在两端都需要 I P地址)。将来或许会有 更多的主机和网络,但是为了不让主机跨越不同的网络就得使用不同的子网号。我们的解决 方法是把子网号从 8 bit扩充到11 b i t,把主机号从 8 bit减为5 bit。这就叫作变长子网,因为 1 4 0 . 2 5 2网络中的大多数子网都采用 8 bit 子网掩码,而我们的子网却采用 11 bit的子网掩码。 RFC 1009[Braden and Postel 1987]允许一个含有子网的网络使用多个子网掩码。新 的路由器需求RFC[Almquist 1993]则要求支持这一功能。 但是,问题在于并不是所有的路由选择协议在交换目的网络时也交换子网掩码。 在第1 0章中,我们将看到R I P不支持变长子网,R I P第2版和O S P F则支持变长子网。在 我们的例子中不存在这种问题,因为在我的子网中不要求使用RIP协议。 作者子网中的I P地址结构如图3 - 11所示,11位子网号中的前8 bit始终是1 3。在剩下的3 bit 中,我们用二进制0 0 1表示以太网,0 1 0表示点对点S L I P链路。这个变长子网掩码在 1 4 0 . 2 5 2网 络中不会给其他主机和路由器带来问题— 只要目的是子网1 4 0 . 2 5 2 . 1 3的所有数据报都传给路 由器s u n(I P地址是1 4 0 . 2 5 2 . 1 . 2 9),如图3 - 11所示。如果s u n知道子网1 3中的主机有11 bit子 网号,那么一切都好办了。 图3-11 变长子网 1 4 0 . 2 5 2 . 1 3子网中的所有接口的子网掩码是 2 5 5 . 2 5 5 . 2 5 5 . 2 2 4,或0 x ffffff e 0。这表明最右边 的5 bit 留给主机号,左边的27 bit留给网络号和子网号。 图3 - 1 0中所有接口的I P地址和子网掩码的分配情况如图 3 - 1 2所示。 图3-12 作者子网的IP地址 第1栏标为是“主机”,但是s u n和b s d i也具有路由器的功能,因为它们是多接口的,可 以把分组数据从一个接口转发到另一个接口。 这个表中的最后一行是图 3 - 1 0中的广播地址 1 4 0 . 2 5 2 . 1 3 . 6 3:它是根据以太网子网号 (1 4 0 . 2 5 2 . 1 3 . 3 2)和图3 - 11中的低5位置1(1 6+8+4+2+1=3 1)得来的(我们在第 1 2章中将 看到,这个地址被称作以子网为目的的广播地址( subnet-directed broadcast address))。 34使用TCP/IP详解,卷1:协议 8位=13 11位16位 B类 子网掩码 5位 子网号ID网络号=140.252 主机号ID 主机 IP地址 子网掩码 网络号 子网号 主机号 注 释 在子网1上 在作者所在子网上 在以太网上 点对点 点对点 以太网上的广播地址3.8 ifconfig命令 到目前为止,我们已经讨论了链路层和 I P层,现在可以介绍 T C P / I P对网络接口进行配置 和查询的命令了。i f c o n f i g( 8 )命令一般在引导时运行,以配置主机上的每个接口。 由于拨号接口可能会经常接通和挂断(如 S L I P 链路),每次线路接通和挂断时, i f c o n f i g都必须(以某种方法)运行。这个过程如何完成取决于使用的 S L I P软件。 下面是作者子网接口的有关参数。请把它们与图 3 - 1 2的值进行比较。 环回接口(2 . 7节)被认为是一个网络接口。它是一个 A类地址,没有进行子网划分。 需要注意的是以太网没有采用尾部封装( 2 . 3节),而且可以进行广播,而 S L I P链路是一 个点对点的链接。 S L I P接口的标志L I N K 0是一个允许压缩s l i p的数据(C S L I P,参见2 . 5节)的配置选项。其 他的选项有L I N K 1(如果从另一端收到一份压缩报文,就允许采用 C S L I P)和L I N K 2(所有 外出的I C M P报文都被丢弃)。我们在4 . 6节中将讨论S L I P链接的目的地址。 安装指南中的注释对最后这个选项进行了解释:“一般它不应设置,但是由于一些 不当的ping操作,可能会导致吞吐量降到0。” b s d i是另一台路由器。由于- a参数是S u n O S操作系统具有的功能,因此我们必须多次执 行i f c o n f i g,并指定接口名字参数: 这里,我们看到以太网接口( w e 0)的一个新选项: S I M P L E X。这个4 . 4 B S D标志表明接 口不能收到本机传送的数据。在 B S D / 3 8 6中所有的以太网都这样设置。一旦这样设置后,如 果接口发送一帧数据到广播地址,那么就会为本机拷贝一份数据送到环回地址(在 6 . 3小节我 们将举例说明这一点)。 在主机s l i p中,S L I P接口的设置基本上与上面的b s d i一致,只是两端的I P地址进行了互换: slip % /sbin/ifconfig sl0 sl0: flags=1011 inet 140.252.13.65 --> 140.252.13.66 netmask ffffffe0 最后一个接口是主机 s v r 4上的以太网接口。它与前面的以太网接口类似,只是 S V R 4版 的i f c o n f i g没有打印R U N N I N G标志: svr4 % /usr/sbin/ifconfig emd0 emd0: flags=23 inet 140.252.13.34 netmask ffffffe0 broadcast 140.252.13.63 第3章 IP:网际协议使用35 在所有接口报告的选项i f c o n f i g命令一般支持T C P / I P以外的其他协议族,而且有很多参数。关于这些细节可 以查看系统说明书。 3.9 netstat命令 n e t s t a t( 1 )命令也提供系统上的接口信息。 - i参数将打印出接口信息, - n参数则打印出 I P地址,而不是主机名字。 这个命令打印出每个接口的 M T U、输入分组数、输入错误、输出分组数、输出错误、冲 突以及当前的输出队列长度。 在第9章将用n e t s t a t命令检查路由表,那时再回头讨论该命令。另外,在第 1 3章将用 它的一个改进版本来查看活动的广播组。 3.10 IP的未来 I P主要存在三个方面的问题。这是 I n t e r n e t在过去几年快速增长所造成的结果(参见习题 1 . 2)。 1) 超过半数的B类地址已被分配。根据估计,它们大约在 1 9 9 5年耗尽。 2) 32 bit的I P地址从长期的I n t e r n e t增长角度来看,一般是不够用的。 3) 当前的路由结构没有层次结构,属于平面型 ( f l a t )结构,每个网络都需要一个路由表目。 随着网络数目的增长,一个具有多个网络的网站就必须分配多个 C类地址,而不是一个 B类地 址,因此路由表的规模会不断增长。 无类别的域间路由选择 C I D R(Classless Interdomain Routing)提出了一个可以解决第三 个问题的建议,对当前版本的 I P(I P版本4)进行扩充,以适应2 1世纪I n t e r n e t的发展。对此我 们将在1 0 . 8节进一步详细介绍。 对新版的I P,即下一代 I P,经常称作 I P n g,主要有四个方面的建议。 1 9 9 3年5月发行的 IEEE Network (vol.7, no.3)对前三个建议进行了综述,同时有一篇关于 C I D R的论文。R F C 1454 [Dixon 1993]对前三个建议进行了比较。 1) SIP,简单I n t e r n e t协议。它针对当前的I P提出了一个最小幅度的修改建议,采用 6 4位地 址和一个不同的首部格式(首部的前 4比特仍然包含协议的版本号,其值不再是 4)。 2) PIP。这个建议也采用了更大的、可变长度的和有层次结构的地址,而且首部格式也不 相同。 3) TUBA, 代 表“ TCP and UDP with Bigger Address”, 它基 于 OSI 的 C L N P (Connectionless Network Protocol,无连接网络协议),一个与I P类似的O S I协议。它提供大得 多的地址空间:可变长度,可达 2 0个字节。由于C L N P是一个现有的协议,而S I P和P I P只是建 议,因此关于C L N P的文档已经出现。RFC 1347[Callon 1992]提供了T U B A的有关细节。文献 [Perlman 1992]的第7章对I P v 4和C L N P进行了比较。许多路由器已经支持 C L N P,但是很少有 主机也提供支持。 36使用TCP/IP详解,卷1:协议4) TP/IX,由RFC 1475 [Ullmann 1993]对它进行了描述。虽然S I P采用了64 bit的址址,但 是它还改变了T C P和U D P的格式:两个协议均为 32 bit的端口号,64 bit的序列号,64 bit的确 认号,以及T C P的32 bit窗口。 前三个建议基本上采用了相同版本的 T C P和U D P作为传输层协议。 由于四个建议只能有一个被选为 I P v 4的替换者,而且在你读到此书时可能已经做出选择, 因此我们对它们不进行过多评论。虽然 C I D R即将实现以解决目前的短期问题,但是 I P v 4后继 者的实现则需要经过许多年。 3.11 小结 本章开始描述了 I P首部的格式,并简要讨论了首部中的各个字段。我们还介绍了 I P路由 选择,并指出主机的路由选择可以非常简单:如果目的主机在直接相连的网络上,那么就把 数据报直接传给目的主机,否则传给默认路由器。 在进行路由选择决策时,主机和路由器都使用路由表。在表中有三种类型的路由:特定 主机型、特定网络型和默认路由型。路由表中的表目具有一定的优先级。在选择路由时,主 机路由优先于网络路由,最后在没有其他可选路由存在时才选择默认路由。 I P路由选择是通过逐跳来实现的。数据报在各站的传输过程中目的 I P地址始终不变,但 是封装和目的链路层地址在每一站都可以改变。大多数的主机和许多路由器对于非本地网络 的数据报都使用默认的下一站路由器。 A类和B类地址一般都要进行子网划分。用于子网号的比特数通过子网掩码来指定。我们 为此举了一个实例来详细说明,即作者所在的子网,并介绍了变长子网的概念。子网的划分 缩小了I n t e r n e t路由表的规模,因为许多网络经常可以通过单个表目就可以访问了。接口和网 络的有关信息通过 i f c o n f i g和n e t s t a t命令可以获得,包括接口的 I P地址、子网掩码、广 播地址以及M T U等。 在本章的最后,我们对I n t e r n e t协议族潜在的改进建议— 下一代I P进行了讨论。 习题 3.1 环回地址必须是1 2 7 . 0 . 0 . 1吗? 3.2 在图3 - 6中指出有两个网络接口的路由器。 3.3 子网号为16 bit的A类地址与子网号为8 bit 的B类地址的子网掩码有什么不同? 3.4 阅读RFC 1219 [Tsuchiya 1991],学习分配子网号和主机号的有关推荐技术。 3.5 子网掩码2 5 5 . 2 5 5 . 0 . 2 5 5是否对A类地址有效? 3.6 你认为为什么3 . 9小节中打印出来的环回接口的 M T U要设置为1 5 3 6? 3.7 T C P / I P协议族是基于一种数据报的网络技术,即 I P层,其他的协议族则基于面向连接的 网络技术。阅读文献[Clark 1988],找出数据报网络层提供的三个优点。 第3章 IP:网际协议使用37第4章 ARP:地址解析协议 4.1 引言 本章我们要讨论的问题是只对 T C P / I P协议簇有意义的 I P地址。数据链路如以太网或令牌 环网都有自己的寻址机制(常常为 48 bit地址),这是使用数据链路的任何网络层都必须遵从 的。一个网络如以太网可以同时被不同的网络层使用。例如,一组使用 T C P / I P协议的主机和 另一组使用某种P C网络软件的主机可以共享相同的电缆。 当一台主机把以太网数据帧发送到位于同一局域网上的另一台主机时,是根据 48 bit的以 太网地址来确定目的接口的。设备驱动程序从不检查 I P数据报中的目的I P地址。 地址解析为这两种不同的地址形式提供映射: 32 bit的I P 地址和数据链路层使用的任何类型的地址。 RFC 826 [Plummer 1 9 8 2 ]是A R P规范描述文档。 本章及下一章我们要讨论的两种协议如图 4 - 1所示:A R P (地址解析协议)和R A R P(逆地址解析协议)。 A R P为I P地址到对应的硬件地址之间提供动态映射。我们 之所以用动态这个词是因为这个过程是自动完成的,一般应用 程序用户或系统管理员不必关心。 R A R P是被那些没有磁盘驱动器的系统使用(一般是无盘工作站或 X终端),它需要系统 管理员进行手工设置。我们在第 5章对它进行讨论。 4.2 一个例子 任何时候我们敲入下面这个形式的命令: % ftp bsdi 都会进行以下这些步骤。这些步骤的序号如图 4 - 2所示。 1) 应用程序FTP客户端调用函数g e t h o s t b y n a m e(3)把主机名(bsdi)转换成32 bit的IP地址。 这个函数在D N S(域名系统)中称作解析器,我们将在第 1 4章对它进行介绍。这个转换 过程或者使用DNS,或者在较小网络中使用一个静态的主机文件(/e t c / h o s t s)。 2) F T P客户端请求T C P用得到的I P地址建立连接。 3) T C P发送一个连接请求分段到远端的主机,即用上述 I P地址发送一份 I P数据报(在第 1 8章我们将讨论完成这个过程的细节)。 4) 如果目的主机在本地网络上(如以太网、令牌环网或点对点链接的另一端),那么I P数 据报可以直接送到目的主机上。如果目的主机在一个远程网络上,那么就通过 I P选路 函数来确定位于本地网络上的下一站路由器地址,并让它转发 I P数据报。在这两种情 况下,I P数据报都是被送到位于本地网络上的一台主机或路由器。 5) 假定是一个以太网,那么发送端主机必须把 32 bit的I P地址变换成48 bit的以太网地址。 图4-1 地址解析协议:ARP 和RARP 32位Internet地址 48位以太网地址第4章 ARP:地址解析协议使用39 从逻辑I n t e r n e t地址到对应的物理硬件地址需要进行翻译。这就是 A R P的功能。 A R P本来是用于广播网络的,有许多主机或路由器连在同一个网络上。 6) A R P发送一份称作 A R P请求的以太网数据帧给以太网上的每个主机。这个过程称作广 播,如图 4 - 2中的虚线所示。 A R P请求数据帧中包含目的主机的 I P地址(主机名为 b s d i),其意思是“如果你是这个 I P地址的拥有者,请回答你的硬件地址。” 图4-2 当用户输入命令“ftp 主机名”时ARP的操作 7) 目的主机的A R P层收到这份广播报文后,识别出这是发送端在寻问它的 I P地址,于是 发送一个A R P应答。这个A R P应答包含I P地址及对应的硬件地址。 8) 收到A R P应答后,使A R P进行请求—应答交换的 I P数据报现在就可以传送了。 9) 发送I P数据报到目的主机。 在A R P背后有一个基本概念,那就是网络接口有一个硬件地址(一个 48 bit的值,标识不 同的以太网或令牌环网络接口)。在硬件层次上进行的数据帧交换必须有正确的接口地址。但 是,T C P / I P有自己的地址:32 bit的I P地址。知道主机的I P地址并不能让内核发送一帧数据给 主机。内核(如以太网驱动程序)必须知道目的端的硬件地址才能发送数据。 A R P的功能是 在32 bit的I P地址和采用不同网络技术的硬件地址之间提供动态映射。 点对点链路不使用A R P。当设置这些链路时(一般在引导过程进行),必须告知内核链路 解析器 主机名 主机名 IP地址 用IP地址建立连接 给IP地址发送IP数据报 以太网 驱动程序 ARP请求(以太网广播) 以太网驱动程序 以太网 驱动程序每一端的I P地址。像以太网地址这样的硬件地址并不涉及。 4.3 ARP高速缓存 A R P高效运行的关键是由于每个主机上都有一个 A R P高速缓存。这个高速缓存存放了最 近I n t e r n e t地址到硬件地址之间的映射记录。高速缓存中每一项的生存时间一般为 2 0分钟,起 始时间从被创建时开始算起。 我们可以用a r p(8)命令来检查ARP高速缓存。参数-a的意思是显示高速缓存中所有的内容。 bsdi % arp -a sun (140.252.13.33) at 8:0:20:3:f6:42 svr4 (140.252.13.34) at 0:0:c0:c2:9b:26 48 bit的以太网地址用 6个十六进制的数来表示,中间以冒号隔开。在 4 . 8小节我们将讨论 a r p命令的其他功能。 4.4 ARP的分组格式 在以太网上解析 I P地址时,A R P请求和应答分组的格式如图 4 - 3所示(A R P可以用于其他 类型的网络,可以解析 I P地址以外的地址。紧跟着帧类型字段的前四个字段指定了最后四个 字段的类型和长度)。 图4-3 用于以太网的ARP请求或应答分组格式 以太网报头中的前两个字段是以太网的源地址和目的地址。目的地址为全 1的特殊地址是 广播地址。电缆上的所有以太网接口都要接收广播的数据帧。 两个字节长的以太网帧类型表示后面数据的类型。对于 A R P请求或应答来说,该字段的 值为0 x 0 8 0 6。 形容词h a r d w a r e (硬件)和p r o t o c o l (协议)用来描述A R P分组中的各个字段。例如,一个 A R P 请求分组询问协议地址(这里是 I P地址)对应的硬件地址(这里是以太网地址)。 硬件类型字段表示硬件地址的类型。它的值为 1即表示以太网地址。协议类型字段表示要 映射的协议地址类型。它的值为 0 x 0 8 0 0即表示I P地址。它的值与包含 I P数据报的以太网数据 帧中的类型字段的值相同,这是有意设计的(参见图 2 - 1)。 接下来的两个1字节的字段,硬件地址长度和协议地址长度分别指出硬件地址和协议地址 的长度,以字节为单位。对于以太网上 I P地址的A R P请求或应答来说,它们的值分别为 6和4。 操作字段指出四种操作类型,它们是 A R P请求(值为1)、A R P应答(值为2)、R A R P请求 (值为3)和R A R P应答(值为4)(我们在第5章讨论R A R P)。这个字段必需的,因为 A R P请求 和A R P应答的帧类型字段值是相同的。 接下来的四个字段是发送端的硬件地址(在本例中是以太网地址)、发送端的协议地址 (I P地址)、目的端的硬件地址和目的端的协议地址。注意,这里有一些重复信息:在以太网 40使用TCP/IP详解,卷1:协议 以太网 目的地址 以太网 源地址 帧 类型 硬件 类型 协议 类型 硬件地址长度 协议地址长度 发送端 以太网地址 发送端 IP地址 目的以太网 地址 目的 IP地址 以太网首部 28字节ARP请求/应答第4章 ARP:地址解析协议使用41 的数据帧报头中和A R P请求数据帧中都有发送端的硬件地址。 对于一个A R P请求来说,除目的端硬件地址外的所有其他的字段都有填充值。当系统收 到一份目的端为本机的 A R P请求报文后,它就把硬件地址填进去,然后用两个目的端地址分 别替换两个发送端地址,并把操作字段置为 2,最后把它发送回去。 4.5 ARP举例 在本小节中,我们用 t c p d u m p命令来看一看运行像Te l n e t这样的普通T C P工具软件时A R P 会做些什么。附录A包含t c p d u m p命令的其他细节。 4.5.1 一般的例子 为了看清楚A R P的运作过程,我们执行t e l n e t命令与无效的服务器连接。 当我们在另一个系统( s u n)上运行带有- e选项的t c p d u m p命令时,显示的是硬件地址 (在我们的例子中是48 bit的以太网地址)。 图4 - 4中的t c p d u m p的原始输出如附录 A中的图A - 3所示。由于这是本书第一个 t c p d u m p 输出例子,你应该去查看附录中的原始输出,看看我们作了哪些修改。 图4-4 TCP连接请求产生的ARP请求和应答 我们删除了t c p d u m p命令输出的最后四行,因为它们是结束连接的信息(我们将在第 1 8 章进行讨论),与这里讨论的内容不相关。 在第1行中,源端主机( b s d i)的硬件地址是0 : 0 : c 0 : 6 f : 2 d : 4 0。目的端主机的硬件地址是 ff : ff : ff : ff : ff : ff,这是一个以太网广播地址。电缆上的每个以太网接口都要接收这个数据帧并对 它进行处理,如图4 - 2所示。 第1行中紧接着的一个输出字段是 a r p,表明帧类型字段的值是 0 x 0 8 0 6,说明此数据帧是 一个A R P请求或回答。 在每行中,单词 a r p或i p后面的值6 0指的是以太网数据帧的长度。由于 A R P请求或回答 检验ARP高速缓存是空的 连接无效的服务器 键入Ctrl和右括号,使Telnet回到提示符并关闭的数据帧长都是4 2字节(2 8字节的A R P数据,1 4字节的以太网帧头),因此,每一帧都必须加 入填充字符以达到以太网的最小长度要求: 6 0字节。 请参见图1 - 7,这个最小长度 6 0字节包含1 4字节的以太网帧头,但是不包括 4个字节的以 太网帧尾。有一些书把最小长度定为 6 4字节,它包括以太网的帧尾。我们在图 1 - 7中把最小长 度定为4 6字节,是有意不包括 1 4字节的帧首部,因为对应的最大长度( 1 5 0 0字节)指的是 M T U— 最大传输单元(见图2 - 5)。我们使用M T U经常是因为它对I P数据报的长度进行限制, 但一般与最小长度无关。大多数的设备驱动程序或接口卡自动地用填充字符把以太网数据帧 充满到最小长度。第 3,4和5行中的I P数据报(包含T C P段)的长度都比最小长度短,因此都 必须填充到6 0字节。 第1行中的下一个输出字段 arp who-has表示作为A R P请求的这个数据帧中,目的 I P地 址是s v r 4的地址,发送端的 I P地址是b s d i的地址。t c p d u m p打印出主机名对应的默认 I P地址 (在4 . 7节中,我们将用-n选项来查看A R P请求中真正的I P地址。) 从第 2行中可以看到,尽管 A R P请求是广播的,但是 A R P应答的目的地址却是 b s d i (0 : 0 : c 0 : 6 f : 2 d : 4 0)。A R P应答是直接送到请求端主机的,而是广播的。 t c p d u m p打印出arp reply的字样,同时打印出响应者的主机名和硬件地址。 第3行是第一个请求建立连接的 T C P段。它的目的硬件地址是目的主机 (s v r 4)。我们将在 第1 8章讨论这个段的细节内容。 在每一行中,行号后面的数字表示 t c p d u m p收到分组的时间(以秒为单位)。除第1行外, 其他每行在括号中还包含了与上一行的时间差异(以秒为单位)。从这个图可以看出,发送 A R P请求与收到A R P回答之间的延时是2.2 ms。而在0.7 ms之后发出第一段T C P报文。在本例 中,用A R P进行动态地址解析的时间小于 3 ms。 最后需要指出的一点,在 t c p d u m p命令输出中,我们没有看到 s v r 4在发出第一段 T C P报 文(第4行)之前发出的A R P请求。这是因为可能在 s v r 4的A R P高速缓存中已经有 b s d i的表 项。一般情况下,当系统收到 A R P请求或发送A R P应答时,都要把请求端的硬件地址和 I P地 址存入A R P高速缓存。在逻辑上可以假设,如果请求端要发送 I P数据报,那么数据报的接收 端将很可能会发送一个应答。 4.5.2 对不存在主机的ARP请求 如果查询的主机已关机或不存在会发生什么情况呢?为此我们指定一个并不存在的 I n t e r n e t地址— 根据网络号和子网号所对应的网络确实存在,但是并不存在所指定的主机号。 从图3 - 1 0可以看出,主机号从 3 6到6 2的主机并不存在(主机号为 6 3是广播地址)。这里,我们 用主机号3 6来举例。 t c p d u m p命令的输出如图4 - 5所示。 42使用TCP/IP详解,卷1:协议 这次是Telnet的一个地址,而不是主机名 在前一个日期输出后76秒 检查ARP高速缓存图4-5 对不存在主机的ARP请求 这一次,我们没有用-e选项,因为已经知道A R P请求是在网上广播的。 令人感兴趣的是看到多次进行 A R P请求:第1次请求发生后5 . 5秒进行第2次请求,在2 4秒 之后又进行第3次请求(在第2 1章我们将看到T C P的超时和重发算法的细节)。t c p d u m p命令 输出的超时限制为 2 9 . 5秒。但是,在t e l n e t命令使用前后分别用 d a t e命令检查时间,可以 发现Te l n e t客户端的连接请求似乎在大约 7 5秒后才放弃。事实上,我们在后面将看到,大多数 的B S D实现把完成T C P连接请求的时间限制设置为 7 5秒。 在第1 8章中,当我们看到建立连接的 T C P报文段序列时,会发现A R P请求对应于T C P试图 发送的初始T C P S Y N(同步)段。 注意,在线路上始终看不到 T C P的报文段。我们能看到的是 A R P请求。直到A R P回答返回 时,T C P报文段才可以被发送,因为硬件地址到这时才可能知道。如果我们用过滤模式运行 t c p d u m p命令,只查看T C P数据,那么将没有任何输出。 4.5.3 ARP高速缓存超时设置 在A R P高速缓存中的表项一般都要设置超时值(在 4 . 8小节中,我们将看到管理员可以用 a r p命令把地址放入高速缓存中而不设置超时值)。从伯克利系统演变而来的系统一般对完整 的表项设置超时值为2 0分钟,而对不完整的表项设置超时值为 3分钟(在前面的例子中我们已 见过一个不完整的表项,即在以太网上对一个不存在的主机发出 A R P请求。)当这些表项再次 使用时,这些实现一般都把超时值重新设为 2 0分钟。 Host Requirements RFC表明即使表项正在使用时,超时值也应该启动,但是大多数从伯 克利系统演变而来的系统没有这样做— 它们每次都是在访问表项时重设超时值。 4.6 ARP代理 如果A R P请求是从一个网络的主机发往另一个网络上的主机,那么连接这两个网络的路 由器就可以回答该请求,这个过程称作委托 A R P或A R P代理(Proxy ARP)。这样可以欺骗发起 A R P请求的发送端,使它误以为路由器就是目的主机,而事实上目的主机是在路由器的“另 一边”。路由器的功能相当于目的主机的代理,把分组从其他主机转发给它。 举例是说明A R P代理的最好方法。如图 3 - 1 0所示,系统s u n与两个以太网相连。但是,我 们也指出过,事实上并不是这样,请把它与封内图 1进行比较。在s u n和子网1 4 0 . 2 5 2 . 1之间实 际存在一个路由器,就是这个具有 A R P代理功能的路由器使得s u n就好像在子网1 4 0 . 2 5 2 . 1上一 样。具体安置如图4 - 6所示,路由器Telebit NetBlazer,取名为n e t b,在子网和主机s u n之间。 当子网1 4 0 . 2 5 2 . 1(称作g e m i n i)上的其他主机有一份I P数据报要传给地址为1 4 0 . 2 5 2 . 1 . 2 9 的s u n时,g e m i n i比较网络号(1 4 0 . 2 5 2)和子网号(1),因为它们都是相同的,因而在图4 - 6 上面的以太网中发送I P地址1 4 0 . 2 5 2 . 1 . 2 9的A R P请求。路由器n e t b识别出该I P地址属于它的一个 拔号主机,于是把它的以太网接口地址 1 4 0 . 2 5 2 . 1作为硬件地址来回答。主机 g e m i n i通过以太 网发送I P数据报到n e t b,n e t b通过拨号S L I P链路把数据报转发到 s u n。这个过程对于所有 第4章 ARP:地址解析协议使用431 4 0 . 2 5 2 . 1子网上的主机来说都是透明的,主机s u n实际上是在路由器n e t b后面进行配置的。 图4-6 ARP代理的例子 如果在主机g e m i n i上执行a r p命令,经过与主机 s u n通信以后,我们发现在同一个子网 1 4 0 . 2 5 2 . 1上的n e t b和s u n的I P地址映射的硬件地址是相同的。这通常是使用委托A R P的线索。 gemini % arp -a 这里是子网1 4 0 . 2 5 2 . 1上其他主机的输出行 netb (140.252.1.183) at 0:80:ad:3:6a:80 sun (140.252.1.29) at 0:80:ad:3:6a:80 图4 - 6中的另一个需要解释的细节是在路由器 n e t b的下方(S L I P链路)显然缺少一个 I P 地址。为什么在拨号 S L I P链路的两端只拥有一个 I P地址,而在b s d i和s l i p之间的两端却分 别有一个I P地址?在3 . 8小节我们已经指出,用 i f c o n f i g命令可以显示拨号 S L I P链路的目的 地址,它是1 4 0 . 2 5 2 . 1 . 1 8 3。N e t B l a z e r不需要知道拨号 S L I P链路每一端的I P地址(这样做会用 更多的I P地址)。相反,它通过分组到达的串行线路接口来确定发送分组的拨号主机,因此对 于连接到路由器的每个拨号主机不需要用唯一的 I P地址。所有的拨号主机使用同一个 I P地址 1 4 0 . 2 5 2 . 1 . 1 8 3作为S L I P链路的目的地址。 A R P代理可以把数据报传送到路由器 s u n上,但是子网1 4 0 . 2 5 2 . 1 3上的其他主机是如何处 理的呢?选路必须使数据报能到达其他主机。这里需要特殊处理,选路表中的表项必须在网 络1 4 0 . 2 5 2的某个地方制定,使所有数据报的目的端要么是子网 1 4 0 . 2 5 2 . 1 3,要么是子网上的 某个主机,这样都指向路由器 n e t b。而路由器 n e t b知道如何把数据报传到最终的目的端, 即通过路由器s u n。 A R P代理也称作混合A R P(p r o m i s c u o u s A R P)或ARP 出租(ARP hack)。这些名字来自于 A R P代理的其他用途:通过两个物理网络之间的路由器可以互相隐藏物理网络。在这种情况 下,两个物理网络可以使用相同的网络号,只要把中间的路由器设置成一个 A R P代理,以响 应一个网络到另一个网络主机的 A R P请求。这种技术在过去用来隐藏一组在不同物理电缆上 运行旧版T C P / I P的主机。分开这些旧主机有两个共同的理由,其一是它们不能处理子网划分, 其二是它们使用旧的广播地址(所有比特值为 0的主机号,而不是目前使用的所有比特值为 1 44使用TCP/IP详解,卷1:协议 以太网,子网140.252.1 以太网140.252.13 调制解调器 调制解调器 ARP应答 ARP请求发给140.252.1.29 Telebit NetBlazer路由器配 置作为s u n的代理ARP (拨号)的主机号)。 4.7 免费ARP 我们可以看到的另一个 A R P特性称作免费ARP (gratuitous ARP)。它是指主机发送A R P查 找自己的I P地址。通常,它发生在系统引导期间进行接口配置的时候。 在互联网中,如果我们引导主机 b s d i并在主机s u n上运行t c p d u m p命令,可以看到如图 4 - 7所示的分组。 图4-7 免费ARP的例子 (我们用- n选项运行t c p d u m p命令,打印出点分十进制的地址,而不是主机名)。对于 A R P请求中的各字段来说,发送端的协议地址和目的端的协议地址是一致的:即主机 b s d i的 地址1 4 0 . 2 5 2 . 1 3 . 3 5。另外,以太网报头中的源地址 0 : 0 : c 0 : 6 f : 2 d : 4 0,正如t c p d u m p命令显示的 那样,等于发送端的硬件地址(见图 4 - 4)。 免费A R P可以有两个方面的作用: 1) 一个主机可以通过它来确定另一个主机是否设置了相同的 I P地址。主机b s d i并不希望 对此请求有一个回答。但是,如果收到一个回答,那么就会在终端日志上产生一个错误消息 “以太网地址: a : b : c : d : e : f发送来重复的I P地址”。这样就可以警告系统管理员,某个系统有不 正确的设置。 2) 如果发送免费A R P的主机正好改变了硬件地址(很可能是主机关机了,并换了一块接 口卡,然后重新启动),那么这个分组就可以使其他主机高速缓存中旧的硬件地址进行相应的 更新。一个比较著名的A R P协议事实[Plummer 1982]是,如果主机收到某个I P地址的A R P请求, 而且它已经在接收者的高速缓存中,那么就要用 A R P请求中的发送端硬件地址(如以太网地 址)对高速缓存中相应的内容进行更新。主机接收到任何 A R P请求都要完成这个操作( A R P 请求是在网上广播的,因此每次发送 A R P请求时网络上的所有主机都要这样做)。 文献[ B h i d e、E l n o z a h y和M o rgan 1991]中有一个应用例子,通过发送含有备份硬件地址和 故障服务器的 I P地址的免费A R P请求,使得备份文件服务器可以顺利地接替故障服务器进行 工作。这使得所有目的地为故障服务器的报文都被送到备份服务器那里,客户程序不用关心 原来的服务器是否出了故障。 不幸的是,作者却反对这个做法,因为这取决于所有不同类型的客户端都要有正 确的ARP协议实现。他们显然碰到过客户端的ARP协议实现与规范不一致的情况。 通过检查作者所在子网上的所有系统可以发现,SunOS 4.1.3和4 . 4 B S D在引导时都 发送免费ARP,但是SVR4却没有这样做。 4.8 arp命令 我们已经用过这个命令及参数- a来显示A R P高速缓存中的所有内容。这里介绍其他参数 的功能。 超级用户可以用选项- d来删除A R P高速缓存中的某一项内容(这个命令格式可以在运行 第4章 ARP:地址解析协议使用45一些例子之前使用,以让我们看清楚 A R P的交换过程)。 另外,可以通过选项- s来增加高速缓存中的内容。这个参数需要主机名和以太网地址: 对应于主机名的I P地址和以太网地址被增加到高速缓存中。新增加的内容是永久性的(比如, 它没有超时值),除非在命令行的末尾附上关键字 t e m p。 位于命令行末尾的关键字 p u b和- s选项一起,可以使系统起着主机 A R P代理的作用。系统 将回答与主机名对应的 I P地址的A R P请求,并以指定的以太网地址作为应答。如果广播的地 址是系统本身,那么系统就为指定的主机名起着委托 A R P代理的作用。 4.9 小结 在大多数的T C P / I P实现中,A R P是一个基础协议,但是它的运行对于应用程序或系统管 理员来说一般是透明的。 A R P高速缓存在它的运行过程中非常关键,我们可以用 a r p命令对高 速缓存进行检查和操作。高速缓存中的每一项内容都有一个定时器,根据它来删除不完整和 完整的表项。a r p命令可以显示和修改A R P高速缓存中的内容。 我们介绍了A R P的一般操作,同时也介绍了一些特殊的功能:委托 A R P(当路由器对来 自于另一个路由器接口的 A R P请求进行应答时)和免费 A R P(发送自己 I P地址的A R P请求, 一般发生在引导过程中)。 习题 4.1 当输入命令以生成类似图4 - 4那样的输出时,发现本地A R P快速缓存为空以后,输入命令 bsdi % rsh svr4 arp -a 如果发现目的主机上的 A R P快速缓存也是空的,那将发生什么情况? (该命令将在s v r 4 主机上运行a r p -a命令)。 4.2 请描述如何判断一个给定主机是否能正确处理接收到的非必要的 A R P请求的方法。 4.3 由于发送一个数据包后 A R P将等待响应,因此 4 . 2节所描述的步骤7可能会持续一段时间。 你认为A R P将如何处理在这期间收到相同目的 I P地址发来的多个数据包? 4.4 在4 . 5节的最后,我们指出Host Requirements RFC和伯克利派生系统在处理活动 A R P表目 的超时时存在差异。那么如果我们在一个由伯克利派生系统的客户端上,试图与一个正 在更换以太网卡而处于关机状态的服务器主机联系,这时会发生什么情况?如果服务器 在引导过程中广播一份免费 A R P,这种情况是否会发生变化? 46使用TCP/IP详解,卷1:协议第5章 RARP:逆地址解析协议 5.1 引言 具有本地磁盘的系统引导时,一般是从磁盘上的配置文件中读取 I P地址。但是无盘机, 如X终端或无盘工作站,则需要采用其他方法来获得 I P地址。 网络上的每个系统都具有唯一的硬件地址,它是由网络接口生产厂家配置的。无盘系统 的R A R P实现过程是从接口卡上读取唯一的硬件地址,然后发送一份 R A R P请求(一帧在网络 上广播的数据),请求某个主机响应该无盘系统的 I P地址(在R A R P应答中)。 在概念上这个过程是很简单的,但是实现起来常常比 A R P要困难,其原因在本章后面介 绍。R A R P的正式规范是RFC 903 [Finlayson et al. 1984]。 5.2 RARP的分组格式 R A R P分组的格式与A R P分组基本一致(见图 4 - 3)。它们之间主要的差别是 R A R P请求或 应答的帧类型代码为0 x 8 0 3 5,而且R A R P请求的操作代码为3,应答操作代码为4。 对应于A R P,R A R P请求以广播方式传送,而R A R P应答一般是单播( u n i c a s t )传送的。 5.3 RARP举例 在互联网中,我们可以强制 s u n主机从网络上引导,而不是从本地磁盘引导。如果在主 机b s d i上运行R A R P服务程序和t c p d u m p命令,就可以得到如图5 - 1那样的输出。用-e参数使 得t c p d u m p命令打印出硬件地址: 图5-1 RARP请求和应答 R A R P请求是广播方式(第 1行),而第2行的R A R P应答是单播方式。第 2行的输出中 a t s u n表示R A R P应答包含主机s u n的I P地址(1 4 0 . 2 5 2 . 1 3 . 3 3)。 在第3行中,我们可以看到,一旦 s u n收到I P地址,它就发送一个T F T P读请求(R R Q)给 文件8 C F C 0 D 2 1 . S U N 4 C(T F T P表示简单文件传送协议。我们将在第 1 5章详细介绍)。文件名 中的8个十六进制数字表求主机 s u n的I P地址1 4 0 . 2 5 2 . 1 3 . 3 3。这个I P地址在R A R P应答中返回。 文件名的后缀S U N 4 C表示被引导系统的类型。 t c p d u m p在第3行中指出I P数据报的长度是6 5个字节,而不是一个U D P数据报(实际上是一 个U D P数据报),因为我们运行t c p d u m p命令时带有- e参数,以查看硬件层的地址。在图5 - 1中需要指出的另一点是,第2行中的以太网数据帧长度比最小长度还要小(在4 . 5节中我们说过应该 是6 0字节)。其原因是我们在发送该以太网数据帧的系统(b s d i)上运行t c p d u m p命令。应用程 序r a r p d写4 2字节到B S D分组过滤设备上(其中1 4字节为以太网数据帧的报头,剩下的2 8字节是 R A R P应答),这就是t c p d u m p收到的副本。但是以太网设备驱动程序要把这一短帧填充空白字 符以达到最小传输长度(6 0)。如果我们在另一个系统上运行t c p d u m p命令,其长度将会是6 0。 从这个例子可以看出,当无盘系统从 R A R P应答中收到它的 I P地址后,它将发送 T F T P请 求来读取引导映象。在这一点上我们将不再进一步详细讨论无盘系统是如何引导的(第 1 6章 将描述无盘X终端利用R A R P、B O O T P以及T F T P进行引导的过程)。 当网络上没有R A R P服务器时,其结果如图5 - 2所示。每个分组的目的地址都是以太网广播地 址。在w h o- 后面的以太网地址是目的硬件地址,跟在t e l l后面的以太网地址是发送端的硬件地址。 请注意重发的频度。第一次重发是在 6 . 5 5秒以后,然后增加到 4 2 . 8 0秒,然后又减到 5 . 3 4 秒和6 . 5 5秒,然后又回到4 2 . 7 9秒。这种不确定的情况一直继续下去。如果计算一下两次重发 之间的时间间隔,我们发现存在一种双倍的关系:从 5 . 3 4到6 . 5 5是1 . 2 1秒,从 6 . 5 5到8 . 9 7是 2 . 4 2秒,从8 . 9 7到1 3 . 8 0是4 . 8 3秒,一直这样继续下去。当时间间隔达到某个阈值时(大于 4 2 . 8 0秒),它又重新置为5 . 3 4秒。 图5-2 网络中没有RARP服务器的RARP请求 超时间隔采用这样的递增方法比每次都采用相同值的方法要好。在图 6 - 8中,我们将看到 一种错误的超时重发方法,以及在第 2 1章中将看到T C P的超时重发机制。 5.4 RARP服务器的设计 虽然R A R P在概念上很简单,但是一个 R A R P服务器的设计与系统相关而且比较复杂。相 反,提供一个 A R P服务器很简单,通常是 T C P / I P在内核中实现的一部分。由于内核知道 I P地 48使用TCP/IP详解,卷1:协议址和硬件地址,因此当它收到一个询问 I P地址的A R P请求时,只需用相应的硬件地址来提供 应答就可以了。 5.4.1 作为用户进程的RARP服务器 R A R P服务器的复杂性在于,服务器一般要为多个主机(网络上所有的无盘系统)提供硬 件地址到I P地址的映射。该映射包含在一个磁盘文件中(在 U n i x系统中一般位于/ e t c / e t h e r s目 录中)。由于内核一般不读取和分析磁盘文件,因此 R A R P服务器的功能就由用户进程来提供, 而不是作为内核的T C P / I P实现的一部分。 更为复杂的是,R A R P请求是作为一个特殊类型的以太网数据帧来传送的(帧类型字段值 为0 x 8 0 3 5,如图2 - 1所示)。这说明R A R P服务器必须能够发送和接收这种类型的以太网数据帧。 在附录A中,我们描述了 B S D分组过滤器、 S u n的网络接口栓以及 S V R 4数据链路提供者接口 都可用来接收这些数据帧。由于发送和接收这些数据帧与系统有关,因此 R A R P服务器的实现 是与系统捆绑在一起的。 5.4.2 每个网络有多个RARP服务器 R A R P服务器实现的一个复杂因素是 R A R P请求是在硬件层上进行广播的,如图 5 - 2所示。 这意味着它们不经过路由器进行转发。为了让无盘系统在R A R P服务器关机的状态下也能引导, 通常在一个网络上(例如一根电缆)要提供多个 R A R P服务器。 当服务器的数目增加时(以提供冗余备份),网络流量也随之增加,因为每个服务器对每 个R A R P请求都要发送R A R P应答。发送R A R P请求的无盘系统一般采用最先收到的 R A R P应答 (对于A R P,我们从来没有遇到这种情况,因为只有一台主机发送 A R P应答)。另外,还有一 种可能发生的情况是每个R A R P服务器同时应答,这样会增加以太网发生冲突的概率。 5.5 小结 R A R P协议是许多无盘系统在引导时用来获取 I P地址的。R A R P分组格式基本上与 A R P分 组一致。一个R A R P请求在网络上进行广播,它在分组中标明发送端的硬件地址,以请求相应 I P地址的响应。应答通常是单播传送的。 R A R P带来的问题包括使用链路层广播,这样就阻止大多数路由器转发 R A R P请求,只返 回很少信息:只是系统的 I P地址。在第1 6章中,我们将看到 B O O T P在无盘系统引导时会返回 更多的信息:I P地址和引导主机的名字等。 虽然R A R P在概念上很简单,但是 R A R P服务器的实现却与系统相关。因此,并不是所有 的T C P / I P实现都提供R A R P服务器。 习题 5.1 RARP需要不同的帧类型字段吗? A R P和R A R P都使用相同的值0 x 0 8 0 6吗? 5.2 在一个有多个R A R P服务器的网络上,如何防止它们的响应发生冲突? 第5章 RARP:逆地址解析协议使用49第6章 ICMP:Internet控制报文协议 6.1 引言 I C M P经常被认为是 I P层的一个组成部分。它传递差错报文以及其他需要注意的信息。 I C M P报文通常被I P层或更高层协议( T C P或U D P)使用。一些 I C M P报文把差错报文返回给 用户进程。 I C M P报文是在I P数据报内部被传输的,如 图6 - 1所示。 ICMP 的正式规范参见 RFC 792 [Posterl 1 9 8 1 b ]。 I C M P报文的格式如图6 - 2所示。所有报文的 前4个字节都是一样的,但是剩下的其他字节则互不相同。下面我们将逐个介绍各种报文格式。 类型字段可以有 1 5个不同的值,以描述特定类型的 I C M P报文。某些I C M P报文还使用代 码字段的值来进一步描述不同的条件。 检验和字段覆盖整个I C M P报文。使用的算法与我们在 3 . 2节中介绍的I P首部检验和算法相 同。I C M P的检验和是必需的。 图6-2 ICMP报文 在本章中,我们将一般地讨论 I C M P报文,并对其中一部分作详细介绍:地址掩码请求和 应答、时间戳请求和应答以及不可达端口。我们将详细介绍第 2 7章P i n g程序所使用的回应请 求和应答报文和第9章处理I P路由的I C M P报文。 6.2 ICMP报文的类型 各种类型的I C M P报文如图6 - 3所示,不同类型由报文中的类型字段和代码字段来共同决定。 图中的最后两列表明 I C M P报文是一份查询报文还是一份差错报文。因为对 I C M P差错报 文有时需要作特殊处理,因此我们需要对它们进行区分。例如,在对 I C M P差错报文进行响应 时,永远不会生成另一份 I C M P差错报文(如果没有这个限制规则,可能会遇到一个差错产生 另一个差错的情况,而差错再产生差错,这样会无休止地循环下去)。 当发送一份I C M P差错报文时,报文始终包含 I P的首部和产生I C M P差错报文的I P数据报的 前8个字节。这样,接收 I C M P差错报文的模块就会把它与某个特定的协议(根据 I P数据报首 图6-1 ICMP封装在IP数据报内部 ICMP报文 IP数据报 20字节 IP首部 (不同类型和代码有不同的内容) 8位类型 8位代码 16位检验和部中的协议字段来判断)和用户进程(根据包含在 I P数据报前8个字节中的T C P或U D P报文首 部中的T C P或U D P端口号来判断)联系起来。 6 . 5节将举例来说明一点。 下面各种情况都不会导致产生 I C M P差错报文: 1) ICMP差错报文(但是,I C M P查询报文可能会产生I C M P差错报文)。 2) 目的地址是广播地址(见图 3 - 9)或多播地址(D类地址,见图1 - 5)的I P数据报。 3) 作为链路层广播的数据报。 4) 不是I P分片的第一片(将在11 . 5节介绍分片)。 5) 源地址不是单个主机的数据报。这就是说,源地址不能为零地址、环回地址、广播地 址或多播地址。 这些规则是为了防止过去允许 I C M P差错报文对广播分组响应所带来的广播风暴。 第6章 ICMP:Internet控制报文协议使用51 类 型 代 码 描 述 查 询 差 错 0 0 回显应答(P i n g应答,第7章) • 3 目的不可达: 0 网络不可达( 9 . 3节) • 1 主机不可达( 9 . 3节) • 2 协议不可达 • 3 端口不可达( 6 . 5节) • 4 需要进行分片但设置了不分片比特( 11 . 6节) • 5 源站选路失败(8 . 5节) • 6 目的网络不认识 • 7 目的主机不认识 • 8 源主机被隔离(作废不用) • 9 目的网络被强制禁止 • 1 0 目的主机被强制禁止 • 11 由于服务类型 TO S,网络不可达(9 . 3节) • 1 2 由于服务类型 TO S,主机不可达(9 . 3节) • 1 3 由于过滤,通信被强制禁止 • 1 4 主机越权 • 1 5 优先权中止生效 • 4 0 源端被关闭(基本流控制, 11 . 11节) • 5 重定向(9 . 5节):• 0 对网络重定向 • 1 对主机重定向 • 2 对服务类型和网络重定向 • 3 对服务类型和主机重定向 • 8 0 请求回显(P i n g请求,第7章) • 9 0 路由器通告( 9 . 6节) • 1 0 0 路由器请求( 9 . 6节) • 11 超时: 0 传输期间生存时间为0(Traceroute, 第8章) • 1 在数据报组装期间生存时间为 0(11 . 5节) • 1 2 参数问题: 0 坏的I P首部(包括各种差错) • 1 缺少必需的选项 • 1 3 0 时间戳请求( 6 . 4节) • 1 4 0 时间戳应答( 6 . 4节) • 1 5 0 信息请求(作废不用) • 1 6 0 信息应答(作废不用) • 1 7 0 地址掩码请求(6 . 3节) • 1 8 0 地址掩码应答(6 . 3节) • 图6-3 ICMP报文类型6.3 ICMP地址掩码请求与应答 I C M P地址掩码请求用于无盘系统在引导过程中获取自己的子网掩码( 3 . 5节)。系统广播 它的I C M P请求报文(这一过程与无盘系统在引导过程中用 R A R P获取I P地址是类似的)。无盘 系统获取子网掩码的另一个方法是 B O O T P协议,我们将在第 1 6章中介绍。I C M P地址掩码请 求和应答报文的格式如图6 - 4所示。 图6-4 ICMP地址掩码请求和应答报文 I C M P报文中的标识符和序列号字段由发送端任意选择设定,这些值在应答中将被返回。 这样,发送端就可以把应答与请求进行匹配。 我们可以写一个简单的程序(取名为 i c m p a d d r m a s k),它发送一份I C M P地址掩码请求报 文,然后打印出所有的应答。由于一般是把请求报文发往广播地址,因此这里我们也这样做。 目的地址(1 4 0 . 2 5 2 . 1 3 . 6 3)是子网1 4 0 . 2 5 2 . 1 3 . 3 2的广播地址(见图3 - 1 2)。 sun % icmpaddrmask 140.252.13.63 received mask = ffffffe0, from 140.252.13.33 来自本机 received mask = ffffffe0, from 140.252.13.35 来自b s d i received mask = ffff0000, from 140.252.13.34 来自s v r 4 在输出中我们首先注意到的是,从 s v r 4返回的子网掩码是错的。显然,尽管 s v r 4接口 已经设置了正确的子网掩码,但是 S V R 4还是返回了一个普通的 B类地址掩码,就好像子网并 不存在一样。 svr4 % ifconfig emd0 emd0: flags=23 inet 140.252.13.34 netmask ffffffe0 broadcast 140.252.13.63 S V R 4处理I C M P地址掩码请求过程存在差错。 我们用t c p d u m p命令来查看主机b s d i上的情况,输出如图 6 - 5所示。我们用-e选项来查看 硬件地址。 图6-5 发到广播地址的ICMP地址掩码请求 注意,尽管在线路上什么也看不见,但是发送主机 s u n也能接收到I C M P应答(带有上面 “来自本机”的输出行)。这是广播的一般特性:发送主机也能通过某种内部环回机制收到一 份广播报文拷贝。由于术语“广播”的定义是指局域网上的所有主机,因此它必须包括发送 52使用TCP/IP详解,卷1:协议 类型(17或18) 代码(0) 检验和 序列号 32位子网掩码 标识符 12字节主机在内(参见图 2 - 4,当以太网驱动程序识别出目的地址是广播地址后,它就把分组送到网 络上,同时传一份拷贝到环回接口)。 接下来,b s d i广播应答,而 s v r 4却只把应答传给请求主机。通常,应答地址必须是单 播地址,除非请求端的源 I P地址是0 . 0 . 0 . 0。本例不属于这种情况,因此,把应答发送到广播 地址是B S D / 3 8 6的一个内部差错。 R F C规定,除非系统是地址掩码的授权代理,否则它不能发送地址掩码应答(为 了成为授权代理,它必须进行特殊配置,以发送这些应答。参见附录 E)。但是,正如 我们从本例中看到的那样,大多数主机在收到请求时都发送一个应答,甚至有一些主 机还发送差错的应答。 最后一点可以通过下面的例子来说明。我们向本机 I P地址和环回地址分别发送地址掩码 请求: sun % icmpaddrmask sun received mask= ff000000, from 140.252.13.33 sun % icmpaddrmask localhost received mask= ff000000, from 127.0.0.1 上述两种情况下返回的地址掩码对应的都是环回地址,即 A类地址1 2 7 . 0 . 0 . 1。还有,我们 从图2 - 4可以看到,发送给本机 I P地址的数据报( 1 4 0 . 2 5 2 . 1 2 . 3 3)实际上是送到环回接口。 I C M P地址掩码应答必须是收到请求接口的子网掩码(这是因为多接口主机每个接口有不同的 子网掩码),因此两种情况下地址掩码请求都来自于环回接口。 6.4 ICMP时间戳请求与应答 I C M P时间戳请求允许系统向另一个系统查询当前的时间。返回的建议值是自午夜开始计 算的毫秒数,协调的统一时间( Coordinated Universal Time, UTC)(早期的参考手册认为 U T C是格林尼治时间)。这种I C M P报文的好处是它提供了毫秒级的分辨率,而利用其他方法 从别的主机获取的时间(如某些 U n i x系统提供的r d a t e命令)只能提供秒级的分辨率。由于 返回的时间是从午夜开始计算的,因此调用者必须通过其他方法获知当时的日期,这是它的 一个缺陷。 I C M P时间戳请求和应答报文格式如图 6 - 6所示。 图6-6 ICMP时间戳请求和应答报文 第6章 ICMP:Internet控制报文协议使用53 类型(13或14) 代码(0) 标识符 检验和 序列号 20字节发起时间戳 接收时间戳 传送时间戳请求端填写发起时间戳,然后发送报文。应答系统收到请求报文时填写接收时间戳,在 发送应答时填写发送时间戳。但是,实际上,大多数的实现把后面两个字段都设成相同的值 (提供三个字段的原因是可以让发送方分别计算发送请求的时间和发送应答的时间)。 6.4.1 举例 我们可以写一个简单程序(取名为 i c m p t i m e),给某个主机发送 I C M P时间戳请求,并 打印出返回的应答。它在我们的小互联网上运行结果如下: 程序打印出I C M P报文中的三个时间戳:发起时间戳( o r i g)、接收时间戳( r e c v)以 及发送时间戳( x m i t)。正如我们在这个例子以及下面的例子中所看到的那样,所有的主机 把接收时间戳和发送时间戳都设成相同的值。 我们还能计算出往返时间(r t t),它的值是收到应答时的时间值减去发送请求时的时间值。 d i f f e r e n c e的值是接收时间戳值减去发起时间戳值。这些值之间的关系如图6 - 7所示。 图6-7 i c m p t i m e 程序输出的值之间的关系 如果我们相信RT T的值,并且相信RT T的一半用于请求报文的传输,另一半用于应答报文 的传输,那么为了使本机时钟与查询主机的时钟一致,本机时钟需要进行调整,调整值是 d i f f e r e n c e减去RT T的一半。在前面的例子中, b s d i的时钟比s u n的时钟要慢7 ms和8 ms。 由于时间戳的值是自午夜开始计算的毫秒数,即 U T C,因此它们的值始终小于86 400 000 ( 2 4×6 0×6 0×1 0 0 0 )。这些例子都是在下午 4 : 0 0以前运行的,并且在一个比 U T C慢7个小时的 时区,因此它们的值比82 800 000(2 3 0 0小时)要大是有道理的。 如果对主机b s d i重复运行该程序数次,我们发现接收时间戳和发送时间戳的最后一位数 总是0。这是因为该版本的软件( 0 . 9 . 4版)只能提供1 0 m s的时间分辨率(说明参见附录 B)。 如果对主机s v r 4运行该程序两次,我们发现 S V R 4时间戳的最后三位数始终为 0: 由于某种原因, S V R 4在I C M P时间戳中不提供毫秒级的分辨率。这样,对秒以下的时间 差调整将不起任何作用。 如果我们对子网 1 4 0 . 2 5 2 . 1上的其他主机运行该程序,结果表明其中一台主机的时钟与 54使用TCP/IP详解,卷1:协议 发起 请求 接收 传送 应答s u n相差3 . 7秒,而另一个主机时钟相差近 7 5秒: 另一个令人感兴趣的例子是路由器 g a t e w a y(一个C i s c o路由器)。它表明,当系统返回 一个非标准时间戳值时(不是自午夜开始计算的毫秒数, U T C),它就用32 bit时间戳中的高 位来表示。我们的程序证明了一点,在尖括号中打印出了接收和发送的时间戳值(在关闭高 位之后)。另外,不能计算发起时间戳和接收时间戳之间的时间差,因为它们的单位不一致。 如果我们在这台主机上运行该程序数次,会发现时间戳值显然具有毫秒级的分辨率,而 且是从某个起始点开始计算的毫秒数,但是起始点并不是午夜 U T C(例如,可能是从路由器 引导时开始计数的毫秒数)。 作为最后一个例子,我们来比较 s u n主机和另一个已知是准确的系统时钟— 一个N T P stratum 1服务器(下面我们会更多地讨论 N T P,网络时间协议)。 如果我们把d i f f e r e n c e的值减去RT T的一半,结果表明s u n主机上的时钟要快3 8 . 5~51.5 ms。 6.4.2 另一种方法 还可以用另一种方法来获得时间和日期。 1) 在1 . 1 2节中描述了日期服务程序和时间服务程序。前者是以人们可读的格式返回当前 的时间和日期,是一行A S C I I字符。可以用t e l n e t命令来验证这个服务: 另一方面,时间服务程序返回的是一个 3 2 b i t的二制进数值,表示自 U T C,1 9 0 0年1月1日 午夜起算的秒数。这个程序是以秒为单位提供的日期和时间(前面我们提过的 r d a t e命令 使用的是T C P时间服务程序)。 2) 严格的计时器使用网络时间协议( N T P),该协议在 RFC 1305中给出了描述 [ M i l l s 1 9 9 2 ]。这个协议采用先进的技术来保证 L A N或WA N上的一组系统的时钟误差在毫秒 级以内。对计算机精确时间感兴趣的读者应该阅读这份 R F C文档。 3) 开放软件基金会( O S F)的分布式计算环境( D C E)定义了分布式时间服务( D T S), 第6章 ICMP:Internet控制报文协议使用55 前三行是Telnet客户的输出 这是日期时间服务器的输出 这也是Telnet客户的输出它也提供计算机之间的时钟同步。文献 [ R o s e n b e rg, Kenney and Fisher 1992]提供了该服 务的其他细节描述。 4) 伯克利大学的 U n i x系统提供守护程序 t i m e d( 8 ),来同步局域网上的系统时钟。不像 N T P和D T S,t i m e d不在广域网范围内工作。 6.5 ICMP端口不可达差错 最后两小节我们来讨论 I C M P查询报文— 地址掩码和时间戳查询及应答。现在来分析一 种I C M P差错报文,即端口不可达报文,它是 I C M P目的不可到达报文中的一种,以此来看一 看I C M P差错报文中所附加的信息。使用 U D P(见第11章)来查看它。 U D P的规则之一是,如果收到一份 U D P数据报而目的端口与某个正在使用的进程不相符, 那么U D P返回一个I C M P不可达报文。可以用 T F T P来强制生成一个端口不可达报文( T F T P将 在第1 5章描述)。 对于T F T P服务器来说, U D P的公共端口号是 6 9。但是大多数的 T F T P客户程序允许用 c o n n e c t命令来指定一个不同的端口号。这里,我们就用它来指定 8 8 8 8端口: c o n n e c t命令首先指定要连接的主机名及其端口号,接着用 g e t命令来取文件。敲入 g e t 命令后,一份U D P数据报就发送到主机s v r 4上的8 8 8 8端口。t c p d u m p命令引起的报文交换结果 如图6 - 8所示。 图6-8 由TFTP产生的ICMP端口不可达差错 在U D P数据报送到s v r 4之前,要先发送一份A R P请求来确定它的硬件地址(第 1行)。接着 返回A R P应答(第2行),然后才发送U D P数据报(第3行)(在t c p d u m p的输出中保留A R P请 求和应答是为了提醒我们,这些报文交换可能在第一个 I P数据报从一个主机发送到另一个主 机之前是必需的。在本书以后的章节中,如果这些报文与讨论的题目不相关,那么我们将省 略它们)。 一个I C M P端口不可达差错是立刻返回的(第 4行)。但是,T F T P客户程序看上去似乎忽 略了这个I C M P报文,而在5秒钟之后又发送了另一份 U D P数据报(第5行)。在客户程序放弃 56使用TCP/IP详解,卷1:协议 指定主机名和端口号 试图得到一个文件 大约25秒后之前重发了三次。 注意,I C M P报文是在主机之间交换的,而不用目的端口号,而每个 2 0字节的U D P数据报 则是从一个特定端口(2 9 2 4)发送到另一个特定端口( 8 8 8 8)。 跟在每个U D P后面的数字2 0指的是U D P数据报中的数据长度。在这个例子中, 2 0字节包 括T F T P的2个字节的操作代码, 9个字节以空字符结束的文件名 t e m p . f o o,以及9个字节以 空字符结束的字符串n e t a s c i i(T F T P报文的详细格式参见图1 5 - 1)。 如果用- e选项运行同样的例子,我们可以看到每个返回的 I C M P端口不可达报文的完整长 度。这里的长度为7 0字节,各字段分配如图6 - 9所示。 图6-9 “UDP端口不可达”例子中返回的ICMP报文 I C M P的一个规则是, I C M P差错报文(参见图 6 - 3的最后一列)必须包括生成该差错报文 的数据报I P首部(包含任何选项),还必须至少包括跟在该 I P首部后面的前 8个字节。在我们 的例子中,跟在I P首部后面的前8个字节包含U D P的首部(见图11 - 2)。 一个重要的事实是包含在 U D P首部中的内容是源端口号和目的端口号。就是由于目的端 口号(8 8 8 8)才导致产生了 I C M P端口不可达的差错报文。接收 I C M P的系统可以根据源端口 号(2 9 2 4)来把差错报文与某个特定的用户进程相关联(在本例中是 T F T P客户程序)。 导致差错的数据报中的 I P首部要被送回的原因是因为 I P首部中包含了协议字段,使得 I C M P可以知道如何解释后面的 8个字节(在本例中是 U D P首部)。如果我们来查看 T C P首部 (图1 7 - 2),可以发现源端口和目的端口被包含在 T C P首部的前8个字节中。 I C M P不可达报文的一般格式如图 6 - 1 0所示。 图6-10 ICMP不可达报文 在图6 - 3中,我们注意到有1 6种不同类型的I C M P不可达报文,代码分别从0到1 5。I C M P端口 不可达差错代码是3。另外,尽管图6 - 1 0指出了在I C M P报文中的第二个32 bit字必须为0,但是当 代码为4时(“需要分片但设置了不分片比特”),路径M T U发现机制(2 . 9节)却允许路由器把外 第6章 ICMP:Internet控制报文协议使用57 IP数据报 ICMP报文 ICMP报文的数据部分 产生差错的数据报IP首部 UDP首部 8字节20字节8字节20字节14字节 以太网首部 IP首部 ICMP首部 类型(3) 代码(0~15) 检验和 未用(必须为0) IP首部(包括选项)+原始IP数据报中数据的前8字节 8字节出接口的MTU填在这个32 bit字的低16 bit中。我们在11.6节中给出了一个这种差错的例子。 尽管I C M P规则允许系统返回多于8个字节的产生差错的I P数据报中的数据,但是大多 数从伯克利派生出来的系统只返回 8个字节。 Solaris 2.2的i p _ i c m p _ r e t u r n _ d a t a _ b y t e s选项默认条件下返回前6 4个字节(E . 4节)。 t c p d u m p时间系列 在本书的后面章节中,我们还要以时间系列的格式给出t c p d u m p命令的输出,如图6 - 11所示。 图6-11 发送到无效端口的TFTP请求的时间系列 时间随着向下而递增,在图左边的时间标记与 t c p d u m p命令的输出是相同的(见图 6 - 8)。 位于图顶部的标记是通信双方的主机名和端口号。需要指出的是,随着页面向下的y坐标轴与真 正的时间值不是成比例的。当出现一个有意义的时间段时,在本例中是每5秒之间的重发,我 们就在时间系列的两侧作上标记。当U D P或T C P数据正在被传送时,我们用粗线的行来表示。 当I C M P报文返回时,为什么 T F T P客户程序还要继续重发请求呢?这是由于网络编程中 的一个因素,即B S D系统不把从插口( s o c k e t )接收到的I C M P报文中的U D P数据通知用户进程, 除非该进程已经发送了一个 c o n n e c t命令给该插口。标准的 BSD TFTP客户程序并不发送 c o n n e c t命令,因此它永远也不会收到 I C M P差错报文的通知。 这里需要注意的另一点是 T F T P客户程序所采用的不太好的超时重传算法。它只是假定 5 秒是足够的,因此每隔 5秒就重传一次,总共需要 2 5秒钟的时间。在后面我们将看到 T C P有一 个较好的超时重发算法。 58使用TCP/IP详解,卷1:协议T F T P客户程序所采用的超时重传算法已被R F C所禁用。不过,在作者所在子网上 的三个系统以及Solaris 2.2仍然在使用它。AIX 3.2.2采用一种指数退避方法来设置超时 值,分别在0、5、1 5和3 5秒时重发报文,这正是所推荐的方法。我们将在第 2 1章更详 细地讨论超时问题。 最后需要指出的是,I C M P报文是在发送U D P数据报3.5 ms后返回的,这与第7章我们所看 到的P i n g应答的往返时间差不多。 6.6 ICMP报文的4.4BSD处理 由于I C M P覆盖的范围很广,从致命差错到信息差错,因此即使在一个给定的系统实现中, 对每个I C M P报文的处理都是不相同的。图 6 - 1 2的内容与图6 - 3相同,它显示的是 4 . 4 B S D系统 对每个可能的I C M P报文的处理方法。 图6-12 4.4BSD系统对ICMP报文的处理 第6章 ICMP:Internet控制报文协议使用59 类 型 代 码 描 述 处 理 方 法 0 0 回显应答 用户进程 3 目的不可达: 0 网络不可达 “无路由到达主机” 1 主机不可达 “无路由到达主机” 2 协议不可达 “连接被拒绝” 3 端口不可达 “连接被拒绝” 4 需要进行分片但设置了不分片比特 D F “报文太长” 5 源站选路失败 “无路由到达主机” 6 目的网络不认识 “无路由到达主机” 7 目的主机不认识 “无路由到达主机” 8 源主机被隔离(作废不用) “无路由到达主机” 9 目的网络被强制禁止 “无路由到达主机” 1 0 目的主机被强制禁止 “无路由到达主机” 11 由于服务类型 TO S,网络不可达 “无路由到达主机” 1 2 由于服务类型 TO S,主机不可达 “无路由到达主机” 1 3 由于过滤,通信被强制禁止 (忽略) 1 4 主机越权 (忽略) 1 5 优先权中止生效 (忽略) 4 0 源站被抑制( q u e n c h ) T C P由内核处理, U D P则忽略 5 重定向 0 对网络重定向 内核更新路由表 1 对主机重定向 内核更新路由表 2 对服务类型和网络重定向 内核更新路由表 3 对服务类型和主机重定向 内核更新路由表 8 0 回显请求 9 0 路由器通告 用户进程 1 0 0 路由器请求 用户进程 11 超时: 0 传输期间生存时间为0 用户进程 1 在数据报组装期间生存时间为 0 用户进程 1 2 参数问题: 0 坏的I P首部(包括各种差错) “协议不可用” 1 缺少必需的选项 “协议不可用” 1 3 0 时间戳请求 内核产生应答 1 4 0 时间戳应答 用户进程 1 5 0 信息请求(作废不用) (忽略) 1 6 0 信息应答(作废不用) 用户进程 1 7 0 地址掩码请求 内核产生应答 1 8 0 地址掩码应答 用户进程如果最后一列标明是“内核”,那么I C M P就由内核来处理。如果最后一列指明是“用户 进程”,那么报文就被传送到所有在内核中登记的用户进程,以读取收到的 I C M P报文。如果 不存在任何这样的用户进程,那么报文就悄悄地被丢弃(这些用户进程还会收到所有其他类 型的I C M P报文的拷贝,虽然它们应该由内核来处理,当然用户进程只有在内核处理以后才能 收到这些报文)。有一些报文完全被忽略。最后,如果最后一列标明的是引号内的一串字符, 那么它就是对应的 U n i x差错。其中一些差错,如 T C P对发送端关闭的处理等,我们将在以后 的章节中对它们进行讨论。 6.7 小结 本章对每个系统都必须包括的 I n t e r n e t控制报文协议进行了讨论。图 6 - 3列出了所有的 I C M P报文类型,其中大多数都将在以后的章节中加以讨论。 我们详细讨论了I C M P地址掩码请求和应答以及时间戳请求和应答。这些是典型的请求— 应答报文。二者在 I C M P报文中都有标识符和序列号。发送端应用程序在标识字段内存入一个 唯一的数值,以区别于其他进程的应答。序列号字段使得客户程序可以在应答和请求之间进 行匹配。 我们还讨论了I C M P端口不可达差错,一种常见的 I C M P差错。对返回的I C M P差错信息进 行了分析:导致差错的 I P数据报的首部及后续 8个字节。这个信息对于 I C M P差错的接收方来 说是必要的,可以更多地了解导致差错的原因。这是因为 T C P和U D P都在它们的首部前 8个字 节中存入源端口号和目的端口号。 最后,我们第一次给出了按时间先后的 t c p d u m p输出,这种表示方式在本书后面的章节 中会经常用到。 习题 6.1 在6 . 2节的末尾,我们列出了 5种不发送I C M P差错报文的特殊条件。如果这些条件不满足 而我们又在局域网上向一个似乎不存在的端口号发送一份广播 U D P数据报,这时会发生 什么样的情况? 6.2 阅读RFC [Braden 1989a],注意生成一个 I C M P端口不可达差错是否为“必须”,“应该” 或者“可能”。这些信息所在的页码和章节是多少? 6.3 阅读RFC 1349 [Almquist 1992],看看I P的服务类型字段(见图3 - 2)是如何被I C M P设置 的? 6.4 如果你的系统提供n e t s t a t命令,请用它来查看接收和发送的 I C M P报文类型。 60使用TCP/IP详解,卷1:协议第7章 Ping程序 7.1 引言 “p i n g”这个名字源于声纳定位操作。 P i n g程序由Mike Muuss编写,目的是为了测试另一 台主机是否可达。该程序发送一份 I C M P回显请求报文给主机,并等待返回 I C M P回显应答 (图6 - 3列出了所有的I C M P报文类型)。 一般来说,如果不能 P i n g到某台主机,那么就不能 Te l n e t或者F T P到那台主机。反过来, 如果不能Te l n e t到某台主机,那么通常可以用 P i n g程序来确定问题出在哪里。 P i n g程序还能测 出到这台主机的往返时间,以表明该主机离我们有“多远”。 在本章中,我们将使用 P i n g程序作为诊断工具来深入剖析 I C M P。P i n g还给我们提供了检 测I P记录路由和时间戳选项的机会。文献 [Stevens 1990]的第11章提供了P i n g程序的源代码。 几年前我们还可以作出这样没有限定的断言,如果不能 P i n g到某台主机,那么就 不能Te l n e t或F T P到那台主机。随着I n t e r n e t安全意识的增强,出现了提供访问控制清单 的路由器和防火墙,那么像这样没有限定的断言就不再成立了。一台主机的可达性可 能不只取决于I P层是否可达,还取决于使用何种协议以及端口号。P i n g程序的运行结果 可能显示某台主机不可达,但我们可以用Te l n e t远程登录到该台主机的2 5号端口(邮件 服务器)。 7.2 Ping程序 我们称发送回显请求的 p i n g程序为客户,而称被 p i n g的主机为服务器。大多数的 T C P / I P 实现都在内核中直接支持 P i n g服务器— 这种服务器不是一个用户进程(在第 6章中描述的两 种I C M P查询服务,地址掩码和时间戳请求,也都是直接在内核中进行处理的)。 I C M P回显请求和回显应答报文如图 7 - 1所示。 图7-1 ICMP回显请求和回显应答报文格式 对于其他类型的I C M P查询报文,服务器必须响应标识符和序列号字段。另外,客户发送 的选项数据必须回显,假设客户对这些信息都会感兴趣。 类型(0或8) 代码(0) 标识符 选项数据 检验和 序号 8字节U n i x系统在实现p i n g程序时是把I C M P报文中的标识符字段置成发送进程的 I D号。这样 即使在同一台主机上同时运行了多个 p i n g程序实例,p i n g程序也可以识别出返回的信息。 序列号从0开始,每发送一次新的回显请求就加 1。p i n g程序打印出返回的每个分组的序 列号,允许我们查看是否有分组丢失、失序或重复。 I P是一种最好的数据报传递服务,因此 这三个条件都有可能发生。 旧版本的p i n g程序曾经以这种模式运行,即每秒发送一个回显请求,并打印出返回的每 个回显应答。但是,新版本的实现需要加上- s选项才能以这种模式运行。默认情况下,新版 本的p i n g程序只发送一个回显请求。如果收到回显应答,则输出“ host is alive”;否则,在 2 0秒内没有收到应答就输出“ no answer(没有回答)”。 7.2.1 LAN输出 在局域网上运行p i n g程序的结果输出一般有如下格式: 当返回I C M P回显应答时,要打印出序列号和 T T L,并计算往返时间( T T L位于I P首部中 的生存时间字段。当前的 B S D系统中的 p i n g程序每次收到回显应答时都打印出收到的 T T L — 有些系统并不这样做。我们将在第 8章中通过t r a c e r o u t e程序来介绍T T L的用法)。 从上面的输出中可以看出,回显应答是以发送的次序返回的( 0,1,2等)。 p i n g程序通过在I C M P报文数据中存放发送请求的时间值来计算往返时间。当应答返回 时,用当前时间减去存放在 I C M P报文中的时间值,即是往返时间。注意,在发送端 b s d i上, 往返时间的计算结果都为 0 ms。这是因为程序使用的计时器分辨率低的原因。 B S D / 3 8 6版本 0 . 9 . 4系统只能提供10 ms级的计时器(在附录B中有更详细的介绍)。在后面的章节中,当我们 在具有较高分辨率计时器的系统上( S u n)查看t c p d u m p输出时会发现,I C M P回显请求和回 显应答的时间差在4 ms以下。 输出的第一行包括目的主机的 I P地址,尽管指定的是它的名字( s v r 4)。这说明名字已 经经过解析器被转换成 I P地址了。我们将在第 1 4章介绍解析器和 D N S。现在,我们发现,如 果敲入p i n g命令,几秒钟过后会在第 1行打印出I P地址,D N S就是利用这段时间来确定主机 名所对应的I P地址。 本例中的t c p d u m p输出如图7 - 2所示。 从发送回显请求到收到回显应答,时间间隔始终为 3.7 ms。还可以看到,回显请求大约每 隔1秒钟发送一次。 通常,第1个往返时间值要比其他的大。这是由于目的端的硬件地址不在 A R P高速缓存中 62使用TCP/IP详解,卷1:协议 键入中断键来停止显示的缘故。正如我们在第 4章中看到的那样,在发送第一个回显请求之前要发送一个 A R P请求并 接收A R P应答,这需要花费几毫秒的时间。下面的例子说明了这一点: 第1个RT T中多出的3 ms很可能就是因为发送A R P请求和接收A R P应答所花费的时间。 这个例子运行在s u n主机上,它提供的是具有微秒级分辨率的计时器,但是 p i n g程序只 能打印出毫秒级的往返时间。在前面运行于 BSD/386 0.9.4版上的例子中,打印出来的往返时 间值为0 ms,这是因为计时器只能提供 1 0 m s的误差。下面的例子是BSD/386 1.0版的输出,它 提供的计时器也具有微秒级的分辨率,因此, p i n g程序的输出结果也具有较高的分辨率。 7.2.2 WAN输出 在一个广域网上,结果会有很大的不同。下面的例子是在某个工作日的下午即 I n t e r n e t具 第7章 Ping程序使用63 保证ARP高速缓存是空的 键入中断键来停止显示 键入中断键来停止显示 图7-2 在LAN上运行ping程序的结果有正常通信量时的运行结果: 这里,序列号为1、2、3、4、6、1 0、11、1 2和1 3的回显请求或回显应答在某个地方丢失 了。另外,我们注意到往返时间发生了很大的变化(像 5 2 %这样高的分组丢失率是不正常的。 即使是在工作日的下午,对于 I n t e r n e t来说也是不正常的)。 通过广域网还有可能看到重复的分组(即相同序列号的分组被打印两次或更多次),失序 的分组(序列号为N + 1的分组在序列号为N的分组之前被打印)。 7.2.3 线路SLIP链接 让我们再来看看S L I P链路上的往返时间,因为它们经常运行于低速的异步方式,如 9 6 0 0 b / s或更低。回想我们在 2 . 1 0节计算的串行线路吞吐量。针对这个例子,我们把主机 b s d i和 s l i p之间的S L I P链路传输速率设置为1200 b/s。 下面我们可以来估计往返时间。首先,从前面的 P i n g程序输出例子中可以注意到,默认 情况下发送的I C M P报文有5 6个字节。再加上2 0个字节的I P首部和8个字节的I C M P首部,I P数 据报的总长度为 8 4字节(我们可以运行 t c p d u m p-e命令查看以太网数据帧来验证这一点)。 另外,从2 . 4节可以知道,至少要增加两个额外的字节:在数据报的开始和结尾加上 E N D字符。 此外,S L I P帧还有可能再增加一些字节,但这取决于数据报中每个字节的值。对于 1200 b/s这 个速率来说,由于每个字节含有 8 bit数据、1 bit起始位和1 bit结束位,因此传输速率是每秒 1 2 0个字节,或者说每个字节 8.33 ms。所以我们可以估计需要 1 4 3 3(8 6×8 . 3 3×2)m s(乘2 是因为我们计算的是往返时间)。 下面的输出证实了我们的计算: (对于S V R 4来说,如果每秒钟发送一次请求则必须带- s选项)。往返时间大约是 1 . 5秒, 但是程序仍然每间隔 1秒钟发送一次 I C M P回显请求。这说明在第 1个回显应答返回之前 (1 . 4 8 0秒时刻)就已经发送了两次回显请求(分别在 0秒和1秒时刻)。这就是为什么总结行指 64使用TCP/IP详解,卷1:协议 键入中断来停止显示出丢失了一个分组。实际上分组并未丢失,很可能仍然在返回的途中。 我们在第8章讨论t r a c e r o u t e程序时将回头再讨论这种低速的 S L I P链路。 7.2.4 拨号SLIP链路 对于拔号 S L I P链路来说,情况有些变化,因为在链路的两端增加了调制解调器。用在 s u n和n e t b系统之间的调制解调器提供的是 V. 3 2调制方式( 9600 b/s)、V. 4 2错误控制方式 (也称作L A P - M)以及V. 4 2 b i s数据压缩方式。这表明我们针对线路链路参数进行的简单计算 不再准确了。 很多因素都有可能影响。调制解调器带来了时延。随着数据的压缩,分组长度可能会减 小,但是由于使用了错误控制协议,分组长度又可能会增加。另外,接收端的调制解调器只 能在验证了循环检验字符(检验和)后才能释放收到的数据。最后,我们还要处理每一端的 计算机异步串行接口,许多操作系统只能在固定的时间间隔内,或者收到若干字符后才去读 这些接口。 作为一个例子,我们在s u n主机上p i n g主机g e m i n i,输出结果如下: 注意,第1个RT T不是10 ms的整数倍,但是其他行都是 10 ms的整数倍。如果我们运行该 程序若干次,发现每次结果都是这样(这并不是由 s u n主机上的时钟分辨率造成的结果,因 为根据附录B中的测试结果可以知道它的时钟能提供毫秒级的分辨率)。 另外还要注意,第1个RT T要比其他的大,而且依次递减,然后徘徊在 2 8 0~300 ms之间。 我们让它运行1 ~ 2分钟,RT T一直处于这个范围,不会低于 260 ms。如果我们以9600 b/s的速 率计算RT T(习题7 . 2),那么观察到的值应该大约是估计值的 1 . 5倍。 如果运行p i n g程序6 0秒钟并计算观察到的 RT T的平均值,我们发现在 V. 4 2和V. 4 2 b i s模式 下平均值为277 ms(这比上个例子打印出来的平均值要好,因为运行时间较长,这样就把开 始较长的时间平摊了)。如果我们关闭V. 4 2 b i s数据压缩方式,平均值为330 ms。如果我们关闭 V. 4 2错误控制方式(它同时也关闭了 V. 4 2 b i s数据压缩方式),平均值为300 ms。这些调制解调 器的参数对RT T的影响很大,使用错误控制和数据压缩方式似乎效果最好。 7.3 IP记录路由选项 p i n g程序为我们提供了查看 I P记录路由(R R)选项的机会。大多数不同版本的 p i n g程 第7章 Ping程序使用65序都提供-R选项,以提供记录路由的功能。它使得 p i n g程序在发送出去的I P数据报中设置I P R R选项(该I P数据报包含I C M P回显请求报文)。这样,每个处理该数据报的路由器都把它的 I P地址放入选项字段中。当数据报到达目的端时, I P地址清单应该复制到 I C M P回显应答中, 这样返回途中所经过的路由器地址也被加入清单中。当 p i n g程序收到回显应答时,它就打印 出这份I P地址清单。 这个过程听起来简单,但存在一些缺陷。源端主机生成 R R选项,中间路由器对 R R选项的 处理,以及把 I C M P回显请求中的 R R清单复制到I C M P回显应答中,所有这些都是选项功能。 幸运的是,现在的大多数系统都支持这些选项功能,只是有一些系统不把 I C M P请求中的I P清 单复制到I C M P应答中。 但是,最大的问题是 I P首部中只有有限的空间来存放 I P地址。我们从图3 - 1可以看到,I P 首部中的首部长度字段只有 4 bit,因此整个I P首部最长只能包括1 5个32 bit长的字(即6 0个字 节)。由于I P首部固定长度为 2 0字节,R R选项用去3个字节(下面我们再讨论),这样只剩下 3 7个字节( 6 0-2 0-3)来存放 I P地址清单,也就是说只能存放 9个I P地址。对于早期的 A R PA N E T来说,9个I P地址似乎是很多了,但是现在看来是非常有限的(在第 8章中,我们将 用Tr a c e r o u t e工具来确定数据报的路由)。除了这些缺点,记录路由选项工作得很好,为详细 查看如何处理I P选项提供了一个机会。 I P数据报中的R R选项的一般格式如图7 - 3所示。 图7-3 IP首部中的记录路由选项的一般格式 c o d e是一个字节,指明 I P选项的类型。对于 R R选项来说,它的值为 7。l e n是R R选项总字 节长度,在这种情况下为 3 9(尽管可以为 R R选项设置比最大长度小的长度,但是 p i n g程序 总是提供3 9字节的选项字段,最多可以记录 9个I P地址。由于I P首部中留给选项的空间有限, 它一般情况都设置成最大长度)。 p t r称作指针字段。它是一个基于 1的指针,指向存放下一个 I P地址的位置。它的最小值为 4,指向存放第一个 I P地址的位置。随着每个 I P地址存入清单,p t r的值分别为8,1 2,1 6,最 大到3 6。当记录下9个I P地址后,p t r的值为4 0,表示清单已满。 当路由器(根据定义应该是多穴的)在清单中记录 I P地址时,它应该记录哪个地址呢? 是入口地址还是出口地址?为此, RFC 791 [Postel 1981a]指定路由器记录出口 I P地址。我们 在后面将看到,当原始主机(运行 p i n g程序的主机)收到带有 R R选项的I C M P回显应答时, 它也要把它的入口I P地址放入清单中。 7.3.1 通常的例子 我们举一个用R R选项运行p i n g程序的例子,在主机s v r 4上运行p i n g程序到主机s l i p。 一个中间路由器( b s d i )将处理这个数据报。下面是 s v r 4的输出结果: 66使用TCP/IP详解,卷1:协议 30字节 4字节 4字节 4字节 4字节分组所经过的四站如图 7 - 4所示(每个方向各有两站),每一站都把自己的 I P地址加入R R 清单。 图7-4 带有记录路由选项的ping程序 路由器b s d i在不同方向上分别加入了不同的 I P地址。它始终是把出口的 I P地址加入清单。 我们还可以看到,当 I C M P回显应答到达原始系统( s v r 4)时,它把自己的入口 I P地址也加入 清单中。 还可以通过运行带有- v选项的t c p d u m p命令来查看主机s u n上进行的分组交换(参见 I P 选项)。输出如图7 - 5所示。 图7-5 记录路由选项的t c p d u m p 输出 输出中o p t l e n = 4 0表示在I P首部中有4 0个字节的选项空间(I P首部长度必须为4字节的整数 倍)。R R { 3 9 }的意思是记录路由选项已被设置,它的长度字段是 3 9。然后是9个I P地址,符号 “#”用来标记 R R选项中的p t r字段所指向的 I P地址。由于我们是在主机 s u n上观察这些分组 (参见图7 - 4),因此所能看到 I C M P回显请求中的 I P地址清单是空的,而 I C M P回显应答中有 3 个I P地址。我们省略了t c p d u m p输出中的其他行,因为它们与图 7 - 5基本一致。 位于路由信息末尾的标记E O L表示I P选项“end of list(清单结束)”的值。E O L选项的值 可以为0。这时表示3 9个字节的R R数据位于I P首部中的4 0字节空间中。由于在数据报发送之 前空间选项被设置为 0,因此跟在3 9个字节的R R数据之后的0字符就被解释为E O L。这正是我 第7章 Ping程序使用67 以太网 空表们所希望的结果。如果在 I P首部中的选项字段中有多个选项,在开始下一个选项之前必须填 入空白字符,另外还可以用另一个值为 1的特殊字符N O P(“no operation”)。 在图7 - 5中,S V R 4把回显请求中的T T L字段设为3 2,B S D / 3 8 6设为2 5 5(它打印出 的值为2 5 4是因为路由器b s d i已经将其减去1)。新的系统都把I C M P报文中的T T L设为最 大值(255)。 在作者使用的三个T C P / I P系统中,B S D / 3 8 6和S V R 4都支持记录路由选项。这就是 说,当转发数据报时,它们都能正确地更新R R清单,而且能正确地把接收到的I C M P回 显请求中的R R清单复制到出口I C M P回显应答中。虽然SunOS 4.1.3在转发一个数据报 时能正确更新RR清单,但是不能复制RR清单。Solaris 2.x对这个问题已作了修改。 7.3.2 异常的输出 下面的例子是作者观察到的,把它作为第 9章讨论 I C M P间接报文的起点。在子网 1 4 0 . 2 5 2 . 1上p i n g主机a i x(在主机s u n上通过拨号S L I P连接可以访问),并带有记录路由选项。 在s l i p主机上运行有如下输出结果: 我们已经在主机b s d i上运行过这个例子。现在选择 s l i p来运行它,观察 R R清单中所有 的9个I P地址。 在输出中令人感到疑惑的是,为什么传出的数据报( I C M P回显请求)直接从 n e t b传到 a i x,而返回的数据报( I C M P回显应答)却从 a i x开始经路由器g a t e w a y再到n e t b?这里 看到的正是下面将要描述的 I P选路的一个特点。数据报经过的路由如图 7 - 6所示。 问题是a i x不知道要把目的地为子网 1 4 0 . 2 5 2 . 1 3的I P数据报发到主机n e t b上。相反,a i x 在它的路由表中有一个默认项,它指明当没有明确某个目的主机的路由时,就把所有的数据 报发往默认项指定的路由器 g a t e w a y。路由器g a t e w a y比子网1 4 0 . 2 5 2 . 1上的任何主机都具备 更强的选路能力(在这个以太网上有超过 1 5 0台主机,每台主机的路由表中都有一个默认项指 向路由器g a t e w a y,这样就不用在每台主机上都运行一个选路守护程序)。 这里没有应答的一个问题是为什么 g a t e w a y不直接发送I C M P报文重定向到a i x(9 . 5节), 以更新它的路由表?由于某种原因(很可能是由于数据报产生的重定向是一份 I C M P回显请求 报文),重定向并没有产生。但是如果我们用 Te l n e t登录到a i x上的d a y t i m e服务器,I C M P就会 68使用TCP/IP详解,卷1:协议 为什么用这个路由器?产生重定向,因而它在 a i x上的路由表也随之更新。如果接着执行 p i n g程序并带有记录路由 选项,其路由显示表明数据报从 n e t b到a i x,然后返回n e t b,而不再经过路由器g a t e w a y。 在9 . 5节中将更详细地讨论I C M P重定向的问题。 图7-6 运行带有记录路由选项的p i n g 程序,显示IP选路的特点 7.4 IP时间戳选项 I P时间戳选项与记录路由选项类似。 I P时间戳选项的格式如图 7 - 7所示(请与图7 - 3进行比 较)。 图7-7 IP首部中时间戳选项的一般格式 时间戳选项的代码为 0 x 4 4。其他两个字段 l e n和p t r与记录路由选项相同:选项的总长度 (一般为3 6或4 0)和指向下一个可用空间的指针( 5,9,1 3等)。 接下来的两个字段是 4 bit的值:O F表示溢出字段,F L表示标志字段。时间戳选项的操作 根据标志字段来进行,如图 7 - 8所示。 图7-8 时间戳选项不同标志字段值的意义 如果路由器由于没有空间而不能增加时间戳选项,那么它将增加溢出字段的值。 第7章 Ping程序使用69 ping目的主机 以太网 以太网 空表 ping客户端 时间戳 时间戳 时间戳 时间戳 4字节4字节4字节 40字节 4字节 标 志 描 述 0 只记录时间戳,正如我们在图 7 - 7看到的那样 1 每台路由器都记录它的I P地址和时间戳。在选项列表中只有存放 4对地址和 时间戳的空间 3 发送端对选项列表进行初始化,存放了 4个I P地址和4个取值为 0的时间戳 值。只有当列表中的下一个 I P地址与当前路由器地址相匹配时,才记录它的 时间戳时间戳的取值一般为自 U T C午夜开始计的毫秒数,与 I C M P时间戳请求和应答相类似。如 果路由器不使用这种格式,它就可以插入任何它使用的时间表示格式,但是必须打开时间戳 中的高位以表明为非标准值。 与我们遇到的记录路由选项所受到的限制相比,时间戳选项遇到情况要更坏一些。如果 我们要同时记录 I P地址和时间戳(标志位为 1),那么就可以同时存入其中的四对值。只记录 时间戳是没有用处的,因为我们没有标明时间戳与路由器之间的对应关系(除非有一个永远 不变的拓扑结构)。标志值取3会更好一些,因为我们可以插入时间戳的路由器。一个更为基 本的问题是,很可能无法控制任何给定路由器上时间戳的正确性。这使得试图用 I P选项来计 算路由器之间的跳站数是徒劳的。我们将看到(第 8章)t r a c e r o u t e程序可以提供一种更好 的方法来计算路由器之间的跳站数。 7.5 小结 p i n g程序是对两个 T C P / I P系统连通性进行测试的基本工具。它只利用 I C M P回显请求和 回显应答报文,而不用经过传输层( T C P / U D P)。P i n g服务器一般在内核中实现I C M P的功能。 我们分析了在 L A N、WA N以及S L I P链路(拨号和线路)上运行 p i n g程序的输出结果, 并对串行线路上的S L I P链路吞吐量进行了计算。我们还讨论并使用了 p i n g程序的I P记录路由 选项。利用该I P选项,可以看到它是如何频繁使用默认路由的。在第 9章我们将再次回到这个 讨论主题。另外,还讨论了 IP 时间戳选项,但它在实际使用时有所限制。 习题 7.1 请画出7 . 2节中p i n g输出的时间线。 7.2 若把b s d i和s l i p主机之间的S L I P链路设置为9600 b/s,请计算这时的RT T。假定默认的 数据是5 6字节。 7.3 当前B S D版中的p i n g程序允许我们为 I C M P报文的数据部分指定一种模式(数据部分的 前8个字节不用来存放模式,因为它要存放发送报文的时间)。如果我们指定的模式为 0 x c 0,请重新计算上一题中的答案(提示:阅读 2 . 4节)。 7.4 使用压缩S L I P(C S L I P,见2 . 5节)是否会影响我们在 7 . 2节中看到的p i n g输出中的时间 值? 7.5 在图2 - 4中,p i n g环回地址与p i n g主机以太网地址会出现什么不同? 70使用TCP/IP详解,卷1:协议第8章 Traceroute程序 8.1 引言 由Van Jacobson编写的Tr a c e r o u t e程序是一个能更深入探索 T C P / I P协议的方便可用的工具。 尽管不能保证从源端发往目的端的两份连续的 I P数据报具有相同的路由,但是大多数情况下 是这样的。Tr a c e r o u t e程序可以让我们看到I P数据报从一台主机传到另一台主机所经过的路由。 Tr a c e r o u t e程序还可以让我们使用I P源路由选项。 使用手册上说:“程序由Steve Deering提议,由Van Jacobson实现,并由许多其他人 根据C. Philip Wood, Tim Seaver 及Ken Adelman等人提出的令人信服的建议或补充意见 进行调试。” 8.2 Traceroute程序的操作 在7 . 3节中,我们描述了 I P记录路由选项( R R)。为什么不使用这个选项而另外开发一个 新的应用程序?有三个方面的原因。首先,原先并不是所有的路由器都支持记录路由选项, 因此该选项在某些路径上不能使用( Tr a c e r o u t e程序不需要中间路由器具备任何特殊的或可选 的功能)。 其次,记录路由一般是单向的选项。发送端设置了该选项,那么接收端不得不从收到的 I P 首部中提取出所有的信息,然后全部返回给发送端。在 7 . 3节中,我们看到大多数P i n g服务器的 实现(内核中的I C M P回显应答功能)把接收到的 R R清单返回,但是这样使得记录下来的 I P地 址翻了一番(一来一回)。这样做会受到一些限制,这一点我们在下一段讨论( Tr a c e r o u t e程序 只需要目的端运行一个U D P模块— 其他不需要任何特殊的服务器应用程序)。 最后一个原因也是最主要的原因是, I P首部中留给选项的空间有限,不能存放当前大多 数的路径。在I P首部选项字段中最多只能存放 9个I P地址。在原先的A R PA N E T中这是足够的, 但是对现在来说是远远不够的。 Tr a c e r o u t e程序使用I C M P报文和I P首部中的T T L字段(生存周期)。T T L字段是由发送端 初始设置一个 8 bit字段。推荐的初始值由分配数字 R F C指定,当前值为 6 4。较老版本的系统 经常初始化为 1 5或3 2。我们从第7章中的一些p i n g程序例子中可以看出,发送 I C M P回显应答 时经常把T T L设为最大值2 5 5。 每个处理数据报的路由器都需要把 T T L的值减1或减去数据报在路由器中停留的秒数。由 于大多数的路由器转发数据报的时延都小于 1秒钟,因此T T L最终成为一个跳站的计数器,所 经过的每个路由器都将其值减 1。 RFC 1009 [Braden and Postel 1987]指出,如果路由器转发数据报的时延超过1秒,那 么它将把T T L值减去所消耗的时间(秒数)。但很少有路由器这么实现。新的路由器需求 文档RFC [Almquist 1993]为此指定它为可选择功能,允许把T T L看成一个跳站计数器。T T L字段的目的是防止数据报在选路时无休止地在网络中流动。例如,当路由器瘫痪或 者两个路由器之间的连接丢失时,选路协议有时会去检测丢失的路由并一直进行下去。在这 段时间内,数据报可能在循环回路被终止。 T T L字段就是在这些循环传递的数据报上加上一 个生存上限。 当路由器收到一份I P数据报,如果其T T L字段是0或1,则路由器不转发该数据报(接收到 这种数据报的目的主机可以将它交给应用程序,这是因为不需要转发该数据报。但是在通常 情况下,系统不应该接收 T T L字段为0的数据报)。相反,路由器将该数据报丢弃,并给信源 机发一份I C M P“超时”信息。Tr a c e r o u t e程序的关键在于包含这份 I C M P信息的I P报文的信源 地址是该路由器的I P地址。 我们现在可以猜想一下Tr a c e r o u t e程序的操作过程。它发送一份 T T L字段为1的I P数据报给 目的主机。处理这份数据报的第一个路由器将 T T L值减1,丢弃该数据报,并发回一份超时 I C M P报文。这样就得到了该路径中的第一个路由器的地址。然后 Tr a c e r o u t e程序发送一份 T T L值为2的数据报,这样我们就可以得到第二个路由器的地址。继续这个过程直至该数据报 到达目的主机。但是目的主机哪怕接收到 T T L值为1的I P数据报,也不会丢弃该数据报并产生 一份超时I C M P报文,这是因为数据报已经到达其最终目的地。那么我们该如何判断是否已经 到达目的主机了呢? Tr a c e r o u t e程序发送一份U D P数据报给目的主机,但它选择一个不可能的值作为 U D P端口 号(大于30 000),使目的主机的任何一个应用程序都不可能使用该端口。因为,当该数据报 到达时,将使目的主机的 U D P模块产生一份“端口不可达”错误(见 6 . 5节)的I C M P报文。 这样,Tr a c e r o u t e程序所要做的就是区分接收到的 I C M P报文是超时还是端口不可达,以判断 什么时候结束。 Tr a c e r o u t e程序必须可以为发送的数据报设置T T L字段。并非所有与T C P / I P接口的 程序都支持这项功能,同时并非所有的实现都支持这项能力,但目前大部分系统都支 持这项功能,并可以运行Tr a c e r o u t e程序。这个程序界面通常要求用户具有超级用户权 限,这意味着它可能需要特殊的权限以在你的主机上运行该程序。 8.3 局域网输出 现在已经做好运行 Tr a c e r o u t e程序并观察其输出的准备了。我们将使用从 s v r 4到s l i p, 经路由器b s d i的简单互联网(见内封面)。b s d i和s l i p之间是9600 b/s的S L I P链路。 输出的第1个无标号行给出了目的主机名和其 I P地址,指出t r a c e r o u t e程序最大的T T L字段 值为3 0。4 0字节的数据报包含2 0字节I P首部、8字节的U D P首部和1 2字节的用户数据(1 2字节 的用户数据包含每发一个数据报就加 1的序列号,送出T T L的副本以及发送数据报的时间)。 输出的后面两行以T T L开始,接下来是主机或路由器名以及其I P地址。对于每个T T L值,发 送3份数据报。每接收到一份I C M P报文,就计算并打印出往返时间。如果在 5秒种内仍未收到3 份数据报的任意一份的响应,则打印一个星号,并发送下一份数据报。在上述输出结果中, T T L字段为1的前3份数据报的I C M P报文分别在20 ms、10 ms和10 ms收到。T T L字段为2的3份数 72使用TCP/IP详解,卷1:协议据报的I C M P报文则在120 ms后收到。由于T T L字段为2到达最终目的主机,因此程序就此停止。 往返时间是由发送主机的 t r a c e r o u t e程序计算的。它是指从 t r a c e r o u t e程序到该路 由器的总往返时间。如果我们对每段路径的时间感兴趣,可以用 T T L字段为N + 1所打印出来的 时间减去T T L字段为N的时间。 图8 - 1给出了t c p d u m p的运行输出结果。正如我们所预想的那样,第 1个发往b s d i的探测 数据报的往返时间是 20 ms、而后面两个数据报往返时间是 10 ms的原因是发生了一次 A R P交 换。t c p d u m p结果证实了确实是这种情况。 图8-1 从svr4到slip的traceroute程序示例的tcpdump输出结果 目的主机U D P端口号最开始设置为 3 3 4 3 5,且每发送一个数据报加 1。可以通过命令行选 项来改变开始的端口号。 U D P数据报包含1 2个字节的用户数据,我们在前面 t r a c e r o u t e程 序输出的4 0字节数据报中已经对其进行了描述。 后面t c p d u m p打印出了 T T L字段为1的I P数据报的注释 [ttl 1]。当T T L值为0或1时, t c p d u m p打印出这条信息,以提示我们数据报中有些不太寻常之处。在这里可以预见到 T T L 值为1;而在其他一些应用程序中,它可以警告我们数据报可能无法到达其最终目的主机。我 们不可能看到路由器传送一个 T T L值为0的数据报,除非发出该数据报的该路由器已经崩溃。 因为b s d i路由器将T T L值减到0,因此我们预计它将发回“传送超时”的 I C M P报文。即 使这份被丢弃的I P报文发送往s l i p,路由器也会发回I C M P报文。 有两种不同的I C M P“超时”报文(见6 . 2节的图6 - 3),它们的I C M P报文中c o d e字段不同。 图8 - 2给出了这种I C M P差错报文的格式。 图8-2 ICMP超时报文 第8章 Traceroute程序使用73 类型 代码(0或1) 检 验 和 未用(必须为0) IP首部(包括选项)+原始IP数据报中数据的前8字节 8字节我们所讨论的I C M P报文是在T T L值等于0时产生的,其c o d e字段为0。 主机在组装分片时可能发生超时,这时,它将发送一份“组装报文超时”的 I C M P报文 (我们将在11 . 5节讨论分片和组装)。这种差错报文将c o d e字段置1。 图8 - 1的第9 ~ 1 4行对应于T T L为2的3份数据报。这 3份报文到达最终目的主机,并产生一 份I C M P端口不可达报文。 计算出S L I P链路的往返时间是很有意义的,就象我们在 7 . 2节中所举的P i n g例子,将链路 值设置为1 2 0 0 b / s一样。发送出的 U D P数据报共4 2个字节,包括 1 2字节的数据、 8字节U D P首 部、2 0字节的I P首部以及(至少) 2字节的S L I P帧(2 . 4节)。但是与P i n g不一样的是,返回的 数据报大小是变化的。从图 6 - 9可以看出,返回的 I C M P报文包含发生差错的数据报的 I P首部 以及紧随该I P首部的8字节数据(在t r a c e r o u t e程序中,即U D P首部)。这样,总共就是 2 0 + 8 + 20 + 8 + 2,即5 8字节。在数据速率为960 b/s的情况下,预计的RT T就是(42 + 58/960), 即104 ms。这个值与s v r 4上所估算出来的110 ms是吻合的。 图8 - 1中的源端口号( 4 2 8 0 4)看起来有些大。 t r a c e r o u t e程序将其发送的U D P数据报 的源端口号设置为 U n i x进程号与 3 2 7 6 8之间的逻辑或值。对于在同一台主机上多次运行 t r a c e r o u t e程序的情况,每个进程都查看 I C M P返回的U D P首部的源端口号,并且只处理那 些对自己发送应答的报文。 关于t r a c e r o u t e程序,还有一些必须指出的事项。首先,并不能保证现在的路由也是 将来所要采用的路由,甚至两份连续的 I P数据报都可能采用不同的路由。如果在运行程序时, 路由发生改变,就会观察到这种变化,这是因为对于一个给定的 T T L,如果其路由发生变化, t r a c e r o u t e程序将打印出新的I P地址。 第二,不能保证 I C M P报文的路由与t r a c e r o u t e程序发送的U D P数据报采用同一路由。 这表明所打印出来的往返时间可能并不能真正体现数据报发出和返回的时间差(如果 U D P数 据报从信源到路由器的时间是 1秒,而I C M P报文用另一条路由返回信源用了 3秒时间,则打印 出来的往返时间是4秒)。 第三,返回的I C M P报文中的信源I P地址是U D P数据报到达的路由器接口的 I P地址。这与 I P记录路由选项(7 . 3节)不同,记录的 I P地址指的是发送接口地址。由于每个定义的路由器 都有2个或更多的接口,因此,从 A主机到B主机上运行t r a c e r o u t e程序和从B主机到A主机 上运行t r a c e r o u t e程序所得到的结果可能是不同的。事实上,如果我们从 s l i p主机到 s v r 4上运行t r a c e r o u t e程序,其输出结果变成了: 这次打印出来的b s d i主机的I P地址是1 4 0 . 2 5 2 . 1 3 . 6 6,对应于S L I P接口;而上次的地址是 1 4 0 . 2 5 2 . 1 3 . 3 5,是以太网接口地址。由于 t r a c e r o u t e程序同时也打印出与 I P地址相关的主 机名,因而主机名也可能变化(在我们的例子中, b s d i上的两个接口都采用相同的名字)。 考虑图8 - 3的情况。它给出了两个局域网通过一个路由器相连的情况。两个路由器通过一 个点对点的链路相连。如果我们在左边 L A N的一个主机上运行 t r a c e r o u t e程序,那么它将 发现路由器的I P地址为i f 1和i f 3。但在另一种情况下,就会发现打印出来的 I P地址为i f 4和i f 2。 i f 2和i f 3有着同样的网络号,而另两个接口则有着不同的网络号。 74使用TCP/IP详解,卷1:协议图8-3 t r a c e r o u t e 程序打印出的接口标识 最后,在广域网情况下,如果 t r a c e r o u t e程序的输出是可读的域名形式,而不是 I P地 址形式,那么会更好理解一些。但是由于 t r a c e r o u t e程序接收到I C M P报文时,它所获得的 唯一信息就是 I P地址,因此,在给定 I P地址的情况下,它做一个“反向域名查看”工作来获 得域名。这就需要路由器或主机的管理员正确配置其反向域名查看功能(并非所有的情况下 都是如此)。我们将在1 4 . 5节描述如何使用D N S将一个I P地址转换成域名。 8.4 广域网输出 前面所给出的小互联网的输出例子对于查看协议运行过程来说是足够了,但对于像全球 互联网这样的大互联网来说,应用 t r a c e r o u t e程序就需要一些更为实际的东西。 图8 - 4是从s u n主机到NIC (Network Information Center)的情况。 图8-4 从s u n 主机到n i c . d d n . m i l 的t r a c e r o u t e 程序 由于运行的这个例子包含文本,非 D D N站点(如,非军方站点)的 N I C已经从 n i c . d d n . m i l转移到r s . i n t e r n i c . n e t,即新的“InterNIC”。 一旦数据报离开t u c . n o a o . e d u网,它们就进入了t e l c o m . a r i z o n a . e d u网络。然后这些 数据报进入NASA Science Internet,n s n . n a s a . g o v。T T L字段为6和7的路由器位于JPL (Jet Propulsion Laboratory)上。T T L字段为11所输出的s u r a . n e t网络位于Southeastern Universities Research Association Network上。T T L字段为1 2的域名G S I是Government Systems, Inc., NIC的运营者。 T T L字段为6的第2个RT T(5 9 0)几乎是其他两个RT T值(2 3 4和2 6 2)的两倍 。它表明I P 路由的动态变化。在发送主机和这个路由器之间发生了使该数据报速度变慢的事件。同样, 我们不能区分是发出的数据报还是返回的 I C M P差错报文被拦截。 T T L字段为3的第1个RT T探测值(2 0 4)比T T L字段为2的第1个探测值(2 3 3)值还小。由 第8章 Traceroute程序使用75 网络1 网络2 网络3 路由器1 路由器2于每个打印出来的RT T值是从发送主机到路由器的总时间,因此这种情况是可能发生的。 图8 - 5的例子是从s u n主机到作者出版商之间的运行例子。 图8-5 从s u n . t u c . n o a o . e d u 主机到a w . c o m 的t r a c e r o u t e 程序 在这个例子中,数据报离开 t e l c o m . a r i z o n a . e d u网络后就进行了地区性的网络 w e s t n e t . n e t ( T T L字段值为 6和7 )。然后进行了由 Advanced Network & Services运营的 N S F N E T主干网,t 3 . a n s . n e t,(T 3是对于主干网采用的45 Mb/s电话线的一般缩写。)最后的网 络是a l t e r . n e t,即a w . c o m与互联网的连接点。 8.5 IP源站选路选项 通常I P路由是动态的,即每个路由器都要判断数据报下面该转发到哪个路由器。应用程 序对此不进行控制,而且通常也并不关心路由。它采用类似 Tr a c e r o u t e程序的工具来发现 实际的路由。 源站选路(source routing)的思想是由发送者指定路由。它可以采用以下两种形式: • 严格的源路由选择。发送端指明 I P数据报所必须采用的确切路由。如果一个路由器发现 源路由所指定的下一个路由器不在其直接连接的网络上,那么它就返回一个“源站路 由失败”的I C M P差错报文。 • 宽松的源站选路。发送端指明了一个数据报经过的 I P地址清单,但是数据报在清单上指 明的任意两个地址之间可以通过其他路由器。 Tr a c e r o u t e程序提供了一个查看源站选路的方法,我们可以在选项中指明源站路由,然后 检查其运行情况。 一些公开的Tr a c e r o u t e程序源代码包中包含指明宽松的源站选路的补丁。但是在标 准版中通常并不包含此项。这些补丁的解释是“ Van Jacobson的原始Tr a c e r o u t e程序 76使用TCP/IP详解,卷1:协议(1 9 8 8年春)支持该特性,但后来因为有人提出会使网关崩溃而将此功能去除。”对于 本章中所给出的例子,作者将这些补丁安装上去,并将它们设置成允许宽松的源站选 路和严格的源站选路。 图8 - 6给出了源站路由选项的格式。 图8-6 IP首部源站路由选项的通用格式 这个格式与我们在图 7 - 3中所示的记录路由选项格式基本一致。不同之处是,对于源站选 路,我们必须在发送I P数据报前填充I P地址清单;而对于记录路由选项,我们需要为 I P地址清 单分配并清空一些空间,并让路由器填充该清单中的各项。同时,对于源站选路,只要为所 需要的I P地址数分配空间并进行初始化,通常其数量小于 9。而对于记录路由选项来说,必须 尽可能地分配空间,以达到 9个地址。 对于宽松的源站选路来说, c o d e字段的值是0 x 8 3;而对于严格的源站选路,其值为 0 x 8 9。 l e n和p t r字段与7 . 3节中所描述的一样。 源站路由选项的实际称呼为“源站及记录路由”(对于宽松的源站选路和严格的源站选路, 分别用L S R R和S S R R表示),这是因为在数据报沿路由发送过程中,对I P地址清单进行了更新。 下面是其运行过程: • 发送主机从应用程序接收源站路由清单,将第 1个表项去掉(它是数据报的最终目的地 址),将剩余的项移到1个项中(如图8 - 6所示),并将原来的目的地址作为清单的最后一 项。指针仍然指向清单的第 1项(即,指针的值为4)。 • 每个处理数据报的路由器检查其是否为数据报的最终地址。如果不是,则正常转发数 据报(在这种情况下,必须指明宽松源站选路,否则就不能接收到该数据报)。 • 如果该路由器是最终目的,且指针不大于路径的长度,那么( 1)由p t r所指定的清单中的 下一个地址就是数据报的最终目的地址;( 2)由外出接口(outgoing interface)相对应的I P 地址取代刚才使用的源地址;( 3)指针加4。 可以用下面这个例子很好地解释上述过程。在图 8 - 7中,我们假设主机 S上的发送应用程 序发送一份数据报给D,指定源路由为R1,R2和R3。 图8-7 IP源路由示例 在上图中,#表示指针字段,其值分别是 4、8、1 2和1 6。长度字段恒为1 5(三个I P地址加 上三个字节首部)。可以看出,每一跳I P数据报中的目的地址都发生改变。 当一个应用程序接收到由信源指定路由的数据时,在发送应答时,应该读出接收到的路 由值,并提供反向路由。 第8章 Traceroute程序使用77 39字节 4字节 4字节 4字节 4字节Host Requirements RFC指明,T C P客户必须能指明源站选路,同时, T C P服务器 必须能够接收源站选路,并且对于该 T C P连接的所有报文段都能采用反向路由。如果 T C P服务器下面接收到一个不同的源站选路,那么新的源站路由将取代旧的源站路 由。 8.5.1 宽松的源站选路的t r a c e r o u t e程序示例 使用t r a c e r o u t e程序的- g选项,可以为宽松的源站选路指明一些中间路由器。采用该 选项可以最多指定8个中间路由器(其个数是 8而不是9的原因是,所使用的编程接口要求最后 的表目是目的主机)。 在图8 - 4中,去往N I C,即n i c . d d n . m i l的路由经过NASA Science Internet。在图8 - 8中, 我们通过指定路由器 e n s s 1 4 2 . U T . w e s t n e t . n e t (192.31.39.21) 作为中间路由器来强制数 据报通过N S F N E T: 图8-8 采用宽松源站选路通过NSFNET到达n i c . d d n . m i l 的t r a c e r o u t e 程序 在这种情况下,看起来路径中共有 1 6跳,其平均RT T大约是350 ms。而图8 - 4的通常选路 则只有1 3跳,其平均RT T约为322 ms。默认路径看起来更好一些(在建立路径时,还需要考 虑其他的一些因素。其中一些必须考虑的因素是所包含网络的组织及政治因素)。 前面我们说看起来有 1 6跳,这是因为将其输出结果与前面的通过 N S F N E T(图8 - 5)的示 例比较,发现在本例采用宽松源路由,选择了 3个路由器(这可能是因为路由器对源站选路数 据 报 产 生 I C M P 超 时 差 错 报 文 上 存 在 一 些 差 错 )。 在 n e t b 和 b u t c h路 由 器 之 间 的 g a t e w a y. t u c . n o a o . e d u路由器丢失了,同时,位于 G a b b y和e n s s 1 4 2 . U T. w e s t . n e t之间的 We s t g a t e . Te l c o m . A r i z o n a . e d u和u u - u a . A Z . w e s t n e t . n e t两个路由器也丢失了。在这些丢失的路由 器上可能发生了与接收到宽松的源站选路选项数据报有关的程序问题。实际上,当采用 N S F N E T时,信源和N I C之间的路径有1 9跳。本章习题8 . 5继续对这些丢失路由器进行讨论。 同时本例也指出了另一个问题。在命令行,我们必须指定路由器 e n s s 1 4 2 . U T. w e s t n e t . n e t的 点分十进制I P地址,而不能以其域名代替。这是因为,反向域名解析( 1 4 . 5节中描述的通过I P 78使用TCP/IP详解,卷1:协议地址返回域名)将域名与 I P地址相关联,但是前向解析(即给出域名返回 I P地址)则无法做 到。在D N S中,前向映射和反向映射是两个独立的文件,而并非所有的管理者都同时拥有这 两个文件。因此,在一个方向是工作正常而另一个方向却失败的情况并不少见。 还有一种以前没有碰到过的情况是在 T T L字段为8的情况下,对于第一个 RT T,打印一个 星号。这表明,发生超时,在 5秒内未收到本次探查的应答信号。 将本图与图8 - 4相比较,还可以得出一个结论,即路由器 n s n - F I X - p e . s u r a . n e t同时 与N S F N E T和NASA Science Internet相连。 8.5.2 严格的源站选路的t r a c e r o u t e程序示例 在作者的t r a c e r o u t e程序版本中,- G选项与前面所描述的- g选项是完全一样的,不 过此时是严格的源站选路而不是宽松的源站选路。我们可以采用这个选项来观察在指明无效 的严格的源站选路时其结果会是什么样的。从图 8 - 5可以看出来,从作者的子网发往 N S F N E T 的数据报的正常路由器顺序是 n e t b,g a t e w a y,b u t c h和g a b b y(为了便于查看,后面所 有的输出结果中,均省略了域名后缀 . t u c . n o a o . e d u和. t e l c o m . a r i z o n a . e d u)。我们 指定了一个严格源路由,使其试图将数据报从 g a t e w a y直接发送到g a b b y,而省略了b u t c h。 我们可以猜测到其结果会是失败的,正如图 8 - 9所给出的结果。 图8-9 采用严格源站路由失败的traceroute程序 这里的关键是在于 T T L字段为3的输出行中,RT T后面的! S。这表明 t r a c e r o u t e程序接 收到I C M P“源站路由失败”的差错报文:即图 6 - 3中t y p e字段为3,而c o d e字段为5。T T L字段 为3的第二个 RT T位置的星号表示未收到这次探查的应答信号。这与我们所猜想的一样, g a t e w a y不可能直接发送数据报给g a b b y,这是因为它们之间没有直接的连接。 T T L字段为2和3的结果都来自于 g a t e w a y,对于T T L字段为2的应答来自g a t e w a y,是因 为g a t e w a y接收到T T L字段为1的数据报。在它查看到(无效的)严格的源站选路之前,就发 现T T L已过期,因此发送回 I C M P超时报文。T T L字段等于3的行,在进入g a t e w a y时其T T L 字段为2,因此,它查看严格的源站选路,发现它是无效的,因此发送回 I C M P源站选路失败 的差错报文。 图8 - 1 0给出了与本例相对应的 t c p d u m p输出结果。该输出结果是在 s u n和n e t b之间的 S L I P链路上遇到的。我们必须在 t c p d u m p中指定- v选项以显示出源站路由信息。这样,会 输出一些像数据报 I D这样我们并不需要的结果,我们在给出结果中将这些不需要的结果删除 掉。同样,用S S R R表示“严格的源站及记录路由”。 首先注意到, s u n所发送的每个 U D P数据报的目的地址都是 n e t b,而不是目的主机 (w e s t g a t e)。这一点可以用图8 - 7的例子来解释。类似地,- G选项所指定的另外两个路由器 (g a t e w a y和g a b b y)以及最终目(w e s t g a t e)成为第一跳的S S R R选项。 从这个输出结果中,还可以看出, t r a c e r o u t e程序所采用的定时时间(第 1 5行和1 6行 第8章 Traceroute程序使用79之间的时间差)是5秒。 图8-10 失败的严格源站选路t r a c e r o u t e 程序的t c p d u m p 输出结果 8.5.3 宽松的源站选路t r a c e r o u t e程序的往返路由 我们在前面已经说过,从A到B的路径并不一定与从B到A的路径完全一样。除非同时在两 个系统中登录并在每个终端上运行 t r a c e r o u t e程序,否则很难发现两条路径是否不同。但 是,采用宽松的源站选路,就可以决定两个方向上的路径。 这里的窍门就在于指定一个宽松的源站路由,该路由的目的端和宽松路径一样,但发送端为 目的主机。例如,在s u n主机上,我们可以查看到发往以及来自b r u n o . c s . c o l o r a d o . e d u的 结果如图8 - 11所示。 发出路径(T T L字段为1 ~ 11)的结果与返回路径( T T L字段为11 ~ 2 1)不同,这很好地说 明了在Internet 上,选路可能是不对称的。 该输出同时还说明了我们在图 8 - 3中所讨论的问题。比较T T L字段为2和1 9的输出结果:它 们都是路由器g a t e w a y . t u c . n o a o . e d u,但两个I P地址却是不同的。由于 t r a c e r o u t e程 序以进入接口作为其标识,而我们从两条不同的方向经过该路由器,一条是发出路径( T T L 字段为2),另一条是返回路径( T T L字段为1 9),因此可以猜想到这个结果。通过比较 T T L字 段为3和1 8、4和1 7的结果,可以看到同样的结果。 80使用TCP/IP详解,卷1:协议图8-11 显示非对称路径的t r a c e r o u t e 程序 8.6 小结 在一个T C P / I P网络中,t r a c e r o u t e程序是不可缺少的工具。其操作很简单:开始时发 送一个T T L字段为1的U D P数据报,然后将 T T L字段每次加 1,以确定路径中的每个路由器。 每个路由器在丢弃 U D P数据报时都返回一个 I C M P超时报文 2,而最终目的主机则产生一个 I C M P端口不可达的报文。 我们给出了在L A N和WA N上运行t r a c e r o u t e程序的例子,并用它来考察 I P源站选路。 我们用宽松的源站选路来检测发往目的主机的路由是否与从目的主机返回的路由一样。 习题 8.1 当I P将接收到的T T L字段减1,发现它为0时,将会发生什么结果? 8.2 t r a c e r o u t e程序是如何计算RT T的?将这种计算RT T的方法与p i n g相比较。 8.3 (本习题与下一道习题是基于开发 t r a c e r o u t e程序过程中遇到的实际问题,它们来自 于t r a c e r o u t e程序源代码注释)。假设源主机和目的主机之间有三个路由器( R 1、R 2 和R 3),而中间的路由器(R 2)在进入T T L字段为1时,将T T L字段减1,但却错误地将该 I P数据报发往下一个路由器。请描述会发生什么结果。在运行 t r a c e r o u t e程序时会看 到什么样的现象? 8.4 同样,假设源主机和目的主机之间有三个路由器。由于目的主机上存在错误,因此,它 总是将进入T T L值作为外出I C M P报文的T T L值。请描述这将发生什么结果,你会看到什 么现象。 第8章 Traceroute程序使用818.5 在图8 - 8运行例子中,我们可以在 s u n和n e t b之间的S L I P链路上运行t c p d u m p程序。如 果指定- v选项,就可以看到返回 I C M P报文的T T L值。这样,我们可以看到进入 n e t b、 b u t c h、G a b b y和e n s s 1 4 2 . U T . w e s t n e t . n e t的T T L值分别为2 5 5、2 5 3、2 5 2和2 4 9。 这是否为我们判断是否存在丢失路由器提供了额外的信息? 8.6 S u n O S和S V R 4都提供了带- l选项的p i n g版本,以提供松源选路。手册上说明,该选项 可以与- R选项(指定记录路由选项)一起使用。如果已经进入到这些系统中,请尝试同 时用这两个选项。其结果是什么?如果采用 t c p d u m p来观测数据报,请描述其过程。 8.7 比较p i n g和t r a c e r o u t e程序在处理同一台主机上客户的多个实例的不同点。 8.8 比较p i n g和t r a c e r o u t e程序在计算往返时间上的不同点。 8.9 我们已经说过, t r a c e r o u t e程序选取开始 U D P目的主机端口号为 3 3 4 5 3,每发送一个 数据报将此数加 1。在1 . 9节中,我们说过暂时端口号通常是 1 0 2 4 ~ 5 0 0 0之间的值,因此 t r a c e r o u t e程序的目的主机端口号不可能是目的主机上所使用的端口号。在 S o l a r i s 2 . 2 系统中的情况也是如此吗?(提示:查看 E . 4节) 8.10 RFC 1393 [Malkin 1993b]提出了另一种判断到目的主机路径的方法。请问其优缺点是什 么? 82使用TCP/IP详解,卷1:协议第9章 IP选路 9.1 引言 选路是I P最重要的功能之一。图 9 - 1是I P层处理过程的简单流程。需要进行选路的数据报 可以由本地主机产生,也可以由其他主机产生。在后一种情况下,主机必须配置成一个路由 器,否则通过网络接口接收到的数据报,如果目的地址不是本机就要被丢弃(例如,悄无声 息地被丢弃)。 在图9 - 1中,我们还描述了一个路由守护程序( d a e m o n),通常这是一个用户进程。在 U n i x系统中,大多数普通的守护程序都是路由程序和网关程序(术语 d a e m o n指的是运行在后 台的进程,它代表整个系统执行某些操作。 d a e m o n一般在系统引导时启动,在系统运行期间 一直存在)。在某个给定主机上运行何种路由协议,如何在相邻路由器上交换选路信息,以及 选路协议是如何工作的,所有这些问题都是非常复杂的,其本身就可以用整本书来加以讨论 (有兴趣的读者可以参考文献 [Perlman 1992]以获得更详细的信息)。在第1 0章中,我们将简单 讨论动态选路和选路信息协议 R I P(Routing Information Protocol)。在本章中,我们主要的目 的是了解单个I P层如何作出路由决策。 图9 - 1所示的路由表经常被 I P访问(在一个繁忙的主机上,一秒钟内可能要访问几百次), 但是它被路由守护程序更新的频度却要低得多(可能大约 3 0秒种一次)。当接收到I C M P重定 向,报文时,路由表也要被更新,这一点我们将在 9 . 5节讨论r o u t e命令时加以介绍。在本章中, 我们还将用n e t s t a t命令来显示路由表。 图9-1 IP层工作流程 路由守 护程序 route命 令 netstat 命令 根据相邻路由 器更新路由表 路由表 IP层 I P输出: 计算下一站路 由器(如果需要) 网络接口 IP输入队列 处理IP选项 是分组( I P地址 之一或是广 播地址) ICMP UDP TCP 是9.2 选路的原理 开始讨论I P选路之前,首先要理解内核是如何维护路由表的。路由表中包含的信息决定 了I P层所做的所有决策。 在3 . 3节中,我们列出了I P搜索路由表的几个步骤: 1) 搜索匹配的主机地址; 2) 搜索匹配的网络地址; 3) 搜索默认表项(默认表项一般在路由表中被指定为一个网络表项,其网络号为 0)。 匹配主机地址步骤始终发生在匹配网络地址步骤之前。 I P层进行的选路实际上是一种选路机制,它搜索路由表并决定向哪个网络接口发送分组。 这区别于选路策略,它只是一组决定把哪些路由放入路由表的规则。 I P执行选路机制,而路 由守护程序则一般提供选路策略。 9.2.1 简单路由表 首先来看一看一些典型的主机路由表。在主机s v r 4上,我们先执行带-r选项的n e t s t a t命令 列出路由表,然后以-n选项再次执行该命令,以数字格式打印出I P地址(我们这样做是因为路由 表中的一些表项是网络地址,而不是主机地址。如果没有- n选项,n e t s t a t命令将搜索文件 / e t c / n e t w o r k s并列出其中的网络名。这样会与另一种形式的名字— 网络名加主机名相混淆)。 第1行说明,如果目的地是 1 4 0 . 2 5 2 . 1 3 . 6 5(s l i p主机),那么网关(路由器)将把分组转 发给1 4 0 . 2 5 2 . 1 3 . 3 5(b s d i)。这正是我们所期望的,因为主机 s l i p通过S L I P链路与b s d i相 连接,而b s d i与该主机在同一个以太网上。 对于一个给定的路由器,可以打印出五种不同的标志( f l a g): U 该路由可以使用。 G 该路由是到一个网关(路由器)。如果没有设置该标志,说明目的地是直接相连的。 H 该路由是到一个主机,也就是说,目的地址是一个完整的主机地址。如果没有设置该 标志,说明该路由是到一个网络,而目的地址是一个网络地址:一个网络号,或者网 络号与子网号的组合。 D 该路由是由重定向报文创建的( 9 . 5节)。 M 该路由已被重定向报文修改( 9 . 5节)。 标志G是非常重要的,因为由它区分了间接路由和直接路由(对于直接路由来说是不设置 标志G的)。其区别在于,发往直接路由的分组中不但具有指明目的端的 I P地址,还具有其链 路层地址(见图 3 - 3)。当分组被发往一个间接路由时, I P地址指明的是最终的目的地,但是 链路层地址指明的是网关(即下一站路由器)。我们在图3 - 4已看到这样的例子。在这个路由 表例子中,有一个间接路由(设置了标志 G),因此采用这一项路由的分组其 I P地址是最终的 目的地(1 4 0 . 2 5 2 . 1 3 . 6 5),但是其链路层地址必须对应于路由器 1 4 0 . 2 5 2 . 1 3 . 3 5。 84使用TCP/IP详解,卷1:协议理解G和H标志之间的区别是很重要的。 G标志区分了直接路由和间接路由,如上所述。 但是H标志表明,目的地址( n e t s t a t命令输出第一行)是一个完整的主机地址。没有设置 H标志说明目的地址是一个网络地址(主机号部分为 0)。当为某个目的I P地址搜索路由表时, 主机地址项必须与目的地址完全匹配,而网络地址项只需要匹配目的地址的网络号和子网号 就可以了。另外,大多数版本的 n e t s t a t命令首先打印出所有的主机路由表项,然后才是网 络路由表项。 参考记数R e f c n t(Reference count)列给出的是正在使用路由的活动进程个数。面向连接 的协议如T C P在建立连接时要固定路由。如果在主机 s v r 4和s l i p之间建立Te l n e t连接,可以 看到参考记数值变为1。建立另一个Te l n e t连接时,它的值将增加为2,依此类推。 下一列(“u s e”)显示的是通过该路由发送的分组数。如果我们是这个路由的唯一用户, 那么运行p i n g程序发送5个分组后,它的值将变为 5。最后一列(i n t e r f a c e)是本地接口的名 字。 输出的第2行是环回接口(2 . 7节),它的名字始终为 l o 0。没有设置G标志,因为该路由不 是一个网关。H标志说明目的地址(1 2 7 . 0 . 0 . 1)是一个主机地址,而不是一个网络地址。由于 没有设置G标志,说明这是一个直接路由,网关列给出的是外出 I P地址。 输出的第3行是默认路由。每个主机都有一个或多个默认路由。这一项表明,如果在表中 没有找到特定的路由,就把分组发送到路由器 1 4 0 . 2 5 2 . 1 3 . 3 3(s u n主机)。这说明当前主机 (s v r 4)利用这一个路由表项就可以通过 I n t e r n e t经路由器s u n(及其S L I P链路)访问其他的系 统。建立默认路由是一个功能很强的概念。该路由标志( U G)表明它是一个网关,这是我们 所期望的。 这里,我们有意称s u n为路由器而不是主机,因为它被当作默认路由器来使用,它 发挥的是IP转发功能,而不是主机功能。 Host Requirements RFC文档特别说明,IP层必须支持多个默认路由。但是,许多实 现系统并不支持这一点。当存在多个默认路由时,一般的技术就成为它们周围的知更 鸟了,例如,Solaris 2.2就是这样做的。 输出中的最后一行是所在的以太网。 H标志没有设置,说明目的地址( 1 4 0 . 2 5 2 . 1 3 . 3 2)是 一个网络地址,其主机地址部分设为 0。事实上,是它的低 5位设为0(见图3 - 11)。由于这是 一个直接路由(G标志没有被设置),网关列指出的I P地址是外出地址。 n e t s t a t命令输出的最后一项还隐含了另一个信息,那就是目的地址( 1 4 0 . 2 5 2 . 1 3 . 3 2) 的子网掩码。如果要把该目的地址与 1 4 0 . 2 5 2 . 1 3 . 3 3进行比较,那么在比较之前首先要把它与 目的地址掩码(0 x ffffff e 0,3 . 7节)进行逻辑与。由于内核知道每个路由表项对应的接口,而 且每个接口都有一个对应的子网掩码,因此每个路由表项都有一个隐含的子网掩码。 主机路由表的复杂性取决于主机所在网络的拓扑结构。 1) 最简单的(也是最不令人感兴趣的)情况是主机根本没有与任何网络相连。 T C P / I P协 议仍然能用于这样的主机,但是只能与自己本身通信!这种情况下的路由表只包含环回接口 一项。 2) 接下来的情况是主机连在一个局域网上,只能访问局域网上的主机。这时路由表包含 两项:一项是环回接口,另一项是局域网(如以太网)。 3) 如果主机能够通过单个路由器访问其他网络(如 I n t e r n e t)时,那么就要进行下一步。 第9章 IP路由选择使用85一般情况下增加一个默认表项指向该路由器。 4) 如果要新增其他的特定主机或网络路由,那么就要进行最后一步。在我们的例子中, 到主机s l i p的路由要通过路由器b s d i就是这样的例子。 我们根据上述I P操作的步骤使用这个路由表为主机 s v r 4上的一些分组例子选择路由。 1) 假定目的地址是主机 s u n,1 4 0 . 2 5 2 . 1 3 . 3 3。首先进行主机地址的匹配。路由表中的两 个主机地址表项( s l i p和l o c a l h o s t)均不匹配,接着进行网络地址匹配。这一次匹配成 功,找到表项 1 4 0 . 2 5 2 . 1 3 . 3 2(网络号和子网号都相同),因此使用e m d 0接口。这是一个直接 路由,因此链路层地址将是目的端的地址。 2) 假定目的地址是主机s l i p,1 4 0 . 2 5 2 . 1 3 . 6 5。首先在路由表搜索主机地址,并找到一个 匹配地址。这是一个间接路由,因此目的端的 I P地址仍然是1 4 0 . 2 5 2 . 1 3 . 6 5,但是链路层地址 必须是网关1 4 0 . 2 5 2 . 1 3 . 6 5的链路层地址,其接口名为 e m d 0。 3) 这一次我们通过I n t e r n e t给主机a w . c o m(1 9 2 . 2 0 7 . 11 7 . 2)发送一份数据报。首先在路 由表中搜索主机地址,失败后进行网络地址匹配。最后成功地找到默认表项。该路由是一个 间接路由,通过网关1 4 0 . 2 5 2 . 1 3 . 3 3,并使用接口名为e m d 0。 4) 在我们最后一个例子中,我们给本机发送一份数据报。有四种方法可以完成这件事, 如用主机名、主机I P地址、环回名或者环回I P地址: ftp svr4 ftp 140.252.13.34 ftp localhost ftp 127.0.0.1 在前两种情况下,对路由表的第 2次搜索得到一个匹配的网络地址 1 4 0 . 2 5 2 . 1 3 . 3 2,并把I P 报文传送给以太网驱动程序。正如图 2 - 4所示的那样,I P报文中的目的地址为本机 I P地址,因 此报文被送给环回驱动程序,然后由驱动程序把报文放入 I P输出队列中。 在后两种情况下,由于指定了环回接口的名字或 I P地址,第一次搜索就找到匹配的主机 地址,因此报文直接被送给环回驱动程序,然后由驱动程序把报文放入 I P输出队列中。 上述四种情况报文都要被送给环回驱动程序,但是采用的两种路由决策是不相同的。 9.2.2 初始化路由表 我们从来没有说过这些路由表是如何被创建的。每当初始化一个接口时(通常是用 i f c o n f i g命令设置接口地址),就为接口自动创建一个直接路由。对于点对点链路和环回接口 来说,路由是到达主机(例如,设置 H标志)。对于广播接口来说,如以太网,路由是到达网 络。 到达主机或网络的路由如果不是直接相连的,那么就必须加入路由表。一个常用的方法 是在系统引导时显式地在初始化文件中运行 r o u t e命令。在主机s v r 4上,我们运行下面两个命 令来添加路由表中的表项: route add default sun 1 route add slip bsdi 1 第3个参数( d e f a u l t和s l i p)代表目的端,第 4个参数代表网关(路由器),最后一个 参数代表路由的度量( m e t r i c )。r o u t e命令在度量值大于0时要为该路由设置G标志,否则,当 耗费值为0时就不设置G标志。 86使用TCP/IP详解,卷1:协议不幸的是,几乎没有系统愿意在启动文件中包含r o u t e命令。在4 . 4 B S D和B S D / 3 8 6 系统中,启动文件是 / e t c / n e t s t a r t ;在 S V R 4 系统中,启动文件是 / e t c / i n e t / r c . i n e t;在Solaris 2.x中,启动文件是/ e t c / r c 2 . d / S 6 9 i n e t;在 SunOS 4.1.x中,启动文件是/ e t c / r c . l o c a l;而AIX 3.2.2则使用文件/ e t c / r c . n e t。 一些系统允许在某个文件中指定默认的路由器,如 / e t c / d e f a u l t r o u t e r。于是在每 次重新启动系统时都要在路由表中加入该默认项。 初始化路由表的其他方法是运行路由守护程序(第 1 0章)或者用较新的路由器发现协议 (9 . 6节)。 9.2.3 较复杂的路由表 在我们的子网上,主机 s u n是所有主机的默认路由器,因为它有拨号 S L I P链路连接到 I n t e r n e t上(参见扉页前图)。 前两项与主机s v r 4的前两项一致:通过路由器 b s d i到达s l i p的特定主机路由,以及环 回路由。 第3行是新加的。这是一个直接到达主机的路由 (没有设置G标志,但设置了H标志),对应 于点对点的链路,即S L I P接口。如果我们把它与i f c o n f i g命令的输出进行比较: sun % ifconfig sl0 sl0: flags=1051 inet 140.252.1.29 --> 140.252.1.183 netmask ffffff00 可以发现路由表中的目的地址就是点对点链路的另一端 (即路由器n e t b), 网关地址为外出 接口的本地I P地址( 1 4 0 . 2 5 2 . 1 . 2 9 ) (前面已经说过, n e t s t a t为直接路由打印出来的网关地址就 是本地接口所用的I P地址)。 默认的路由表项是一个到达网络的间接路由 (设置了G标志,但没有设置 H标志),这正是 我们所希望的。网关地址是路由器的地址 ( 1 4 0 . 2 5 2 . 1 . 1 8 3,S L I P链路的另一端), 而不是S L I P链 路的本地I P地址( 1 4 0 . 2 5 2 . 1 . 2 9 )。其原因还是因为是间接路由,不是直接路由。 还应该指出的是,n e t s t a t输出的第3和第4行(接口名为s l 0)由S L I P软件在启动时创建, 并在关闭时删除. 9.2.4 没有到达目的地的路由 我们所有的例子都假定对路由表的搜索能找到匹配的表项,即使匹配的是默认项。如果 路由表中没有默认项,而又没有找到匹配项,这时会发生什么情况呢? 结果取决于该 I P数据报是由主机产生的还是被转发的(例如,我们就充当一个路由器)。 如果数据报是由本地主机产生的,那么就给发送该数据报的应用程序返回一个差错,或者是 “主机不可达差错”或者是“网络不可达差错”。如果是被转发的数据报,那么就给原始发送 第9章 IP路由选择使用87端发送一份I C M P主机不可达的差错报文。下一节将讨论这种差错。 9.3 ICMP主机与网络不可达差错 当路由器收到一份 I P数据报但又不能转发时,就要发送一份 I C M P“主机不可达”差错报 文(I C M P主机不可达报文的格式如图 6 - 1 0所示)。可以很容易发现,在我们的网络上把接在 路由器 s u n上的拨号S L I P链路断开,然后试图通过该 S L I P链路发送分组给任何指定 s u n为默 认路由器的主机。 较老版本的B S D产生一个主机不可达或者网络不可达差错,这取决于目的端是否 处于一个局域子网上。4.4 BSD只产生主机不可达差错。 我们在上一节通过在路由器 s u n上运行n e t s t a t命令可以看到,当接通 S L I P链路启动时 就要在路由表中增加一项使用 S L I P链路的表项,而当断开 S L I P链路时则删除该表项。这说明 当S L I P链路断开时,s u n的路由表中就没有默认项了。但是我们不想改变网络上其他主机的 路由表,即同时删除它们的默认路由。相反,对于 s u n不能转发的分组,我们对它产生的 I C M P主机不可达差错报文进行计数。 在主机s v r 4上运行 p i n g程序就可以看到这一点,它在拨号 S L I P链路的另一端(拨号链 路已被断开): 在主机b s d i上运行t c p d u m p命令的输出如图9 - 2所示。 图9-2 响应p i n g 命令的ICMP主机不可达报文 当路由器s u n发现找不到能到达主机 g e m i n i的路由时,它就响应一个主机不可达的回显 请求报文。 如果把S L I P链路接到I n t e r n e t上,然后试图p i n g一个与I n t e r n e t没有连接的I P地址,那么应该会 产生差错。但令人感兴趣的是,我们可以看到在返回差错报文之前,分组要在I n t e r n e t上传送多远: 从图8 - 5可以看出,在发现该I P地址是无效的之前,该分组已通过了 6个路由器。只有当它 到达N S F N E T骨干网的边界时才检测到差错。这说明, 6个路由器之所以能转发分组是因为路 由表中有默认项。只有当分组到达 N S F N E T骨干网时,路由器才能知道每个连接到 I n t e r n e t上 的每个网络的信息。这说明许多路由器只能在局部范围内工作。 参考文献[Ford, Rekhter, and Braun 1993]定义了顶层选路域( top-level routing domain), 由它来维护大多数I n t e r n e t网站的路由信息,而不使用默认路由。他们指出,在 I n t e r n e t上存在 88使用TCP/IP详解,卷1:协议 键入中断键停止显示 该IP地址没有连接到Internet上5个这样的顶层选路域: N S F N E T主干网、商业互联网交换( Commercial Internet Exchange: C I X)、N A S A科学互联网( NASA Science Internet: NSI)、S p r i n t L i n k以及欧洲 I P主干网 (E B O N E)。 9.4 转发或不转发 前面我们已经提过几次,一般都假定主机不转发 I P数据报,除非对它们进行特殊配置而 作为路由器使用。如何进行这样的配置呢? 大多数伯克利派生出来的系统都有一个内核变量 i p f o r w a r d i n g,或其他类似的名字 (参见附录E)。一些系统(如B S D / 3 8 6和S V R 4)只有在该变量值不为0的情况下才转发数据报。 SunOS 4.1.x允许该变量可以有三个不同的值:- 1表示始终不转发并且始终不改变它的值; 0表 示默认条件下不转发,但是当打开两个或更多个接口时就把该值设为 1;1表示始终转发。 Solaris 2.x把这三个值改为0(始终不转发)、1(始终转发)和2(在打开两个或更多个接口时 才转发)。 较早版本的4 . 2 B S D主机在默认条件下可以转发数据报,这给没有进行正确配置的系统带 来了许多问题。这就是内核选项为什么要设成默认的“始终不转发”的原因,除非系统管理 员进行特殊设置。 9.5 ICMP重定向差错 当I P数据报应该被发送到另一个路由器时,收到数据报的路由器就要发送 I C M P重定向差 错报文给I P数据报的发送端。这在概念上是很简单的,正如图 9 - 3所示的那样。只有当主机可 以选择路由器发送分组的情况下,我们才可能看到 I C M P重定向报文(回忆我们在图 7 - 6中看 过的例子)。 1) 我们假定主机发送一份 I P数据报给R 1。这种选路决策经常发生,因为 R 1是该主机的默 认路由。 2) R1收到数据报并且检查它的路由表,发现 R 2是发送该数据报的下一站。当它把数据报 发送给R 2时,R 1检测到它正在发送的接口与数据报到达接口是相同的(即主机和两个路由器 所在的L A N)。这样就给路由器发送重定向报文给原始发送端提供了线索。 3) R1发送一份I C M P重定向报文给主机,告诉它以后把数据报发送给 R 2而不是R 1。 图9-3 ICMP重定向的例子 第9章 IP路由选择使用89 主机 R1 R2 最终目标 (2) IP数据报 (3) ICMP重定向 (1) IP数据报重定向一般用来让具有很少选路信息的主机逐渐建立更完善的路由表。主机启动时路由 表中可以只有一个默认表项(在图 9 - 3所示的例子中,为 R 1或R 2)。一旦默认路由发生差错, 默认路由器将通知它进行重定向,并允许主机对路由表作相应的改动。 I C M P重定向允许 T C P / I P主机在进行选路时不需要具备智能特性,而把所有的智能特性放在路由器端。显然, 在我们的例子中,R 1和R2 必须知道有关相连网络的更多拓扑结构的信息,但是连在 L A N上的 所有主机在启动时只需一个默认路由,通过接收重定向报文来逐步学习。 9.5.1 一个例子 可以在我们的网络上观察到 I C M P重定向的操作过程(见封二的图)。尽管在拓扑图中只 画出了三台主机(a i x , s o l a r i s和g e m i n i)和两台路由器(g a t e w a y和n e t b),但是整个 网络有超过1 5 0台主机和1 0台另外的路由器。大多数的主机都把 g a t e w a y指定为默认路由器, 因为它提供了I n t e r n e t的入口。 子网1 4 0 . 2 5 2 . 1上的主机是如何访问作者所在子网(图中底下的四台主机)的呢?首先, 如果在S L I P链路的一端只有一台主机,那么就要使用代理 A R P(4 . 6节)。这意味着位于拓扑 图顶部的子网(1 4 0 . 2 5 2 . 1)中的主机不需要其他特殊条件就可以访问主机 s u n(1 4 0 . 2 5 2 . 1 . 2 9)。 位于n e t b上的代理A R P软件处理这些事情。 但是,当网络位于 S L I P链路的另一端时,就要涉及到选路了。一个办法是让所有的主机 和路由器都知道路由器 n e t b是网络1 4 0 . 2 5 2 . 1 3的网关。这可以在每个主机的路由表中设置静 态路由,或者在每个主机上运行守护程序来实现。另一个更简单的办法(也是实际采用的方 法)是利用I C M P重定向报文来实现。 在位于网络顶部的主机 s o l a r i s上运行p i n g程序到主机b s d i( 1 4 0 . 2 5 2 . 1 3 . 3 5 )。由于子 网号不相同,代理 A R P不能使用。假定没有安装静态路由,发送的第一个分组将采用到路由 器g a t e w a y的默认路由。下面是我们运行 p i n g程序之前的路由表: (2 2 4 . 0 . 0 . 0所在的表项是I P广播地址。我们将在第 1 2章讨论)。如果为p i n g程序指定-v选项, 可以看到主机接收到的任何 I C M P报文。我们需要指定该选项以观察发送的重定向报文。 在收到p i n g程序的第一个响应之前,主机先收到一份来自默认路由器 g a t e w a y发来的 90使用TCP/IP详解,卷1:协议 键入中断键停止显示I C M P重定向报文。如果这时查看路由表,就会发现已经插入了一个到主机 b s d i的新路由 (该表项如以下黑体字所示)。 这是我们第一次看到D标志,表示该路由是被I C M P重定向报文创建的。G标志说明这是一份到 达g a t e w a y (n e t b)的间接路由,H标志则说明这是一个主机路由(正如我们期望的那样),而 不是一个网络路由。 由于这是一个被主机重定向报文增加的主机路由,因此它只处理到达主机 b s d i的报文。 如果我们接着访问主机 s v r 4,那么就要产生另一个 I C M P重定向报文,创建另一个主机路由。 类似地,访问主机 s l i p也创建另一个主机路由。位于子网上的三台主机( b s d i , s v r 4和 s l i p)还可以由一个指向路由器 s u n的网络路由来进行处理。但是 I C M P重定向报文创建的 是主机路由,而不是网络路由,这是因为在本例中,产生 I C M P重定向报文的路由器并不知道 位于1 4 0 . 2 5 2 . 1 3网络上的子网信息。 9.5.2 更多的细节 I C M P重定向报文的格式如图9 - 4所示。 图9-4 ICMP重定向报文 有四种不同类型的重定向报文,有不同的代码值,如图 9 - 5所示。 I C M P重定向报文的接收者必须查看三个 I P地址: ( 1 )导致重定向的 I P地址(即I C M P重定向报文的数据 位于I P数据报的首部);( 2 )发送重定向报文的路由器 的I P地址(包含重定向信息的 I P数据报中的源地址; ( 3 )应该采用的路由器I P地址(在I C M P报文中的4 ~ 7字 节)。 关于I C M P重定向报文有很多规则。首先,重定向报文只能由路由器生成,而不能由主机 生成。另外,重定向报文是为主机而不是为路由器使用的。假定路由器和其他一些路由器共 同参与某一种选路协议,则该协议就能消除重定向的需要(这意味着在图 9 - 1中的路由表应该 第9章 IP路由选择使用91 (5)类型 (0~3)代码 应该使用的路由器IP地址 IP首部(包括选项)+原始IP数据报中的数据前8字节 检验和 8字节 描 述代码 网络重定向 主机重定向 服务类型和网络重定向 服务类型和主机重定向 图9-5 ICMP重定向报文的不同代码值消除或者能被选路守护程序修改,或者能被重定向报文修改,但不能同时被二者修改)。 在4 . 4 B S D系统中,当主机作为路由器使用时,要进行下列检查。在生成 I C M P重定向报文 之前这些条件都要满足。 1) 出接口必须等于入接口。 2) 用于向外传送数据报的路由不能被 I C M P重定向报文创建或修改过,而且不能是路由器 的默认路由。 3) 数据报不能用源站选路来转发。 4) 内核必须配置成可以发送重定向报文。 内核变量取名为i p _ s e n d r e d i r e c t s或其他类似的名字(参见附录E)。大多数当 前的系统(例如B S D、 SunOS 4.1.x、Solaris 2.x 及AIX 3.2.2)在默认条件下都设置该 变量,使系统可以发送重定向报文。其他系统如SVR4则关闭了该项功能。 另外,一台4 . 4 B S D主机收到I C M P重定向报文后,在修改路由表之前要作一些检查。这是 为了防止路由器或主机的误操作,以及恶意用户的破坏,导致错误地修改系统路由表。 1) 新的路由器必须直接与网络相连接。 2) 重定向报文必须来自当前到目的地所选择的路由器。 3) 重定向报文不能让主机本身作为路由器。 4) 被修改的路由必须是一个间接路由。 关于重定向最后要指出的是,路由器应该发送的只是对主机的重定向(代码 1或3,如图 9 - 5所示),而不是对网络的重定向。子网的存在使得难于准确指明何时应发送对网络的重定 向而不是对主机的重定向。只当路由器发送了错误的类型时,一些主机才把收到的对网络的 重定向当作对主机的重定向来处理。 9.6 ICMP路由器发现报文 在本章前面已提到过一种初始化路由表的方法,即在配置文件中指定静态路由。这种方 法经常用来设置默认路由。另一种新的方法是利用 I C M P路由器通告和请求报文。 一般认为,主机在引导以后要广播或多播传送一份路由器请求报文。一台或更多台路由 器响应一份路由器通告报文。另外,路由器定期地广播或多播传送它们的路由器通告报文, 允许每个正在监听的主机相应地更新它们的路由表。 RFC 1256 [Deering 1991]确定了这两种I C M P报文的格式。I C M P路由器请求报文的格式如 图9 - 6所示。I C M P路由器通告报文的格式如图 9 - 7所示。 路由器在一份报文中可以通告多个地址。地址数指的是报文中所含的地址数。地址项大 小指的是每个路由器地址 32 bit字的数目,始终为 2。生存期指的是通告地址有效的时间(秒 数)。 图9-6 ICMP路由器请求报文格式 92使用TCP/IP详解,卷1:协议 类型(10) 代码(0) 检验和 未用(置为0发送) 8字节图9-7 ICMP路由器通告报文格式 接下来是一对或多对 I P地址和优先级。 I P地址必须是发送路由器的某个地址。优先级是 一个有符号的32 bit整数,指出该I P地址作为默认路由器地址的优先等级,这是与子网上的其 他路由器相比较而言的。值越大说明优先级越高。优先级为 0 x 8 0 0 0 0 0 0 0说明对应的地址不能 作为默认路由器地址使用,尽管它也包含中通告报文中。优先级的默认值一般为 0。 9.6.1 路由器操作 当路由器启动时,它定期在所有广播或多播传送接口上发送通告报文。准确地说,这些 通告报文不是定期发送的,而是随机传送的,以减小与子网上其他路由器发生冲突的概率。 一般每两次通告间隔4 5 0秒和6 0 0秒。一份给定的通告报文默认生命周期是 3 0分钟。 使用生命周期域的另一个时机是当路由器上的某个接口被关闭时。在这种情况下,路由 器可以在该接口上发送最后一份通告报文,并把生命周期值设为 0。 除了定期发送主动提供的通告报文以外,路由器还要监听来自主机的请求报文,并发送 路由器通告报文以响应这些请求报文。 如果子网上有多台路由器,由系统管理员为每个路由器设置优先等级。例如,主默认路 由器就要比备份路由器具有更高的优先级。 9.6.2 主机操作 主机在引导期间一般发送三份路由器请求报文,每三秒钟发送一次。一旦接收到一个有 效的通告报文,就停止发送请求报文。 主机也监听来自相邻路由器的请求报文。这些通告报文可以改变主机的默认路由器。另 外,如果没有接收到来自当前默认路由器的通告报文,那么默认路由器会超时。 只要有一般的默认路由器,该路由器就会每隔 1 0分钟发送通告报文,报文的生命周期是 3 0分钟。这说明主机的默认表项是不会超时的,即使错过一份或两份通告报文。 9.6.3 实现 路由器发现报文一般由用户进程(守护程序)创建和处理。这样,在图 9 - 1中就有另一个 第9章 IP路由选择使用93 类型(9) 代码(0) 检验和 生存时间地址项长度(2) 路由器地址[1] 优先级[1] 优先级[2] 路由器地址[2] 地址数 8字节修改路由表的程序,尽管它只增加或删除默认表项。守护程序必须把它配置成一台路由器或 主机来使用。 这两种I C M P报文是新加的,不是所有的系统都支持它们。在我们的网络中,只有 Solaris 2.x支持这两种报文(i n . r d i s c守护程序)。尽管RFC建议尽可能用IP多播传送, 但是路由器发现还可以利用广播报文来实现。 9.7 小结 I P路由操作对于运行T C P/I P的系统来说是最基本的,不管是主机还是路由器。路由表项 的内容很简单,包括: 5 bit标志、目的I P地址(主机、网络或默认)、下一站路由器的 I P地址 (间接路由)或者本地接口的 I P地址(直接路由)及指向本地接口的指针。主机表项比网络表 项具有更高的优先级,而网络表项比默认项具有更高的优先级。 系统产生的或转发的每份 I P数据报都要搜索路由表,它可以被路由守护程序或 I C M P重定 向报文修改。系统在默认情况下不转发数据报,除非进行特殊的配置。用 r o u t e命令可以进 入静态路由,可以利用新 I C M P路由器发现报文来初始化默认表项,并进行动态修改。主机在 启动时只有一个简单的路由表,它可以被来自默认路由器的 I C M P重定向报文动态修改。 在本章中,我们集中讨论了单个系统是如何利用路由表的。在下一章,我们将讨论路由 器之间是如何交换路由信息的。 习题 9.1 为什么你认为存在两类I C M P重定向报文— 网络和主机? 9.2 在9 . 4节开头列出的s v r 4主机上的路由表中,到主机 s l i p(1 4 0 . 2 5 2 . 1 3 . 6 5)的特定路由 是必需的吗?如果把这一项从路由表中删除会有什么变化? 9.3 考虑有一电缆连接4 . 2 B S D主机和4 . 3 B S D主机。假定网络号是1 4 0 . 1。4 . 2 B S D主机把主机号为 全0的地址识别为广播地址( 1 4 0 . 1 . 0 . 0 ),而4 . 3 B S D通常使用全1的主机号(1 4 0 . 1 . 2 5 5 . 2 5 5)发 送广播。另外,4 . 2 B S D主机在默认条件下要尽力转发接收到的数据报,尽管它们只有一个 接口。 请描述当4 . 2 B S D主机收到一份目的地址为1 4 0 . 1 . 2 5 5 . 2 5 5的I P数据报时会发生什么事。 9.4 继续前一个习题,假定有人在子网 1 4 0 . 1上的某个系统A R P高速缓存中增加了一项(用 a r p 命令)内容,指定 I P地址1 4 0 . 1 . 2 5 5 . 2 5 5对应的以太网地址为全 1(以太网广播地址)。请 描述此时发生的情况。 9.5 检查你所使用的系统上的路由表,并解释每一项内容。 94使用TCP/IP详解,卷1:协议第10章 动态选路协议 10.1 引言 在前面各章中,我们讨论了静态选路。在配置接口时,以默认方式生成路由表项(对于 直接连接的接口),并通过r o u t e命令增加表项(通常从系统自引导程序文件),或是通过I C M P 重定向生成表项(通常是在默认方式出错的情况下)。 在网络很小,且与其他网络只有单个连接点且没有多余路由时(若主路由失败,可以使 用备用路由),采用这种方法是可行的。如果上述三种情况不能全部满足,通常使用动态选 路。 本章讨论动态选路协议,它用于路由器间的通信。我们主要讨论 R I P,即选路信息协议 (Routing Infromation Protocol),大多数T C P / I P实现都提供这个应用广泛的协议。然后讨论两 种新的选路协议, O S P F和B G P。本章的最后研究一种名叫无分类域间选路的新的选路技术, 现在I n t e r n e t上正在开始采用该协议以保持 B类网络的数量。 10.2 动态选路 当相邻路由器之间进行通信,以告知对方每个路由器当前所连接的网络,这时就出现了 动态选路。路由器之间必须采用选路协议进行通信,这样的选路协议有很多种。路由器上有 一个进程称为路由守护程序( routing daemon),它运行选路协议,并与其相邻的一些路由器 进行通信。正如图 9 - 1所示,路由守护程序根据它从相邻路由器接收到的信息,更新内核中的 路由表。 动态选路并不改变我们在 9 . 2节中所描述的内核在 I P层的选路方式。这种选路方式称为选 路机制(routing mechanism)。内核搜索路由表,查找主机路由、网络路由以及默认路由的方 式并没有改变。仅仅是放置到路由表中的信息改变了— 当路由随时间变化时,路由是由路 由守护程序动态地增加或删除,而不是来自于自引导程序文件中的 r o u t e命令。 正如前面所描述的那样,路由守护程序将选路策略( routing policy)加入到系统中,选 择路由并加入到内核的路由表中。如果守护程序发现前往同一信宿存在多条路由,那么它 (以某种方法)将选择最佳路由并加入内核路由表中。如果路由守护程序发现一条链路已经断 开(可能是路由器崩溃或电话线路不好),它可以删除受影响的路由或增加另一条路由以绕过 该问题。 在像I n t e r n e t这样的系统中,目前采用了许多不同的选路协议。 I n t e r n e t是以一组自治系统 (A S,Autonomous System)的方式组织的,每个自治系统通常由单个实体管理。常常将一个公 司或大学校园定义为一个自治系统。 N S F N E T的I n t e r n e t骨干网形成一个自治系统,这是因为 骨干网中的所有路由器都在单个的管理控制之下。 每个自治系统可以选择该自治系统中各个路由器之间的选路协议。这种协议我们称之为 内部网关协议I G P(Interior Gateway Protocol)或域内选路协议(intradomain routing protocol)。最常用的I G P是选路信息协议 R I P。一种新的 I G P是开放最短路径优先 O S P F(Open Shortest Path First)协议。它意在取代 R I P。另一种1 9 8 6年在原来N S F N E T骨干网上使用的较早的 I G P 协议— H E L L O,现在已经不用了。 新的RFC [Almquist 1993]规定,实现任何动态选路协议的路由器必须同时支持 OSPF和RIP,还可以支持其他IGP协议。 外部网关协议E G P(Exterier Gateway Protocol)或域内选路协议的分隔选路协议用于不 同自治系统之间的路由器。在历史上,(令人容易混淆)改进的 E G P有着一个与它名称相同的 协议:E G P。新E G P是当前在N S F N E T骨干网和一些连接到骨干网的区域性网络上使用的是边 界网关协议B G P(Border Gateway Protocol)。B G P意在取代E G P。 10.3 Unix选路守护程序 U n i x系统上常常运行名为r o u t e d路由守护程序。几乎在所有的 T C P / I P实现中都提供该程 序。该程序只使用R I P进行通信,我们将在下一节中讨论该协议。这是一种用于小型到中型网 络中的协议。 另一个程序是g a t e d。I G P和E G P都支持它。[Fedor 1998]描述了早期开发的 g a t e d。图 1 0 - 1对r o u t e d和两种不同版本的g a t e d所支持的不同选路协议进行了比较。大多数运行路由 守护程序的系统都可以运行 r o u t e d,除非它们需要支持g a t e d所支持的其他协议。 图10-1 r o u t e d 和g a t e d 所支持的选路协议 我们在下一节中描述 RIP 版本1,1 0 . 5节描述它与R I P版本2的不同点,1 0 . 6节描述O S P F, 1 0 . 7节描述B G P。 10.4 RIP:选路信息协议 本节对R I P进行了描述,这是因为它是最广为使用(也是最受攻击)的选路协议。对于 R I P 的正式描述文件是RFC 1058 [Hedrick 1988a],但是该R F C是在该协议实现数年后才出现的。 10.4.1 报文格式 RIP报文包含中在UDP数据报中,如图10-2所示(在第11章中对UDP进行更为详细的描述)。 图1 0 - 3给出了使用 I P地址时的R I P报文 格式。 命令字段为1表示请求,2表示应答。还 有两个舍弃不用的命令( 3和4),两个非正 式的命令:轮询( 5)和轮询表项( 6)。请 求表示要求其他系统发送其全部或部分路由 96使用TCP/IP详解,卷1:协议 内部网点协议守护程序 routed gated, 版本2 gated, 版本3 外部网点协议 图10-2 封装在UDP数据报中的RIP报文 IP数据报 UDP数据报 RIP报文 首部首部 20字节 8字节表。应答则包含发送者全部或部分路由表。 版本字段通常为1,而第2版R I P(1 0 . 5节)将此字段设置为2。 紧跟在后面的2 0字节指定地址系列(address family)(对于I P地址来说,其值是2)、I P地 址以及相应的度量。在本节的后面可以看出, R I P的度量是以跳计数的。 采用这种2 0字节格式的R I P报文可以通告多达 2 5条路由。上限2 5是用来保证R I P报文的总 长度为2 0×25 + 4 = 504,小于5 1 2字节。由于每个报文最多携带 2 5个路由,因此为了发送整 个路由表,经常需要多个报文。 图 10-3 10.4.2 正常运行 让我们来看一下采用R I P协议的r o u t e d程序正常运行的结果。R I P常用的U D P端口号是5 2 0。 • 初始化:在启动一个路由守护程序时,它先判断启动了哪些接口,并在每个接口上发送 一个请求报文,要求其他路由器发送完整路由表。在点对点链路中,该请求是发送给其 他终点的。如果网络支持广播的话,这种请求是以广播形式发送的。目的 U D P端口号是 5 2 0(这是其他路由器的路由守护程序端口号)。 这种请求报文的命令字段为 1,但地址系列字段设置为 0,而度量字段设置为 1 6。这是一 种要求另一端完整路由表的特殊请求报文。 • 接收到请求。如果这个请求是刚才提到的特殊请求,那么路由器就将完整的路由表发送 给请求者。否则,就处理请求中的每一个表项:如果有连接到指明地址的路由,则将度 量设置成我们的值,否则将度量置为 1 6(度量为1 6是一种称为“无穷大”的特殊值,它 意味着没有到达目的的路由)。然后发回响应。 • 接收到响应。使响应生效,可能会更新路由表。可能会增加新表项,对已有的表项进行 修改,或是将已有表项删除。 • 定期选路更新。每过3 0秒,所有或部分路由器会将其完整路由表发送给相邻路由器。发 送路由表可以是广播形式的(如在以太网上),或是发送给点对点链路的其他终点的。 第10章 动态选路协议使用97 命令 地址系列(2) 32位IP地址 (必须为0) (必须为0) 度量(1-16) (最多可有24个另外的路由,与前20字节具有相同的格式) 版本 (必须为0) (必须为0) 字节• 触发更新。每当一条路由的度量发生变化时,就对它进行更新。不需要发送完整路由表, 而只需要发送那些发生变化的表项。 每条路由都有与之相关的定时器。如果运行 R I P的系统发现一条路由在 3分钟内未更新, 就将该路由的度量设置成无穷大( 1 6),并标注为删除。这意味着已经在 6个3 0秒更新时间里 没收到通告该路由的路由器的更新了。再过 6 0秒,将从本地路由表中删除该路由,以保证该 路由的失效已被传播开。 10.4.3 度量 R I P所使用的度量是以跳 ( h o p )计算的。所有直接连接接口的跳数为 1。考虑图1 0 - 4所示的 路由器和网络。画出的 4条虚线是广播 R I P 报文。 路由器R 1通过发送广播到 N 1通告它与 N 2之间的跳数是 1(发送给 N 1的广播中通 告它与N 1之间的路由是无用的)。同时也通 过发送广播给N 2通告它与N 1之间的跳数为 1。同样,R 2通告它与N 2的度量为1,与N 3 的度量为1。 如果相邻路由器通告它与其他网络路 由的跳数为1,那么我们与那个网络的度量就是 2,这是因为为了发送报文到该网络,我们必 须经过那个路由器。在我们的例子中, R 2到N 1的度量是2,与R 1到N 3的度量一样。 由于每个路由器都发送其路由表给邻站,因此,可以判断在同一个自治系统 A S内到每个 网络的路由。如果在该 A S内从一个路由器到一个网络有多条路由,那么路由器将选择跳数最 小的路由,而忽略其他路由。 跳数的最大值是 1 5,这意味着R I P只能用在主机间最大跳数值为 1 5的A S内。度量为1 6表 示到无路由到达该I P地址。 10.4.4 问题 这种方法看起来很简单,但它有一些缺陷。首先, R I P没有子网地址的概念。例如,如果 标准的B类地址中16 bit的主机号不为0,那么R I P无法区分非零部分是一个子网号,或者是一个 主机地址。有一些实现中通过接收到的R I P信息,来使用接口的网络掩码,而这有可能出错。 其次,在路由器或链路发生故障后,需要很长的一段时间才能稳定下来。这段时间通常 需要几分钟。在这段建立时间里,可能会发生路由环路。在实现 R I P时,必须采用很多微妙的 措施来防止路由环路的出现,并使其尽快建立。 RFC 1058 [Hedrick 1988a]中指出了很多实现 R I P的细节。 采用跳数作为路由度量忽略了其他一些应该考虑的因素。同时,度量最大值为 1 5则限制 了可以使用R I P的网络的大小。 10.4.5 举例 我们将使用r i p q u e r y程序来查询一些路由器中的路由表,该程序可以从 g a t e d中得到。 98使用TCP/IP详解,卷1:协议 图10-4 路由器和网络示例 经过R1到N1的一 条跳数为2的路由 经过R2到N3的一 条跳数为2的路由r i p q u e r y程序通过发送一个非正式请求(图 1 0 - 3中命令字段为5的“p o l l”)给路由器,要求 得到其完整的路由表。如果在 5秒内未收到响应,则发送标准的 R I P请求(c o m m a n d字段为1) (前面提到过的,将地址系列字段置为 0,度量字段置为 1 6的请求,要求其他路由器发送其完 整路由表)。 图1 0 - 5给出了将从 s u n主机上查询其路由表的两个路由器。如果在主机 s u n上执行 r i p q u e r y程序,以得到其下一站路由器 n e t b的选路信息,那么可以得到下面的结果: sun % ripquery -n netb 504 bytes from netb (140.252.1.183):第一份报文包含5 0 4字节 这里删除了许多行 140.252.1.0, metric 1 图1 0 - 5中上面的以太网 140.252.13.0, metric 1 图1 0 - 5中下面的以太网 244 bytes from netb (140.252.1.183): 第二份报文包含剩下的2 4 4字节下面删除了许多行 正如我们所猜想的那样, n e t b告诉我们子网的度量为 1。另外,与n e t b相连的位于机端 的以太网(1 4 0 . 2 5 2 . 1 . 0)的m e t r i c也是1(-n参数表示 直接打印 I P地址而不需要去查看其域名)。在本例中, 将n e t b配置成认为所有位于 1 4 0 . 2 5 2 . 1 3子网的主机都与 其直接相连— 即, n e t b 并不知道哪些主机真正与 1 4 0 . 2 5 2 . 1 3子网相连。由于与 1 4 0 . 2 5 2 . 1 3子网只有一个 连接点,因此,通告每个主机的度量实际上没有太大意 义。 图1 0 - 6给出了使用 t c p d u m p交换的报文。采用 - i s 1 0选项指定S L I P接口。 第1个请求发出一个R I P轮询命令(第1行)。这个请 求在 5秒后超时,发出一个常规的 R I P请求(第 2行)。 第1行和第2行最后的2 4表示请求报文的长度: 4个字节 的R I P首部(包括命令和版本),然后是单个 2 0字节的 地址和度量。 第3行是第一个应答报文。该行最后的 2 5表示包含了2 5个地址和度量对,我们在前面已经 计算过,其字节数为5 0 4。这是上面的r i p q u e r y程序所打印出来的结果。我们为 t c p d u m p程 序指定- s 6 0 0选项,以让它从网络中读取 6 0 0个字节。这样,它可以接收整个 U D P数据报(而 不是报文的前半部),然后打印出R I P响应的内容。该输出结果省略了。 图10-6 运行r i p q u e r y 程序的t c p d u m p 输出结果 第4行是来自路由器的第二个响应报文,它包含后面的 1 2个地址和度量对。可以计算出该 报文的长度为1 2×20 + 4=244,这正是r i p q u e r y程序所打印出来的结果。 如果越过n e t b路由器,到g a t e w a y,那么可以预测到我们子网( 1 4 0 . 2 5 2 . 1 3 . 0)的度量 为2。可以运行下面的命令来进行验证: 第10章 动态选路协议使用99 图10-5 查询其路由表内容的两个 路由器n e t b 和g a t e w a ysun % ripquery -n gateway 504 bytes from gateway (140.252.1.4): 这里删除了许多行 140.252.1.0, metric 1 图1 0 - 5上面的以太网 140.252.13.0, metric 2 图1 0 - 5下面的以太网 这里,位于图1 0 - 5上面的以太网(1 4 0 . 2 5 2 . 1 . 0)的度量依然是1,这是因为该以太网直接 与g a t e w a y和n e t b相连。而我们的子网1 4 0 . 2 5 2 . 1 3 . 0正如预想的一样,其度量为 2。 10.4.6 另一个例子 现在察看以太网上所有非主动请求的R I P更新,以看一看R I P定期给其邻站发送的信息。图1 0 - 7 是n o a o . e d u网络的多种排列情况。为了简化,我们不用本文其他地方所采用的路由器表示方式, 而以R n来代表路由器,其中n是子网号。以虚线表示点对点链路,并给出了这些链路对端的I P地址。 图10-7 noao.edu 140.252的多个网络 在主机s o l a r i s上运行Solaris 2.x的s n o o p程序,它与t c p d u m p相类似。我们可以在不 需要超用户权限的条件下运行该程序,但它只捕获广播报文、多播报文以及发送给主机的报 文。图1 0 - 8给出了在6 0秒内所捕获的报文。在这里,我们将大部分正式的主机名以 Rn来表示。 -P标志以非混杂模式捕获报文,- t r打印出相应的时戳,而udp port 520只捕获信源 或信宿端口号为5 2 0的U D P数据报。 来自R 6、R 4、R 2、R 7、R 8和R 3的前6个报文,每个报文只通告一个网络。查看这些报文, 可以发现R 2通告前往1 4 0 . 2 5 2 . 6 . 0的跳数为1的一条路由,R 4通告前往1 4 0 . 2 5 2 . 4 . 0的跳数为1的 一条路由,等等。 但是,g a t e w a y路由器却通告了1 5条路由。我们可以通过运行 s n o o p程序时加上-v参数 来查看R I P报文的全部内容(这个标志输出全部报文的全部内容:以太网首部、 I P首部、U D P 首部以及R I P报文。我们只保留了R I P信息而删除了其他信息)。图1 0 - 9给出了输出结果。 100使用TCP/IP详解,卷1:协议图10-8 s o l a r i s 在60秒内所捕获到的RIP广播报文 把这些子网1 4 0 . 2 5 2 . 1上通告报文经过的路由与图 1 0 - 7中的拓扑结构进行比较。 使人迷惑不解的一个问题是为什么图 1 0 - 8输出结果中, R 1 0通告其有4个网络而在图 1 0 - 7 中显示的只有3个。如果查看带s n o o p的R I P报文,就会得到以下通告路由: R I P: Address Metric RIP: 140.251.0.0 16 (not reachable) RIP: 140.252.9.0 1 RIP: 140.252.10.0 1 RIP: 140.252.11.0 1 前往B类网络1 4 0 . 2 5 1的路由是假的,不应该通告它(它属于其他机构而不是n o a o . e d u)。 图10-9 来自g a t e w a y 的RIP响应 图1 0 - 8中,对于 R 1 0发送的R I P报文,s n o o p输出“B R O A D C A S T”符号,它表示目的I P 地址是有限的广播地址 2 5 5 . 2 5 5 . 2 5 5 . 2 5 5(1 2 . 2节),而不是其他路由器用来指向子网的广播地 第10章 动态选路协议使用101 删去许多行址(1 4 0 . 2 5 2 . 1 . 2 5 5)。 10.5 RIP版本2 RFC 1388 [Malkin 1993a]中对R I P定义进行了扩充,通常称其结果为 R I P - 2。这些扩充并 不改变协议本身,而是利用图 1 0 - 3中的一些标注为“必须为0”的字段来传递一些额外的信息。 如果R I P忽略这些必须为0的字段,那么,R I P和R I P - 2可以互操作。 图1 0 - 1 0重新给出了由R I P - 2定义的图。对于R I P - 2来说,其版本字段为2。 图10-10 RIP-2报文格式 选路域(routing domain)是一个选路守护程序的标识符,它指出了这个数据报的所有者。 在一个U n i x实现中,它可以是选路守护程序的进程号。该域允许管理者在单个路由器上运行 多个R I P实例,每个实例在一个选路域内运行。 选路标记(routing tag)是为了支持外部网关协议而存在的。它携带着一个 E G P和B G P的自 治系统号。 每个表项的子网掩码应用于相应的 I P地址上。下一站I P地址指明发往目的I P地址的报文该 发往哪里。该字段为0意味着发往目的地址的报文应该发给发送 R I P报文的系统。 R I P - 2提供了一种简单的鉴别机制。可以指定 R I P报文的前2 0字节表项地址系列为 0 x ffff, 路由标记为2。表项中的其余1 6字节包含一个明文口令。 最后,R I P - 2除了广播(第 1 2章)外,还支持多播。这可以减少不收听 R I P - 2报文的主机 的负载。 10.6 OSPF:开放最短路径优先 O S P F是除R I P外的另一个内部网关协议。它克服了 R I P的所有限制。 RFC 1247 [Moy 1 9 9 1 ]中对第2版O S P F进行了描述。 与采用距离向量的 R I P协议不同的是, O S P F是一个链路状态协议。距离向量的意思是, R I P发送的报文包含一个距离向量(跳数)。每个路由器都根据它所接收到邻站的这些距离向 102使用TCP/IP详解,卷1:协议 命令(1-6) 版本(2) 路由域 路由标记 20字节 地址类(2) 32位IP地址 32位子网掩码 32位下一站IP地位 度量(1-16) (最多超过24个路由,与前20字节具有相同的格式)量来更新自己的路由表。 在一个链路状态协议中,路由器并不与其邻站交换距离信息。它采用的是每个路由器主 动地测试与其邻站相连链路的状态,将这些信息发送给它的其他邻站,而邻站将这些信息在 自治系统中传播出去。每个路由器接收这些链路状态信息,并建立起完整的路由表。 从实际角度来看,二者的不同点是链路状态协议总是比距离向量协议收敛更快。收敛的 意思是在路由发生变化后,例如在路由器关闭或链路出故障后,可以稳定下来。 [ P e r l m a n 1 9 9 2 ]的9 . 3节对这两种类型的选路协议的其他方面进行了比较。 O S P F与R I P(以及其他选路协议)的不同点在于, O S P F直接使用I P。也就是说,它并不 使用U D P或T C P。对于I P首部的p r o t o c o l字段,O S P F有其自己的值(图3 - 1)。 另外,作为一种链路状态协议而不是距离向量协议, O S P F还有着一些优于R I P的特点。 1) OSPF可以对每个 I P服务类型(图 3 - 2)计算各自的路由集。这意味着对于任何目的, 可以有多个路由表表项,每个表项对应着一个 I P服务类型。 2) 给每个接口指派一个无维数的费用。可以通过吞吐率、往返时间、可靠性或其他性能 来进行指派。可以给每个I P服务类型指派一个单独的费用。 3) 当对同一个目的地址存在着多个相同费用的路由时,O S P F在这些路由上平均分配流量。 我们称之为流量平衡。 4) OSPF支持子网:子网掩码与每个通告路由相连。这样就允许将一个任何类型的 I P地址 分割成多个不同大小的子网(我们在 3 . 7节中给出了这样的一个例子,称之为变长度子网)。 到一个主机的路由是通过全 1子网掩码进行通告的。默认路由是以 I P地址为0 . 0 . 0 . 0、网络掩码 为全0进行通告的。 5) 路由器之间的点对点链路不需要每端都有一个 I P地址,我们称之为无编号网络。这样 可以节省I P地址— 现在非常紧缺的一种资源。 6) 采用了一种简单鉴别机制。可以采用类似于 R I P - 2机制(1 0 . 5节)的方法指定一个明文 口令。 7) OSPF采用多播(第1 2章),而不是广播形式,以减少不参与 O S P F的系统负载。 随着大部分厂商支持O S P F,在很多网络中O S P F将逐步取代R I P。 10.7 BGP:边界网关协议 B G P是一种不同自治系统的路由器之间进行通信的外部网关协议。 B G P是A R PA N E T所使 用的老E G P的取代品。RFC1267 [Lougheed and Rekhter 1991] 对第3版的B G P进行了描述。 RFC 1268 [Rekhter and Gross 1991] 描述了如何在I n t e r n e t中使用B G P。下面对于B G P的大 部分描述都来自于这两个 R F C文档。同时,1 9 9 3年开发第4版的B G P(见RFC 1467 [To p o l c i c 1 9 9 3 ]),以支持我们将在1 0 . 8节描述的C I D R。 B G P系统与其他B G P系统之间交换网络可到达信息。这些信息包括数据到达这些网络所 必须经过的自治系统 A S中的所有路径。这些信息足以构造一幅自治系统连接图。然后,可以 根据连接图删除选路环,制订选路策略。 首先,我们将一个自治系统中的 I P数据报分成本地流量和通过流量。在自治系统中,本 地流量是起始或终止于该自治系统的流量。也就是说,其信源 I P地址或信宿I P地址所指定的 主机位于该自治系统中。其他的流量则称为通过流量。在 I n t e r n e t中使用B G P的一个目的就是 第10章 动态选路协议使用103减少通过流量。 可以将自治系统分为以下几种类型: 1) 残桩自治系统(stub AS),它与其他自治系统只有单个连接。 stub AS只有本地流量。 2) 多接口自治系统(multihomed AS),它与其他自治系统有多个连接,但拒绝传送通过流 量。 3) 转送自治系统(transit AS),它与其他自治系统有多个连接,在一些策略准则之下,它 可以传送本地流量和通过流量。 这样,可以将I n t e r n e t的总拓扑结构看成是由一些残桩自治系统、多接口自治系统以及转 送自治系统的任意互连。残桩自治系统和多接口自治系统不需要使用 B G P——它们通过运行 E G P在自治系统之间交换可到达信息。 B G P允许使用基于策略的选路。由自治系统管理员制订策略,并通过配置文件将策略指 定给B G P。制订策略并不是协议的一部分,但指定策略允许 B G P实现在存在多个可选路径时 选择路径,并控制信息的重发送。选路策略与政治、安全或经济因素有关。 B G P与R I P和O S P F的不同之处在于B G P使用T C P作为其传输层协议。两个运行 B G P的系统 之间建立一条T C P连接,然后交换整个 B G P路由表。从这个时候开始,在路由表发生变化时, 再发送更新信号。 B G P是一个距离向量协议,但是与(通告到目的地址跳数的) R I P不同的是,B G P列举了 到每个目的地址的路由(自治系统到达目的地址的序列号)。这样就排除了一些距离向量协议 的问题。采用16 bit 数字表示自治系统标识。 B G P通过定期发送k e e p a l i v e报文给其邻站来检测T C P连接对端的链路或主机失败。两个报 文之间的时间间隔建议值为 3 0秒。应用层的 k e e p a l i v e报文与T C P的k e e p a l i v e选项(第2 3章) 是独立的。 10.8 CIDR:无类型域间选路 在第3章中,我们指出了 B类地址的缺乏,因此现在的多个网络站点只能采用多个 C类网 络号,而不采用单个 B类网络号。尽管分配这些 C类地址解决了一个问题( B类地址的缺乏), 但它却带来了另一个问题:每个 C类网络都需要一个路由表表项。无类型域间选路( C I D R) 是一个防止I n t e r n e t路由表膨胀的方法,它也称为超网( s u p e r n e t t i n g)。在RFC 1518 [Rekher and Li 1993] 和RFC 1519 [Fuller et al. 1993]中对它进行了描述,而[Ford, Rekhter, and Braun 1 9 9 3 ]是它的综述。C I D R有一个Internet Architecture Board’s blessing [Huitema 1993]。R F C 1467 [Topolcic 1993] 对I n t e r n e t中C I D R的开发状况进行了小结。 C I D R的基本观点是采用一种分配多个 I P地址的方式,使其能够将路由表中的许多表项总 和( s u m m a r i z a t i o n )成更少的数目。例如,如果给单个站点分配 1 6个C类地址,以一种可以用总 和的方式来分配这 1 6个地址,这样,所有这 1 6个地址可以参照 I n t e r n e t上的单个路由表表项。 同时,如果有8个不同的站点是通过同一个 I n t e r n e t服务提供商的同一个连接点接入 I n t e r n e t的, 且这8个站点分配的8个不同I P地址可以进行总和,那么,对于这 8个站点,在I n t e r n e t上,只需 要单个路由表表项。 要使用这种总和,必须满足以下三种特性: 1) 为进行选路要对多个I P地址进行总和时,这些I P地址必须具有相同的高位地址比特。 104使用TCP/IP详解,卷1:协议2) 路由表和选路算法必须扩展成根据 32 bit IP地址和32 bit掩码做出选路决策。 3) 必须扩展选路协议使其除了 32 bit地址外,还要有32 bit掩码。O S P F(1 0 . 6节)和R I P - 2 (1 0 . 5节)都能够携带第4版B G P所提出的32 bit掩码。 例 如 , RFC 1466 [Gerich 1993] 建 议 欧 洲 新 的 C类 地 址 的 范 围 是 1 9 4 . 0 . 0 . 0~ 1 9 5 . 2 5 5 . 2 5 5 . 2 5 5。以1 6进制表示,这些地址的范围是 0 x c 2 0 0 0 0 0 0~0 x c 3 ffffff。它代表了6 5 5 3 6 个不同的C类网络号,但它们地址的高 7 bit是相同的。在欧洲以外的国家里,可以采用 I P地址 为0 x c 2 0 0 0 0 0 0和32 bit 0xfe000000 (254.0.0.0) 为掩码的单个路由表表项来对所有这些 6 5 5 3 6个 C类网络号选路到单个点上。 C类地址的后面各比特位(即在 1 9 4或1 9 5后面各比特)也可以进 行层次分配,例如以国家或服务提供商分配,以允许对在欧洲路由器之间使用除了这 32 bit掩 码的高7 bit外的其他比特进行概括。 C I D R同时还使用一种技术,使最佳匹配总是最长的匹配:即在 32 bit掩码中,它具有最 大值。我们继续采用上一段中所用的例子,欧洲的一个服务提供商可能会采用一个与其他欧 洲服务提供商不同的接入点。如果给该提供商分配的地址组是从 1 9 4 . 0 . 1 6 . 0到194.0.31.255 (16 个 C 类网络号 ),那么可能只有这些网络的路由表项的 I P地址是 1 9 4 . 0 . 1 6 . 0 ,掩码为 255.255.240.0 (0xfffff 0 0 0 )。发往1 9 4 . 0 . 2 2 . 1地址的数据报将同时与这个路由表表项和其他欧洲 C类地址的表项进行匹配。但是由于掩码 2 5 5 . 2 5 5 . 2 4 0比2 5 4 . 0 . 0 . 0更“长”,因此将采用具有更 长掩码的路由表表项。 “无类型”的意思是现在的选路决策是基于整个 32 bit IP地址的掩码操作,而不管其 I P地 址是A类、B类或是C类,都没有什么区别。 C I D R最初是针对新的C类地址提出的。这种变化将使 I n t e r n e t路由表增长的速度缓慢下来, 但对于现存的选路则没有任何帮助。这是一个短期解决方案。作为一个长期解决方案,如果将 C I D R应用于所有I P地址,并根据各洲边界和服务提供商对已经存在的 I P地址进行重新分配(且 所有现有主机重新进行编址!),那么[Ford, Rekhter, and Braun 1993] 宣称,目前包含10 000网 络表项的路由表将会减少成只有2 0 0个表项。 10.9 小结 有两种基本的选路协议,即用于同一自治系统各路由器之间的内部网关协议( I G P)和用 于不同自治系统内路由器通信的外部网关协议( E G P)。 最常用的I G P是路由信息协议(R I P),而O S P F是一个正在得到广泛使用的新 I G P。一种新 近流行的E G P是边界网关协议(B G P)。在本章中,我们讨论了 R I P及其交换的报文类型。第 2 版R I P是其最近的一个改进版,它支持子网,还有一些其他改进技术。同时也对 O S P F、B G P 和无类型域间选路( C I D R)进行了描述。 C I D R是一种新技术,可以减小 I n t e r n e t路由表的大 小。 你可能还会遇到一些其他的 O S I选路协议。域间选路协议( I D R P)最开始时,是一个为 了使用O S I地址而不是I P地址,而进行修改的 B G P版本。Intermediate System to Intermediate System 协议(I S - I S)是O S I的标准I G P。可以用它来选路 C L N P(无连接网络协议),这是一 种与I P类似的O S I协议。I S - I S和O S P F相似。 动态选路仍然是一个网间互连的研究热点。对使用的选路协议和运行的路由守护程序进 行选择,是一项复杂的工作。 [Perlman 1992]提供了许多细节。 第10章 动态选路协议使用105习题 10.1 在图1 0 - 9中哪些路由是从路由器k p n o进入g a t e w a y的? 10.2 假设一个路由器要使用R I P通告3 0个路由,这需要一个包含2 5条路由和另一个包含5条路 由的数据报。如果每过一个小时,第一个包含 2 5条路由的数据报丢失一次,那么其结果 如何? 10.3 OSPF报文格式中有一个检验和字段,而 R I P报文则没有此项,这是为什么? 10.4 像O S P F这样的负载平衡,对于传输层的影响是什么? 10.5 查阅RFC1058 关于实现R I P的其他资料。在图1 0 - 8中,1 4 0 . 2 5 2 . 1网络的每个路由器只通 告它所提供的路由,而它并不能通过其他路由器的广播中知道任何其他路由。这种技术 的名称是什么? 10.6 在3 . 4节中,我们说过除了图1 0 - 7中所示的8个路由器外,1 4 0 . 2 5 2 . 1子网上还有超过1 0 0个主 机。那么这100个主机是如何处理每30秒到达它们的8个广播信息呢(图10-8)? 106使用TCP/IP详解,卷1:协议第11章 UDP:用户数据报协议 11.1 引言 U D P是一个简单的面向数据报的运输层协议:进程的每个输出操作都正好产生一个 U D P 数据报,并组装成一份待发送的 I P数据报。 这与面向流字符的协议不同,如 T C P,应用 程序产生的全体数据与真正发送的单个 I P数 据报可能没有什么联系。 U D P数据报封装成一份 I P数据报的格式 如图11 - 1所示。 RFC 768 [Postel 1980] 是U D P的正式规 范。 U D P不提供可靠性:它把应用程序传给 I P层的数据发送出去,但是并不保证它们能到达 目的地。由于缺乏可靠性,我们似乎觉得要避免使用 U D P而使用一种可靠协议如 T C P。我们 在第1 7章讨论完T C P后将再回到这个话题,看看什么样的应用程序可以使用 U D P。 应用程序必须关心 I P数据报的长度。如果它超过网络的 M T U(2 . 8节),那么就要对 I P数 据报进行分片。如果需要,源端到目的端之间的每个网络都要进行分片,并不只是发送端主 机连接第一个网络才这样做(我们在 2 . 9节中已定义了路径 M T U的概念)。在11 . 5节中,我们 将讨论I P分片机制。 11.2 UDP首部 U D P首部的各字段如图11 - 2所示。 图11-2 UDP首部 端口号表示发送进程和接收进程。在图 1 - 8中,我们画出了T C P和U D P用目的端口号来分 用来自I P层的数据的过程。由于 I P层已经把I P数据报分配给T C P或U D P(根据I P首部中协议字 段值),因此T C P端口号由T C P来查看,而U D P端口号由U D P来查看。T C P端口号与U D P端口 号是相互独立的。 图11-1 UDP封装 IP数据报 UDP数据报 首部 UDP 首部 UDP数据 20字节 8字节 16位源端口号 16位目的端口号 16位UDP长度 16位UDP检验和 数据(如果有) 8字节尽管相互独立,如果T C P和U D P同时提供某种知名服务,两个协议通常选择相同 的端口号。这纯粹是为了使用方便,而不是协议本身的要求。 U D P长度字段指的是U D P首部和U D P数据的字节长度。该字段的最小值为 8字节(发送一 份0字节的 U D P数据报是O K)。这个 U D P长度是有冗余的。 I P数据报长度指的是数据报全长 (图3 - 1),因此U D P数据报长度是全长减去 I P首部的长度(该值在首部长度字段中指定,如图 3 - 1所示)。 11.3 UDP检验和 U D P检验和覆盖U D P首部和U D P数据。回想I P首部的检验和,它只覆盖 I P的首部— 并不 覆盖I P数据报中的任何数据。 U D P和T C P在首部中都有覆盖它们首部和数据的检验和。 U D P的检验和是可选的,而T C P 的检验和是必需的。 尽管U D P检验和的基本计算方法与我们在 3 . 2节中描述的 I P首部检验和计算方法相类似 (16 bit字的二进制反码和),但是它们之间存在不同的地方。首先, U D P数据报的长度可以为 奇数字节,但是检验和算法是把若干个 16 bit字相加。解决方法是必要时在最后增加填充字节 0,这只是为了检验和的计算(也就是说,可能增加的填充字节不被传送)。 其次,U D P数据报和T C P段都包含一个 1 2字节长的伪首部,它是为了计算检验和而设置 的。伪首部包含 I P首部一些字段。其目的是让 U D P两次检查数据是否已经正确到达目的地 (例如,I P没有接受地址不是本主机的数据报,以及 I P没有把应传给另一高层的数据报传给 U D P)。U D P数据报中的伪首部格式如图 11 - 3所示。 图11-3 UDP检验和计算过程中使用的各个字段 在该图中,我们特地举了一个奇数长度的数据报例子,因而在计算检验和时需要加上填 充字节。注意,U D P数据报的长度在检验和计算过程中出现两次。 如果检验和的计算结果为 0,则存入的值为全 1(6 5 5 3 5),这在二进制反码计算中是等效 的。如果传送的检验和为0,说明发送端没有计算检验和。 108使用TCP/IP详解,卷1:协议 32位源IP地址 32位目的IP地址 0 8位协议(17) 16位UDP长度 16位目的端口号 16位UDP检验和 UDP首部 UDP伪首部 16位源端口号 16位UDP长度 数据 填充字节(0)如果发送端没有计算检验和而接收端检测到检验和有差错,那么 U D P数据报就要被悄悄 地丢弃。不产生任何差错报文(当 I P层检测到I P首部检验和有差错时也这样做)。 U D P检验和是一个端到端的检验和。它由发送端计算,然后由接收端验证。其目的是为 了发现U D P首部和数据在发送端到接收端之间发生的任何改动。 尽管U D P检验和是可选的,但是它们应该总是在用。在 8 0年代,一些计算机产商在默认 条件下关闭U D P检验和的功能,以提高使用 U D P协议的N F S(Network File System)的速度。 在单个局域网中这可能是可以接受的,但是在数据报通过路由器时,通过对链路层数据帧进 行循环冗余检验(如以太网或令牌环数据帧)可以检测到大多数的差错,导致传输失败。不 管相信与否,路由器中也存在软件和硬件差错,以致于修改数据报中的数据。如果关闭端到 端的U D P检验和功能,那么这些差错在 U D P数据报中就不能被检测出来。另外,一些数据链 路层协议(如S L I P)没有任何形式的数据链路检验和。 Host Requirements RFC声明,U D P检验和选项在默认条件下是打开的。它还声明, 如果发送端已经计算了检验和,那么接收端必须检验接收到的检验和(如接收到检验 和不为0)。但是,许多系统没有遵守这一点,只是在出口检验和选项被打开时才验证 接收到的检验和。 11.3.1 tcpdump输出 很难知道某个特定系统是否打开了 U D P检验和选项。应用程序通常不可能得到接收到的 U D P首部中的检验和。为了得到这一点,作者在 t c p d u m p程序中增加了一个选项,以打印出 接收到的U D P检验和。如果打印出的值为 0,说明发送端没有计算检验和。 测试网络上三个不同系统的输出如图 11 - 4所示(参见封面二)。运行我们自编的 s o c k程序 (附录C),发送一份包含9个字节数据的U D P数据报给标准回显服务器。 图11-4 t c p d u m p 输出,观察其他主机是否打开UDP检验和选项 从这里可以看出,三个系统中有两个打开了 U D P检验和选项。 还要注意的是,在这个简单例子中,送出的数据报与收到的数据报具有相同的检验和值 (第3和第4行,第5和第6行)。从图11-3可以看出,两个IP地址进行了交换,正如两个端口号一样。 伪首部和U D P首部中的其他字段都是相同的,就像数据回显一样。这再次表明 U D P检验和(事 实上,TCP/IP协议簇中所有的检验和)是简单的16 bit和。它们检测不出交换两个16 bit的差错。 作者在1 4 . 2节中在8个域名服务器中各进行了一次 D N S查询。D N S主要使用U D P, 结果只有两台服务器打开了UDP检验和选项。 11.3.2 一些统计结果 文献[Mogul 1992 ]提供了在一个繁忙的N F S服务器上所发生的不同检验和差错的统计结果, 第11章 UDP:用户数据报协议使用109时间持续了 4 0天。统计数字结果如图 11 - 5所 示。 最后一列是每一行的大概总数,因为以 太网和I P层还使用其他的协议。例如,不是 所有的以太网数据帧都是 I P数据报,至少以 太网还要使用 A R P协议。不是所有的 I P数据 报都是U D P或T C P数据,因为I C M P也用I P传送数据。 注意,T C P发生检验和差错的比例与 U D P相比要高得多。这很可能是因为在该系统中的 T C P连接经常是“远程”连接(经过许多路由器和网桥等中间设备),而U D P一般为本地通信。 从最后一行可以看出,不要完全相信数据链路(如以太网,令牌环等)的 C R C检验。应 该始终打开端到端的检验和功能。而且,如果你的数据很有价值,也不要完全相信 U D P或 T C P的检验和,因为这些都只是简单的检验和,不能检测出所有可能发生的差错。 11.4 一个简单的例子 用我们自己编写的s o c k程序生成一些可以通过t c p d u m p观察的U D P数据报: bsdi % sock -v -u -i -n4 svr4 discard connected on 140.252.13.35.1108 to 140.252.13.34.9 bsdi % sock -v -u -i -n4 -w0 svr4 discard connected on 140.252.13.35.1110 to 140.252.13.34.9 第1次执行这个程序时,我们指定 v e r b o s e模式(- v)来观察e p h e m e r a l端口号,指定U D P (- u)而不是默认的 T C P,并且指定源模式( - i)来发送数据,而不是读写标准的输入和输 出。- n 4选项指明输出4份数据报(默认条件下为 1 0 2 4),目的主机为s v r 4。在1 . 1 2节描述了丢 弃服务。每次写操作的输出长度取默认值 1 0 2 4。 第2次运行该程序时我们指定 - w 0,意思是写长度为 0的数据报。两个命令的 t c p d u m p输 出结果如图11 - 6所示。 图11-6 向一个方向发送UDP数据报时的t c p d u m p 输出 输出显示有四份1 0 2 4字节的数据报,接着有四份长度为 0的数据报。每份数据报间隔几毫 秒(输入第2个命令花了4 1秒的时间)。 在发送第1份数据报之前,发送端和接收端之间没有任何通信(在第 1 7章,我们将看到 T C P在发送数据的第 1个字节之前必须与另一端建立连接)。另外,当收到数据时,接收端没 有任何确认。在这个例子中,发送端并不知道另一端是否已经收到这些数据报。 最后要指出的是,每次运行程序时,源端的 U D P端口号都发生变化。第一次是 11 0 8,然 后是11 0。在1 . 9节我们已经提过,客户程序使用 e p h e m e r a l端口号一般在1 0 2 4~5 0 0 0之间,正 110使用TCP/IP详解,卷1:协议 图11-5 检测到不同检验和差错的分组统计结果 层 次 以太网 检验和差错数 近似总分组数如我们现在看到的这样。 11.5 IP分片 正如我们在2 . 8节描述的那样,物理网络层一般要限制每次发送数据帧的最大长度。任何 时候I P层接收到一份要发送的 I P数据报时,它要判断向本地哪个接口发送数据(选路),并查 询该接口获得其M T U。I P把M T U与数据报长度进行比较,如果需要则进行分片。分片可以发 生在原始发送端主机上,也可以发生在中间路由器上。 把一份I P数据报分片以后,只有到达目的地才进行重新组装(这里的重新组装与其他网 络协议不同,它们要求在下一站就进行进行重新组装,而不是在最终的目的地)。重新组装由 目的端的 I P层来完成,其目的是使分片和重新组装过程对运输层( T C P和U D P)是透明的, 除了某些可能的越级操作外。已经分片过的数据报有可能会再次进行分片(可能不止一次)。 I P首部中包含的数据为分片和重新组装提供了足够的信息。 回忆I P首部(图3 - 1),下面这些字段用于分片过程。对于发送端发送的每份 I P数据报来说, 其标识字段都包含一个唯一值。该值在数据报分片时被复制到每个片中(我们现在已经看到 这个字段的用途)。标志字段用其中一个比特来表示“更多的片”。除了最后一片外,其他每 个组成数据报的片都要把该比特置 1。片偏移字段指的是该片偏移原始数据报开始处的位置。 另外,当数据报被分片后,每个片的总长度值要改为该片的长度值。 最后,标志字段中有一个比特称作“不分片”位。如果将这一比特置 1,I P将不对数据报 进行分片。相反把数据报丢弃并发送一个 I C M P差错报文(“需要进行分片但设置了不分片比 特”,见图6 - 3)给起始端。在下一节我们将看到出现这个差错的例子。 当I P数据报被分片后,每一片都成为一个分组,具有自己的 I P首部,并在选择路由时与 其他分组独立。这样,当数据报的这些片到达目的端时有可能会失序,但是在 I P首部中有足 够的信息让接收端能正确组装这些数据报片。 尽管I P分片过程看起来是透明的,但有一点让人不想使用它:即使只丢失一片数据也要重 传整个数据报。为什么会发生这种情况呢?因为 I P层本身没有超时重传的机制——由更高层来 负责超时和重传(T C P有超时和重传机制,但U D P没有。一些U D P应用程序本身也执行超时和 重传)。当来自T C P报文段的某一片丢失后,T C P在超时后会重发整个T C P报文段,该报文段对 应于一份I P数据报。没有办法只重传数据报中的一个数据报片。事实上,如果对数据报分片的 是中间路由器,而不是起始端系统,那么起始端系统就无法知道数据报是如何被分片的。就这 个原因,经常要避免分片。文献[Kent and Mogul 1987]对避免分片进行了论述。 使用U D P很容易导致I P分片(在后面我们将看到, T C P试图避免分片,但对于应用程序来 说几乎不可能强迫 T C P发送一个需要进行分片的长报文段)。我们可以用 s o c k程序来增加数 据报的长度,直到分片发生。在一个以太网上,数据帧的最大长度是 1 5 0 0字节(见图 2 - 1), 其中1 4 7 2字节留给数据,假定 I P首部为2 0字节, U D P首部为8字节。我们分别以数据长度为 1471, 1472, 1473和1 4 7 4字节运行s o c k程序。最后两次应该发生分片: bsdi % sock -u -i -nl -w1471 svr4 discard bsdi % sock -u -i -nl -w1472 svr4 discard bsdi % sock -u -i -nl -w1473 svr4 discard bsdi % sock -u -i -nl -w1474 svr4 discard 相应的t c p d u m p输出如图11 - 7所示。 第11章 UDP:用户数据报协议使用111图11-7 观察UDP数据报分片 前两份U D P数据报(第1行和第2行)能装入以太网数据帧,没有被分片。但是对应于写 1 4 7 3字节的I P数据报长度为1 5 0 1,就必须进行分片(第3行和第4行)。同理,写1 4 7 4字节产生 的数据报长度为1 5 0 2,它也需要进行分片(第5行和第6行)。 当I P数据报被分片后,t c p d u m p打印出其他的信息。首先, frag 26304(第3行和第4 行)和frag 26313(第5行和第6行)指的是I P首部中标识字段的值。 分片信息中的下一个数字,即第 3行中位于冒号和@号之间的1 4 8 0,是除I P首部外的片长。 两份数据报第一片的长度均为 1 4 8 0:U D P首部占8字节,用户数据占1 4 7 2字节(加上I P首部的 2 0字节分组长度正好为 1 5 0 0字节)。第1份数据报的第2片(第4行)只包含1字节数据— 剩下 的用户数据。第2份数据报的第2片(第6行)包含剩下的2字节用户数据。 在分片时,除最后一片外,其他每一片中的数据部分(除 I P首部外的其余部分)必须是 8 字节的整数倍。在本例中, 1 4 8 0是8的整数倍。 位于@符号后的数字是从数据报开始处计算的片偏移值。两份数据报第1片的偏移值均为0(第3行 和第5行),第2片的偏移值为1 4 8 0(第4行和第6行)。跟在偏移值后面的加号对应于I P首部中3 bit标志 字段中的“更多片”比特。设置这一比特的目的是让接收端知道在什么时候完成所有的分片组装。 最后,注意第4行和第6行(不是第1片)省略了协议名(U D P)、源端口号和目的端口号。 协议名是可以打印出来的,因为它在 I P首部并被复制到各个片中。但是,端口号在 U D P首部, 只能在第1片中被发现。 发送的第3份数据报(用户数据为 1 4 7 3字节)分片情况如图 11 - 8所示。需要重申的是,任 何运输层首部只出现在第1片数据中。 另外需要解释几个术语: I P数据报是指I P层端到端的传输单元(在分片之前和重新组装 之后),分组是指在I P层和链路层之间传送的数据单元。一个分组可以是一个完整的 I P数据报, 也可以是I P数据报的一个分片。 图11-8 UDP分片举例 112使用TCP/IP详解,卷1:协议 20字节 20字节 8字节 8字节 1472字节 20字节 1字节 IP首部UDP首部IP首部 IP首部 UDP首部 IP数据报 UDP数据(1473字节) 分组分组11.6 ICMP不可达差错(需要分片) 发生I C M P不可达差错的另一种情况是,当路由器收到一份需要分片的数据报,而在 I P首 部又设置了不分片(D F)的标志比特。如果某个程序需要判断到达目的端的路途中最小 M T U 是多少— 称作路径M T U发现机制(2 . 9节),那么这个差错就可以被该程序使用。 这种情况下的I C M P不可达差错报文格式如图 11 - 9所示。这里的格式与图 6 - 1 0不同,因为 在第2个32 bit字中,16~31 bit可以提供下一站的M T U,而不再是0。 图11-9 需要分片但又设置不分片标志比特时的ICMP不可达差错报文格式 如果路由器没有提供这种新的 I C M P差错报文格式,那么下一站的 M T U就设为0。 新版的路由器需求RFC [Almquist 1993]声明,在发生这种I C M P不可达差错时,路 由器必须生成这种新格式的报文。 例子 关于分片作者曾经遇到过一个问题, I C M P差错试图判断从路由器n e t b到主机s u n之间的 拨号S L I P链路的M T U。我们知道从s u n到n e t b的链路的M T U:当S L I P被安装到主机s u n时, 这是S L I P配置过程中的一部分,加上在 3 . 9节中已经通过n e t s t a t命令观察过。现在,我们想 从另一个方向来判断它的M T U(在第2 5章,将讨论如何用S N M P来判断)。在点到点的链路中, 不要求两个方向的M T U为相同值。 所采用的技术是在主机 s o l a r i s上运行p i n g程序到主机b s d i,增加数据分组长度,直 到看见进入的分组被分片为止。如图 11 - 1 0所示。 图11-10 用来判断从n e t b 到s u n 的SLIP链路MTU的系统 在主机s u n上运行t c p d u m p,观察S L I P链路,看什么时候发生分片。开始没有观察到分 片,一切都很正常直到 p i n g分组的数据长度从5 0 0增加到6 0 0字节。可以看到接收到的回显请 第11章 UDP:用户数据报协议使用113 类型(3) 代码(4) 检验和 8字节 下一站网络的MTU未用(必须为0) IP首部(包括选项)+原始IP数据报中数据的前8字节 分片 分片 用tcpdump观察 分片 ICMP回显请求求(仍然没有分片),但不见回显应答。 为了跟踪下去,也在主机 b s d i上运行 t c p d u m p,观察它接收和发送的报文。输出如图 11 - 11所示。 图11-11 600字节的IP数据报从s o l a r i s 主机p i n g 到b s d i 主机时的t c p d u m p 输出 首先,每行中的标记( D F)说明在I P首部中设置了不分片比特。这意味着 Solaris 2.2 一 般把不分片比特置1,作为实现路径M T U发现机制的一部分。 第1行显示的是回显请求通过路由器 n e t b到达s u n主机,没有进行分片,并设置了 D F比 特,因此我们知道还没有达到 n e t b的SLIP MTU。 接下来,在第2行注意到D F标志被复制到回显应答报文中。这就带来了问题。回显应答与 回显请求报文长度相同(超过 6 0 0字节),但是s u n外出的S L I P接口M T U为5 5 2。因此回显应 答需要进行分片,但是 D F标志比特又被设置了。这样, s u n就产生一个I C M P不可达差错报文 返回给b s d i(报文在b s d i处被丢弃)。 这就是我们在主机 s o l a r i s上没有看到任何回显应答的原因。这些应答永远不能通过 s u n。分组的路径如图11 - 1 2所示。 图11-12 例子中的分组交换 最后,在图11 - 11中的第3行和第6行中,m t u = 0表示主机s u n没有在I C M P不可达报文中返 回出口M T U值,如图11 - 9所示(在2 5 . 9节中,将重新回到这个问题,用 S N M P判断n e t b上的 S L I P接口M T U值为1 5 0 0)。 11.7 用Traceroute确定路径MTU 尽管大多数的系统不支持路径 M T U发现功能,但可以很容易地修改 t r a c e r o u t e程序 (第8章),用它来确定路径 M T U。要做的是发送分组,并设置“不分片”标志比特。发送的 第一个分组的长度正好与出口 M T U相等,每次收到I C M P“不能分片”差错时(在上一节讨论 114使用TCP/IP详解,卷1:协议 ICMP回显请求 ICMP回显请求 ICMP回显请求 ICMP回显应答 ICMP不可达:需要分片, 但又设置了DF位的)就减小分组的长度。如果路由器发送的 I C M P差错报文是新格式,包含出口的 M T U,那么 就用该M T U值来发送,否则就用下一个最小的 M T U值来发送。正如 RFC 1191 [Mogul and Deering 1990]声明的那样,M T U值的个数是有限的,因此在我们的程序中有一些由近似值构 成的表,取下一个最小M T U值来发送。 首先,我们尝试判断从主机 s u n到主机s l i p的路径M T U,知道S L I P链路的M T U为2 9 6。 在这个例子中,路由器 b s d i没有在I C M P差错报文中返回出口 M T U,因此我们选择另一个 M T U近似值。T T L为2的第1行输出打印的主机名为 b s d i,但这是因为它是返回 I C M P差错报 文的路由器。T T L为2的最后一行正是我们所要找的。 在b s d i上修改I C M P代码使它返回出口M T U值并不困难,如果那样做并再次运行该程序, 得到如下输出结果: 这时,在找到正确的 M T U值之前,我们不用逐个尝试 8个不同的M T U值——路由器返回 了正确的M T U值。 全球互联网 作为一个实验,我们多次运行修改以后的 t r a c e r o u t e程序,目的端为世界各地的主机。 可以到达1 5个国家(包括南极洲),使用了多个跨大西洋和跨太平洋的链路。但是,在这样做 之前,作者所在子网与路由器 n e t b之间的拨号S L I P链路M T U(见图11 - 1 2)增加到1 5 0 0,与 以太网相同。 在1 8次运行当中,只有其中 2次发现的路径 M T U小于1 5 0 0。其中一个跨大西洋的链路 M T U值为5 7 2(其近似值甚至在 RFC 11 9 1中也没有被列出),而路由器返回的是新格式的 I C M P差错报文。另外一条链路,在日本的两个路由器之间,不能处理 1 5 0 0字节的数据帧,并 且路由器没有返回新格式的 I C M P差错报文。把M T U值设成1 0 0 6则可以正常工作。 从这个实验可以得出结论,现在许多但不是所有的广域网都可以处理大于 5 1 2字节的分组。 利用路径M T U发现机制,应用程序就可以充分利用更大的 M T U来发送报文。 第11章 UDP:用户数据报协议使用11511.8 采用UDP的路径MTU发现 下面对使用U D P的应用程序与路径 M T U发现机制之间的交互作用进行研究。看一看如果 应用程序写了一个对于一些中间链路来说太长的数据报时会发生什么情况。 例子 由于我们所使用的支持路径 M T U发现机制的唯一系统就是Solaris 2.x,因此,将采用它作 为源站发送一份6 5 0字节数据报经s l i p。由于s l i p主机位于M T U为2 9 6的S L I P链路后,因此, 任何长于2 6 8字节(2 9 6-2 0-8)且“不分片”比特置为 1的U D P数据都会使b s d i路由器产生 I C M P“不能分片”差错报文。图 11 - 1 3给出了拓扑结构和M T U。 图11-13 使用UDP进行路径MTU发现的系统 可以用下面的命令行来产生 6 5 0字节U D P数据报,每两个U D P数据报之间的间隔是5秒: solaris % sock -u -i -n10 -w650 -p5 slip discard 图11 - 1 4是t c p d u m p的输出结果。在运行这个例子时,将b s d i设置成在I C M P“不能分片” 差错中,不返回下一跳M T U信息。 在发送的第一个数据报中将 D F比特置1(第1行),其结果是从b s d i路由器发回我们可以 猜测的结果(第 2行)。令人不解的是,发送一个 D F比特置1的数据报(第 3行),其结果是同 样的I C M P差错(第4行)。我们预计这个数据报在发送时应该将 D F比特置0。 第5行结果显示,I P已经知道了发往该目的地址的数据报不能将 D F比特置1,因此,I P进 而将数据报在源站主机上进行分片。这与前面的例子中, I P发送经过U D P的数据报,允许具 有较小M T U的路由器(在本例中是 b s d i)对它进行分片的情况不一样。由于 I C M P“不能分 片”报文并没有指出下一跳的 M T U,因此,看来I P猜测M T U为5 7 6就行了。第一次分片(第 5 行)包含5 4 4字节的U D P数据、8字节U D P首部以及2 0字节I P首部,因此,总 I P数据报长度是 5 7 2字节。第2次分片(第6行)包含剩余的1 0 6字节U D P数据和2 0字节I P首部。 不幸的是,第7行的下一个数据报将其 D F比特置1,因此b s d i将它丢弃并返回 I C M P差错。 这时发生了 I P定时器超时,通知 I P查看是不是因为路径 M T U增大了而将 D F比特再一次置 1。 我们可以从第1 9行和2 0行看出这个结果。将第 7行与1 9行进行比较,可以看出 I P每过3 0秒就将 D F比特置1,以查看路径M T U是否增大了。 这个3 0秒的定时器值看来太短。 R F C 11 9 1建议其值取 1 0分钟。可以通过修改 i p _ i r e _ p a t h m t u _ i n t e r v a l(E . 4节)参数来改变该值。同时,Solaris 2.2无法对单个 116使用TCP/IP详解,卷1:协议 在这里运行tcpdump命令 将DF比特置1的650字节UDP数据报 ICMP不能分片差错U D P应用或所有U D P应用关闭该路径M T U发现。只能通过修改i p _ p a t h _ m t u _ d i s c o v e r y 参数,在系统一级开放或关闭它。正如在这个例子里所能看到的那样,如果允许路径M T U 发现,那么当U D P应用程序写入可能被分片数据报时,该数据报将被丢弃。 图11-14 使用UDP路径MTU发现 s o l a r i s的I P层所假设的最大数据报长度( 5 7 6字节)是不正确的。在图 11 - 1 3中,我们 看到,实际的 M T U值是2 9 6字节。这意味着经 s o l a r i s分片的数据报还将被 b s d i分片。图 11 - 1 5给出了在目的主机( s l i p)上所收集到的 t c p d u m p对于第一个到达数据报的输出结果 (图11 - 1 4的第5行和第6行)。 图11-15 从solaris到达slip的第一个数据报 在本例中,s o l a r i s不应该对外出数据报分片,它应该将 D F比特置0,让具有最小M T U 的路由器来完成分片工作。 现在我们运行同一个例子,只是对路由器 b s d i进行修改使其在 I C M P“不能分片”差错 中返回下一跳M T U。图11 - 1 6给出了t c p d u m p输出结果的前6行。 与图11 - 1 4一样,前两个数据报同样是将 D F比特置1后发送出去的。但是在知道了下一跳 M T U后,只产生了3个数据报片,而图11 - 1 5中的b s d i路由器则产生了4个数据报片。 第11章 UDP:用户数据报协议使用117图11-16 使用UDP的路径MTU发现 11.9 UDP和ARP之间的交互作用 使用U D P,可以看到U D P与A R P典型实现之间的有趣的(而常常未被人提及)交互作用。 我们用s o c k程序来产生一个包含8 1 9 2字节数据的U D P数据报。预测这将会在以太网上产 生6个数据报片(见习题 11 . 3)。同时也确保在运行该程序前, A R P缓存是清空的,这样,在 发送第一个数据报片前必须交换 A R P请求和应答。 bsdi % arp -a 验证A R P高速缓存是空的 bsdi % sock -u -i -nl -w8192 svr4 discard 预计在发送第一个数据报片前会先发送一个 A R P请求。I P还会产生5个数据报片,这样就 提出了我们必须用 t c p d u m p来回答的两个问题:在接收到 A R P回答前,其余数据报片是否已 经做好了发送准备?如果是这样,那么在 A R P等待应答时,它会如何处理发往给定目的的多 个报文?图11 - 1 7给出了t c p d u m p的输出结果。 图11-17 在以太网上发送8192字节UDP数据报时的报文交换 在这个输出结果中有一些令人吃惊的结果。首先,在第一个 A R P应答返回以前,总共产 生了6个A R P请求。我们认为其原因是 I P很快地产生了 6个数据报片,而每个数据报片都引发 了一个A R P请求。 第二,在接收到第一个 A R P应答时(第7行),只发送最后一个数据报片(第 9行)!看来 似乎将前5个数据报片全都丢弃了。实际上,这是 A R P的正常操作。在大多数的实现中,在等 待一个A R P应答时,只将最后一个报文发送给特定目的主机。 Host Requirements RFC要求实现中必须防止这种类型的A R P洪泛(ARP flooding, 118使用TCP/IP详解,卷1:协议即以高速率重复发送到同一个I P地址的A R P请求)。建议最高速率是每秒一次。而这里 却在4.3 ms内发出了6个ARP请求。 Host Requirements RFC规定,ARP应该保留至少一个报文,而这个报文必须是最后 一个报文。这正是我们在这里所看到的结果。 另一个无法解释的不正常的现象是, s v r 4发回7个,而不是6个A R P应答。 最后要指出的是,在最后一个 A R P应答返回后,继续运行 t c p d u m p程序5分钟,以看看 s v r 4是否会返回I C M P“组装超时”差错。并没有发送 I C M P差错(我们在图 8 - 2中给出了该 消息的格式。c o d e字段为1表示在重新组装数据报时发生了超时)。 在第一个数据报片出现时, I P层必须启动一个定时器。这里“第一个”表示给定数据报 的第一个到达数据报片,而不是第一个数据报片(数据报片偏移为 0)。正常的定时器值为 3 0 或6 0秒。如果定时器超时而该数据报的所有数据报片未能全部到达,那么将这些数据报片丢 弃。如果不这么做,那些永远不会到达的数据报片(正如我们在本例中所看到的那样)迟早 会引起接收端缓存满。 这里我们没看到 I C M P消息的原因有两个。首先,大多数从 B e r k e l e y派生的实现从不产生 该差错!这些实现会设置定时器,也会在定时器溢出时将数据报片丢弃,但是不生成 I C M P差 错。第二,并未接收到包含 U D P首部的偏移量为 0的第一个数据报片(这是被 A R P所丢弃的5 个报文的第1个)。除非接收到第一个数据报片,否则并不要求任何实现产生 I C M P差错。其原 因是因为没有运输层首部,I C M P差错的接收者无法区分出是哪个进程所发送的数据报被丢弃。 这里假设上层(T C P或使用U D P的应用程序)最终会超时并重传。 在本节中,我们使用 I P数据报片来查看 U D P与A R P之间的交互作用。如果发送端迅速发 送多个U D P数据报,也可以看到这个交互过程。我们选择采用分片的方法,是因为 I P可以生 成报文的速度,比一个用户进程生成多个数据报的速度更快。 尽管本例看来不太可能,但它确实经常发生。 N F S发送的U D P数据报长度超过8 1 9 2字节。 在以太网上,这些数据报以我们所指出的方式进行分片,如果适当的 A R P缓存入口发生超时, 那么就可以看到这里所显示的现象。 N F S将超时并重传,但是由于A R P的有限队列,第一个I P 数据报仍可能被丢弃。 11.10 最大UDP数据报长度 理论上,I P数据报的最大长度是6 5 5 3 5字节,这是由I P首部(图3 - 1)1 6比特总长度字段所 限制的。去除 2 0字节的I P首部和8个字节的U D P首部,U D P数据报中用户数据的最长长度为 6 5 5 0 7字节。但是,大多数实现所提供的长度比这个最大值小。 我们将遇到两个限制因素。第一,应用程序可能会受到其程序接口的限制。 socket API提 供了一个可供应用程序调用的函数,以设置接收和发送缓存的长度。对于 UDP socket,这个 长度与应用程序可以读写的最大 U D P数据报的长度直接相关。现在的大部分系统都默认提供 了可读写大于 8 1 9 2字节的U D P数据报(使用这个默认值是因为 8 1 9 2是N F S读写用户数据数的 默认值)。 第二个限制来自于T C P / I P的内核实现。可能存在一些实现特性(或差错),使I P数据报长 度小于6 5 5 3 5字节。 作者使用s o c k程序对不同U D P数据报长度进行了试验。在SunOS 4.1.3下使用环回 第11章 UDP:用户数据报协议使用119接口的最大I P数据报长度是3 2 7 6 7字节。比它大的值都会发生差错。但是从 B S D / 3 8 6到 SunOS 4.1.3的情况下,S u n所能接收到最大I P数据报长度为3 2 7 8 6字节(即3 2 7 5 8字节用 户数据)。在Solaris 2.2下使用环回接口,最大可收发 I P数据报长度为6 5 5 3 5字节。从 Solaris 2.2到AIX 3.2.2,发送的最大IP数据报长度可以是65535字节。很显然,这个限制 与源端和目的端的实现有关。 我们在3 . 2节中提过,要求主机必须能够接收最短为 5 7 6字节的I P数据报。在许多U D P应用 程序的设计中,其应用程序数据被限制成 5 1 2字节或更小,因此比这个限制值小。例如,我们 在1 0 . 4节中看到,路径信息协议总是发送每份数据报小于 5 1 2字节的数据。我们还会在其他 U D P应用程序如D N S(第1 4章)、T F T P(第1 5章)、B O O T P(第1 6章)以及S N M P(第2 5章) 中遇到这个限制。 数据报截断 由于I P能够发送或接收特定长度的数据报并不意味着接收应用程序可以读取该长度的数 据。因此,U D P编程接口允许应用程序指定每次返回的最大字节数。如果接收到的数据报长 度大于应用程序所能处理的长度,那么会发生什么情况呢? 不幸的是,该问题的答案取决于编程接口和实现。 典型的B e r k e l e y版socket API对数据报进行截断,并丢弃任何多余的数据。应用程 序何时能够知道,则与版本有关(4.3BSD Reno及其后的版本可以通知应用程序数据报 被截断)。 S V R 4下的socket API(包括Solaris 2.x) 并不截断数据报。超出部分数据在后面的读 取中返回。它也不通知应用程序从单个UDP数据报中多次进行读取操作。 TLI API不丢弃数据。相反,它返回一个标志表明可以获得更多的数据,而应用程 序后面的读操作将返回数据报的其余部分。 在讨论T C P时,我们发现它为应用程序提供连续的字节流,而没有任何信息边界。 T C P以 应用程序读操作时所要求的长度来传送数据,因此,在这个接口下,不会发生数据丢失。 11.11 ICMP源站抑制差错 我们同样也可以使用 U D P产生I C M P“源站抑制(source quench)”差错。当一个系统(路 由器或主机)接收数据报的速度比其处理速度快时,可能产生这个差错。注意限定词“可能”。 即使一个系统已经没有缓存并丢弃数据报,也不要求它一定要发送源站抑制报文。 图11 - 1 8给出了I C M P源站抑制差错报文的格式。有一个很好的方案可以在我们的测试网 络里产生该差错报文。可以从 b s d i通过必须经过拨号 S L I P链路的以太网,将数据报发送给路 由器s u n。由于S L I P链路的速度大约只有以太网的千分之一,因此,我们很容易就可以使其缓 存用完。下面的命令行从主机 b s d i通过路由器s u n发送1 0 0个1 0 2 4字节长数据报给 s o l a r i s。 我们将数据报发送给标准的丢弃服务,这样,这些数据报将被忽略: bsdi % sock -u -i -w1024 -n100 solaris discard 图11 - 1 9给出了与此命令行相对应的 t c p d u m p输出结果 在这个输出结果中,删除了很多行,这只是一个模型。接收前 2 6个数据报时未发生差 120使用TCP/IP详解,卷1:协议错;我们只给出了第一个数据报的结果。然而,从第 2 7个数据报开始,每发送一份数据报, 就会接收到一份源站抑制差错报文。总共有 26 +(7 4×2)= 1 7 4行输出结果。 图11-18 ICMP源站抑制差错报文格式 图11-19 来自路由器s u n 的ICMP源站抑制 从2 . 1 0节的并行线吞吐率计算结果可以知道,以 9600 b/s速率传送1 0 2 4字节数据报只需要 1秒时间(由于从s u n到n e t b的S L I P链路的M T U为5 5 2字节,因此在我们的例子中, 20 + 8 + 1 0 2 4字节数据报将进行分片,因此,其时间会稍长一些)。但是我们可以从图 11 - 1 9的时间中 看出, s u n路由器在不到 1秒时间内就处理完所有的 1 0 0个数据报,而这时,第一份数据报还 未通过S L I P链路。因此我们用完其缓存就不足不奇了。 尽管RFC 1009 [Braden and Postel 1987] 要求路由器在没有缓存时产生源站抑制差 错报文,但是新的Router Requirements RFC [Almquist 1993] 对此作了修改,提出路由 器不应该产生源站抑制差错报文。由于源站抑制要消耗网络带宽,且对于拥塞来说是 一种无效而不公平的调整,因此现在人们对于源站抑制差错的态度是不支持的。 在本例中,还需要指出的是, s o c k程序要么没有接收到源站抑制差错报文,要么接收到 却将它们忽略了。结果是如果采用 U D P协议,那么B S D实现通常忽略其接收到的源站抑制报 文(正如我们在2 1 . 1 0节所讨论的那样, T C P接受源站抑制差错报文,并将放慢在该连接上的 数据传输速度)。其部分原因在于,在接收到源站抑制差错报文时,导致源站抑制的进程可能 已经中止了。实际上,如果使用 Unix 的t i m e程序来测定s o c k程序所运行的时间,其结果是它 只运行了大约0 . 5秒时间。但是从图11 - 1 9中可以看到,在发送第一份数据报过后 0 . 7 1秒才接收 到一些源站抑制,而此时该进程已经中止。其原因是我们的程序写入了 1 0 0个数据报然后中止 了。但是所有的1 0 0个数据报都已发送出去— 有一些数据报在输出队列中。 这个例子重申了 U D P是一个非可靠的协议,它说明了端到端的流量控制。尽管 s o c k程序 成功地将1 0 0个数据报写入其网络,但只有 2 6个数据报真正发送到了目的端。其他 7 4个数据报 第11章 UDP:用户数据报协议使用121 类型(4) 代码(0) 检验和 8字节 未用(必须为0) IP首部(包括选项)+原始IP数据报中数据的前8 字节可能被中间路由器丢弃。除非在应用程序中建立一些应答机制,否则发送端并不知道接收端 是否收到了这些数据。 11.12 UDP服务器的设计 使用U D P的一些蕴含对于设计和实现服务器会产生影响。通常,客户端的设计和实现比 服务器端的要容易一些,这就是我们为什么要讨论服务器的设计,而不是讨论客户端的设计 的原因。典型的服务器与操作系统进行交互作用,而且大多数需要同时处理多个客户。 通常一个客户启动后直接与单个服务器通信,然后就结束了。而对于服务器来说,它启 动后处于休眠状态,等待客户请求的到来。对于 U D P来说,当客户数据报到达时,服务器苏 醒过来,数据报中可能包含来自客户的某种形式的请求消息。 在这里我们所感兴趣的并不是客户和服务器的编程方面( [Stevens 1990]对这些方面的细 节进行了讨论),而是U D P那些影响使用该协议的服务器的设计和实现方面的协议特性(我们 在 1 8 . 11节中对T C P服务器的设计进行了描述)。尽管我们所描述的一些特性取决于所使用 U D P的实现,但对于大多数实现来说,这些特性是公共的。 11.12.1 客户IP地址及端口号 来自客户的是 U D P数据报。I P首部包含源端和目的端 I P地址,U D P首部包含了源端和目 的端的U D P端口号。当一个应用程序接收到 U D P数据报时,操作系统必须告诉它是谁发送了 这份消息,即源I P地址和端口号。 这个特性允许一个交互 U D P服务器对多个客户进行处理。给每个发送请求的客户发回应 答。 11.12.2 目的IP地址 一些应用程序需要知道数据报是发送给谁的,即目的 I P地址。例如,Host Requirements R F C规定,T F T P服务器必须忽略接收到的发往广播地址的数据报(我们分别在第 1 2章和第1 5 章对广播和T F T P进行描述)。 这要求操作系统从接收到的 U D P数据报中将目的 I P地址交给应用程序。不幸的是,并非 所有的实现都提供这个功能。 socket API以I P _ R E C V D S TADDR socket选项提供了这个功能。对于本文中使用的 系统,只有B S D / 3 8 6、4 . 4 B S D和AIX 3.2.2支持该选项。S V R 4、SunOS 4.x和Solaris 2.x 都不支持该选项。 11.12.3 UDP输入队列 我们在1 . 8节中说过,大多数 U D P服务器是交互服务器。这意味着,单个服务器进程对单 个U D P端口上(服务器上的名知端口)的所有客户请求进行处理。 通常程序所使用的每个 U D P端口都与一个有限大小的输入队列相联系。这意味着,来自 不同客户的差不多同时到达的请求将由 U D P自动排队。接收到的 U D P数据报以其接收顺序交 给应用程序(在应用程序要求交送下一个数据报时)。 122使用TCP/IP详解,卷1:协议然而,排队溢出造成内核中的 U D P模块丢弃数据报的可能性是存在的。可以进行以下试 验。我们在作为U D P服务器的b s d i主机上运行s o c k程序: bsdi % sock -s -u -v -E -R256 -P30 6666 from 140.252.13.33, to 140.252.13.63: 1111111111 从s u n发送到广播地址 from 140.252.13.34, to 140.252.13.35: 4444444444444 从s v r 4发送到单播地址 我们指明以下标志: - s表示作为服务器运行, - u表示 U D P,- v表示打印客户的 I P地 址,- E表示打印目的I P地址(该系统支持这个功能)。另外,我们将这个端口的 U D P接收缓存 设置为2 5 6字节(-R),其每次应用程序读取的大小也是这个数( - r)。标志 - P 3 0表示创建 U D P端口后,先暂停 3 0秒后再读取第一个数据报。这样,我们就有时间在另两台主机上启动 客户程序,发送一些数据报,以查看接收队列是如何工作的。 服务器一开始工作,处于其 3 0秒的暂停时间内,我们就在 s u n主机上启动一个客户,并 发送三个数据报: sun % sock -u -v 140.252.13.63 6666 到以太网广播地址 connected on 140.252.13.33.1252 to 140.252.13.63.6666 1 1 1 1 1 1 1 1 1 1 1 1字节的数据(新行) 2 2 2 2 2 2 2 2 2 1 0字节的数据(新行) 3 3 3 3 3 3 3 3 3 3 3 1 2字节的数据(新行) 目的地址是广播地址( 1 4 0 . 2 5 2 . 1 3 . 6 3)。我们同时也在主机 s v r 4上启动第2个客户,并发 送另外三个数据报: svr4 % sock -u -v bsdi 6666 connected on 0.0.0.0.1042 to 140.252.13.35.6666 4 4 4 4 4 4 4 4 4 4 4 4 4 1 4字节的数据(新行) 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 1 6字节的数据(新行) 6 6 6 6 6 6 6 6 9字节的数据(新行) 首先,我们早些时候在 b s d i上所看到的结果表明,应用程序只接收到 2个数据报:来自 s u n的第一个全1报文,和来自s v r 4的第一个全4报文。其他4个数据报看来全被丢弃。 图11 - 2 0给出的t c p d u m p输出结果表明,所有 6个数据报都发送给了目的主机。两个客户 的数据报以交替顺序键入:第一个来自 s u n,然后是来自s v r 4的,以此类推。同时也可以看 出,全部6个数据报大约在1 2秒内发送完毕,也就是在服务器休眠的 3 0秒内完成的。 图11-20 两个客户发送UDP数据报的t c p d u m p 输出结果 我们还可以看到,服务器的- E选项使其可以知道每个数据报的目的 I P地址。如果需要, 它可以选择如何处理其接收到的第一个数据报,这个数据报的地址是广播地址。 我们可以从本例中看到以下几个要点。首先,应用程序并不知道其输入队列何时溢出。 只是由U D P对超出数据报进行丢弃处理。同时,从 t c p d u m p输出结果,我们看到,没有发回 任何信息告诉客户其数据报被丢弃。这里不存在像 I C M P源站抑制这样发回发送端的消息。最 后,看来 U D P输出队列是 F I F O(先进先出)的,而我们在 11 . 9节中所看到的 A R P输入却是 第11章 UDP:用户数据报协议使用123L I F O(后进先出)的。 11.12.4 限制本地IP地址 大多数U D P服务器在创建U D P端点时都使其本地 I P地址具有通配符( w i l d c a r d )的特点。这 就表明进入的 U D P数据报如果其目的地为服务器端口,那么在任何本地接口均可接收到它。 例如,我们以端口号7 7 7启动一个U D P服务器: sun % sock -u -s 7777 然后,用n e t s t a t命令观察端点的状态: sun % netstat -a -n -f inet Active Internet connections (including servers) Proto Recv-Q Send-Q Local Address Foreign Address (state) udp 0 0 *.7777 *.* 这里,我们删除了许多行,只保留了其中感兴趣的东西。 - a选项表示报告所有网络端点 的状态。- n选项表示以点数格式打印 I P地址而不用D N S把地址转换成名字,打印数字端口号 而不是服务名称。-f inet选项表示只报告T C P和U D P端点。 本地地址以* . 7 7 7 7格式打印,星号表示任何本地 I P地址。 当服务器创建端点时,它可以把其中一个主机本地 I P地址包括广播地址指定为端点的本 地I P地址。只有当目的 I P地址与指定的地址相匹配时,进入的 U D P数据报才能被送到这个端 点。用我们的s o c k程序,如果在端口号之前指定一个 I P地址,那么该I P地址就成为该端点的 本地I P地址。例如: sun % sock -u -s 140.252.1.29 7777 就限制服务器在S L I P接口( 1 4 0 . 2 5 2 . 1 . 2 9 )处接收数据报。n e t s t a t输出结果显示如下: Proto Recv-Q Send-Q Local Address Foreign Address (state) udp 0 0 140.252.1.29.7777 *.* 如果我们试图在以太网上的主机 b s d i以地址1 4 0 . 2 5 2 . 1 3 . 3 5向该服务器发送一份数据报, 那么将返回一个 I C M P端口不可达差错。服务器永远看不到这份数据报。这种情形如图 11 - 2 1 所示。 图11-21 服务器本地地址绑定导致拒绝接收UDP数据报 有可能在相同的端口上启动不同的服务器,每个服务器具有不同的本地 I P地址。但是, 一般必须告诉系统应用程序重用相同的端口号没有问题。 使用sockets API时,必须指定S O _ R E U S E A D D R s o c k e t选项。在s o c k程序中是通过-A 选项来完成的。 在主机s u n上,可以在同一个端口号( 8 8 8 8)上启动5个不同的服务器: 124使用TCP/IP详解,卷1:协议 对于SLIP链路 对于以太网 对于环回接口 对于以太网广播 其他(IP地址通配)除了第一个以外,其他的服务器都必须以- A选项启动,告诉系统可以重用同一个端口号。 5个服务器的n e t s t a t输出结果如下所示: 在这种情况下,到达服务器的数据报中,只有带星号的本地 I P地址,其目的地址为 1 4 0 . 2 5 2 . 1 . 2 5 5,因为其他4个服务器占用了其他所有可能的 I P地址。 如果存在一个含星号的 I P地址,那么就隐含了一种优先级关系。如果为端点指定了特定 I P地址,那么在匹配目的地址时始终优先匹配该 I P地址。只有在匹配不成功时才使用含星号 的端点。 11.12.5 限制远端IP地址 在前面所有的 n e t s t a t输出结果中,远端 I P地址和远端端口号都显示为 * . *,其意思是该端 点将接受来自任何 I P地址和任何端口号的 U D P数据报。大多数系统允许 U D P端点对远端地址 进行限制。 这说明端点将只能接收特定 I P地址和端口号的 U D P数据报。s o c k程序用- f选项来指定远 端I P地址和端口号: sun % sock -u -s -f 140.252.13.35.4444 5555 这样就设置了远端I P地址1 4 0 . 2 5 2 . 1 3 . 3 5(即主机b s d i)和远端端口号4444 。服务器的有名端 口号为5 5 5 5。如果运行n e t s t a t命令,我们发现本地I P地址也被设置了,尽管我们没有指定。 Proto Recv-Q Send-Q Local Address Foreign Address (state) udp 0 0 140.252.13.33.5555 140.252.13.35.4444 这是在伯克利派生系统中指定远端 I P地址和端口号带来的副作用:如果在指定远端地址 时没有选择本地地址,那么将自动选择本地地址。它的值就成为选择到达远端 I P地址路由时 将选择的接口 I P地址。事实上,在这个例子中, s u n 在以太网上的 I P地址与远端地址 1 4 0 . 2 5 2 . 1 3 . 3 3相连。 图11 - 2 2总结了U D P服务器本身可以创建的三类地址绑定。 图11-22 为UDP服务器指定本地和远端IP地址及端口号 在所有情况下,l p o r t指的是服务器有名端口号, l o c a l I P必须是本地接口的I P地址。表中这 三行的排序是 U D P模块在判断用哪个端点接收数据报时所采用的顺序。最为确定的地址(第 一行)首先被匹配,最不确定的地址(最后一行 I P地址带有两个星号)最后进行匹配。 11.12.6 每个端口有多个接收者 尽管在R F C中没有指明,但大多数的系统在某一时刻只允许一个程序端点与某个本地 I P 第11章 UDP:用户数据报协议使用125 本 地 地 址 远 端 地 址 描 述 l o c a l I P. l p o r t f o r e i g n I P. f p o r t 只限于一个客户 l o c a l I P. l p o r t * . * 限于到达一个本地接口的数据报: l o c a l I P * . l p o r t * . * 接收发送到l p o r t的所有数据报地址及U D P端口号相关联。当目的地为该 I P地址及端口号的 U D P数据报到达主机时,就复制 一份传给该端点。端点的I P地址可以含星号,正如我们前面讨论的那样。 例如,在SunOS 4.1.3中,我们启动一个端口号为 9 9 9 9的服务器,本地I P地址含有星号: sun % sock -u -s 9999 接着,如果启动另一个具有相同本地地址和端口号的服务器,那么它将不运行,尽管我 们指定了- A选项: sun % sock -u -s 9999 我们预计它会失败 can't bind local address: Address already in use sun % sock -u -s -A 9999 因此,这次尝试- A参数 can't bind local address: Address already in use 在一个支持多播的系统上(第 1 2章),这种情况将发生变化。多个端点可以使用同一个 I P 地址和 U D P端口号,尽管应用程序通常必须告诉 A P I是可行的(如,用 - A 标志来指明 S O _ R E U S E A D D R s o c k e t选项)。 4 . 4 B S D支持多播传送,需要应用程序设置一个不同的s o c k e t选项(S O _ R E U S E P O R T) 以允许多个端点共享同一个端口。另外,每个端点必须指定这个选项,包括使用该端口 的第一个端点。 当U D P数据报到达的目的 I P地址为广播地址或多播地址,而且在目的 I P地址和端口号处 有多个端点时,就向每个端点传送一份数据报的复制(端点的本地 I P地址可以含有星号,它 可匹配任何目的I P地址)。但是,如果U D P数据报到达的是一个单播地址,那么只向其中一个 端点传送一份数据报的复制。选择哪个端点传送数据取决于各个不同的系统实现。 11.13 小结 U D P是一个简单协议。它的正式规范是 RFC 768 [Postel 1980],只包含三页内容。它向用 户进程提供的服务位于 I P层之上,包括端口号和可选的检验和。我们用 U D P来检查检验和, 并观察分片是如何进行的。 接着,我们讨论了 I C M P不可达差错,它是新的路径 M T U发现功能中的一部分( 2 . 9节)。 用Tr a c e r o u t e和U D P来观察路径M T U发现过程。还查看了 U D P和A R P之间的接口,大多数的 A R P实现在等待A R P应答时只保留最近传送给目的端的数据报。 当系统接收I P数据报的速率超过这些数据报被处理的速率时,系统可能发送 I C M P源站抑 制差错报文。使用U D P时很容易产生这样的I C M P差错。 习题 11.1 在11 . 5节中,向U D P数据报中写入1 4 7 3字节用户数据时导致以太网数据报片的发生。在 采用以太网IEEE 802封装格式时,导致分片的最小用户数据长度为多少? 11.2 阅读RFC 791[Postel 1981a],理解为什么除最后一片外,其他片中的数据长度均要求为 8字节的整数倍? 11.3 假定有一个以太网和一份 8 1 9 2字节的U D P数据报,那么需要分成多少个数据报片,每个 数据报片的偏移和长度为多少? 11.4 继续前一习题,假定这些数据报片要经过一条 M T U为5 5 2的S L I P链路。必须记住每一个 126使用TCP/IP详解,卷1:协议数据报片中的数据(除 I P首部外)为8字节的整数倍。那么又将分成多少个数据报片? 每个数据报片的偏移和长度为多少? 11.5 一个用U D P发送数据报的应用程序,它把数据报分成 4个数据报片。假定第 1片和第2片 到达目的端,而第3片和第4片丢失了。应用程序在1 0秒钟后超时重发该U D P数据报,并 且被分成相同的4片(相同的偏移和长度)。假定这一次接收主机重新组装的时间为6 0秒, 那么当重发的第3片和第4片到达目的端时,原先收到的第 1片和第2片还没有被丢弃。接 收端能否把这4片数据重新组装成一份I P数据报? 11.6 你是如何知道图11 - 1 5中的片实际上与图11 - 1 4中第5行和第6行相对应? 11.7 主机g e m i n i开机3 3天后,n e t s t a t程序显示48 000 000份I P数据报中由于首部检验和 差错被丢弃1 2 9份,在30 000 000个T C P段中由于T C P检验和差错而被丢弃 2 0个。但是, 在大约18 000 000份U D P数据报中,因为U D P检验和差错而被丢弃的数据报一份也没有。 请说明两个方面的原因(提示:参见图 11 - 4)。 11.8 在讨论分片时没有提及任何关于 I P首部中的选项——它们是否也要被复制到每个数据报 片中,或者只留在第一个数据报片中?我们已经讨论过下面这些 I P选项:记录路由 (7 . 3节)、时间戳(7 . 4节)、严格和宽松的源站选路( 8 . 5节)。你希望分片如何处理这些 选项?对照RFC 791检查你的答案。 11.9 在图1 - 8中,我们说U D P数据报是根据目的U D P端口号进行分配的。这正确吗? 第11章 UDP:用户数据报协议使用127第12章 广播和多播 12.1 引言 在第1章中我们提到有三种 I P地址:单播地址、广播地址和多播地址。本章将更详细地介 绍广播和多播。 广播和多播仅应用于 U D P,它们对需将报文同时传往多个接收者的应用来说十分重要。 T C P是一个面向连接的协议,它意味着分别运行于两主机(由 I P地址确定)内的两进程(由 端口号确定)间存在一条连接。 考虑包含多个主机的共享信道网络如以太网。每个以太网帧包含源主机和目的主机的以 太网地址(4 8 b i t)。通常每个以太网帧仅发往单个目的主机,目的地址指明单个接收接口,因 而称为单播( u n i c a s t )。在这种方式下,任意两个主机的通信不会干扰网内其他主机(可能引起 争夺共享信道的情况除外)。 然而,有时一个主机要向网上的所有其他主机发送帧, 这就是广播。通过 A R P和R A R P可以看到这一过程。多播 (multicast) 处于单播和广播之间:帧仅传送给属于多播组的 多个主机。 为了弄清广播和多播,需要了解主机对由信道传送过 来帧的过滤过程。图1 2 - 1说明了这一过程。 首先,网卡查看由信道传送过来的帧,确定是否接收 该帧,若接收后就将它传往设备驱动程序。通常网卡仅接 收那些目的地址为网卡物理地址或广播地址的帧。另外, 多数接口均被设置为混合模式,这种模式能接收每个帧的 一个复制。作为一个例子, t c p d u m p使用这种模式。 目前,大多数的网卡经过配置都能接收目的地址为多 播地址或某些子网多播地址的帧。对于以太网,当地址中 最高字节的最低位设置为 1时表示该地址是一个多播地址, 用十六进制可表示为 0 1 : 0 0 : 0 0 : 0 0 : 0 0 : 0 0(以太网广播地址 ff : ff : ff : ff : ff : ff可看作是以太网多播地址的特例)。 如果网卡收到一个帧,这个帧将被传送给设备驱动程序(如果帧检验和错,网卡将丢弃 该帧)。设备驱动程序将进行另外的帧过滤。首先,帧类型中必须指定要使用的协议( I P、 A R P等等)。其次,进行多播过滤来检测该主机是否属于多播地址说明的多播组。 设备驱动程序随后将数据帧传送给下一层,比如,当帧类型指定为 I P数据报时,就传往 I P层。I P根据I P地址中的源地址和目的地址进行更多的过滤检测。如果正常,就将数据报传送 给下一层(如T C P或U D P)。 每次U D P收到由I P传送来的数据报,就根据目的端口号,有时还有源端口号进行数据报 图12-1 协议栈各层对收到帧 的过滤过程 丢弃 丢弃 丢弃 丢弃 交付 设备驱 动程序 接口卡 交付 交付 交付过滤。如果当前没有进程使用该目的端口号,就丢弃该数据报并产生一个 I C M P不可达报文 (T C P根据它的端口号作相似的过滤)。如果U D P数据报存在检验和错,将被丢弃。 使用广播的问题在于它增加了对广播数据不感兴趣主机的处理负荷。拿一个使用 U D P广 播应用作为例子。如果网内有 5 0个主机,但仅有 2 0个参与该应用,每次这 2 0个主机中的一个 发送U D P广播数据时,其余 3 0个主机不得不处理这些广播数据报。一直到 U D P层,收到的 U D P广播数据报才会被丢弃。这 3 0个主机丢弃U D P广播数据报是因为这些主机没有使用这个 目的端口。 多播的出现减少了对应用不感兴趣主机的处理负荷。使用多播,主机可加入一个或多个 多播组。这样,网卡将获悉该主机属于哪个多播组,然后仅接收主机所在多播组的那些多播 帧。 12.2 广播 在图3 - 9中,我们知道了四种I P广播地址,下面对它们进行更详细的介绍。 12.2.1 受限的广播 受限的广播地址是 2 5 5 . 2 5 5 . 2 5 5 . 2 5 5。该地址用于主机配置过程中 I P数据报的目的地址, 此时,主机可能还不知道它所在网络的网络掩码,甚至连它的 I P地址也不知道。 在任何情况下,路由器都不转发目的地址为受限的广播地址的数据报,这样的数据报仅 出现在本地网络中。 一个未解的问题是:如果一个主机是多接口的,当一个进程向本网广播地址发送数据报时, 为实现广播,是否应该将数据报发送到每个相连的接口上?如果不是这样,想对主机所有接口 广播的应用必须确定主机中支持广播的所有接口,然后向每个接口发送一个数据报复制。 大多数B S D系统将2 5 5 . 2 5 5 . 2 5 5 . 2 5 5看作是配置后第一个接口的广播地址,并且不提供向 所属具备广播能力的接口传送数据报的功能。不过, r o u t e d(见1 0 . 3节)和r w h o d(B S D r w h o客户的服务器)是向每个接口发送 U D P数据报的两个应用程序。这两个应用程序均用相 似的启动过程来确定主机中的所有接口,并了解哪些接口具备广播能力。同时,将对应于那 种接口的指向网络的广播地址作为发往该接口的数据报的目的地址。 Host Requirements RFC没有进一步涉及多接口主机是否应当向其所有的接口发送 受限的广播。 12.2.2 指向网络的广播 指向网络的广播地址是主机号为全 1的地址。A类网络广播地址为n e t i d . 2 5 5 . 2 5 5 . 2 5 5,其中 n e t i d为A类网络的网络号。 一个路由器必须转发指向网络的广播,但它也必须有一个不进行转发的选择。 12.2.3 指向子网的广播 指向子网的广播地址为主机号为全 1且有特定子网号的地址。作为子网直接广播地址的 I P 地址需要了解子网的掩码。例如,如果路由器收到发往 1 2 8 . 1 . 2 . 2 5 5的数据报,当 B类网络 第12章 广播和多播使用129130使用TCP/IP详解,卷1:协议 1 2 8 . 1的子网掩码为2 5 5 . 2 5 5 . 2 5 5 . 0时,该地址就是指向子网的广播地址;但如果该子网的掩码 为2 5 5 . 2 5 5 . 2 5 4 . 0,该地址就不是指向子网的广播地址。 12.2.4 指向所有子网的广播 指向所有子网的广播也需要了解目的网络的子网掩码,以便与指向网络的广播地址区分 开。指向所有子网的广播地址的子网号及主机号为全 1。例如,如果目的子网掩码为 2 5 5 . 2 5 5 . 2 5 5 . 0,那么I P地址1 2 8 . 1 . 2 5 5 . 2 5 5是一个指向所有子网的广播地址。然而,如果网络 没有划分子网,这就是一个指向网络的广播。 当前的看法[Almquist 1993]是这种广播是陈旧过时的,更好的方式是使用多播而不是对 所有子网的广播。 [Almquist 1993] 指出RFC 922要求将一个指向所有子网的广播传送给所有子网,但 当前的路由器没有这么做。这很幸运,因为一个因错误配置而没有子网掩码的主机会 把它的本地广播传送到所有子网。例如,如果I P地址为1 2 8 . 1 . 2 . 3的主机没有设置子网掩 码,它的广播地址在正常情况下的默认值是 1 2 8 . 1 . 2 5 5 . 2 5 5。但如果子网掩码被设置为 255.255.255.0,那么由错误配置的主机发出的广播将指向所有的子网。 1 9 8 3年问世的4 . 2 B S D是第一个影响广泛的T C P / I P的实现,它使用主机号全0作为广 播地址。一个最早提到广播IP地址的是IEN 212 [Gurwitz and Hinden 1982],它提出用主 机号中的1比特来表示I P广播地址(IENs 是互联网试验注释,基本上是 R F C的前身)。 RFC 894 [Hornig 1984]认为4.2BSD使用不标准的广播地址,但RFC 906 [Finlayson 1984] 注意到对广播地址还没有I n t e r n e t标准。R F C编辑在RFC 906中加了一个脚注承认缺少标 准的广播地址,并强烈推荐将主机号全1作为广播地址。尽管1 9 8 6年的4 . 3 B S D采用主机 号全1表示广播地址,但直到9 0年代早期,操作系统(著名的是 SunOS 4.x)还继续使 用非标准的广播地址。 12.3 广播的例子 广播是怎样传送的?路由器及主机又如何处理广播?很遗憾,这是难以回答的问题,因 为它依赖于广播的类型、应用的类型、 T C P / I P实现方法以及有关路由器的配置。 首先,应用程序必须支持广播。如果执行 sun % ping 255.255.255.255 /usr/etc/ping: unknown host 255.255.255.255 打算在本地电缆上进行广播。但它无法进行,原因在于该应用程序( p i n g)中存在一个程序 设计上的问题。大多数应用程序收到点分十进制的 I P地址或主机名后,会调用函数 i n e t _ a d d r( 3 )来把它们转化为 32 bit的二进制I P地址。假定要转化的是一个主机名,如果转 化失败,该库函数将返回- 1来表明存在某种差错(例如是字符而不是数字或串中有小数点)。 但本网广播地址( 2 5 5 . 2 5 5 . 2 5 5 . 2 5 5)也被当作存在差错而返回- 1。大多数程序均假定接收到 的字符串是主机名,然后查找 D N S(第1 4章),失败后输出差错信息如“未知主机”。 如果我们修复 p i n g程序中这个欠缺,结果也并不总是令人满意的。在 6个不同系统的测 试中,仅有一个像预期的那样产生了一个本网广播数据报。大多数则在路由表中查找 I P地址 2 5 5 . 2 5 5 . 2 5 5 . 2 5 5,而该地址被用作默认路由器地址,因此向默认路由器单播一个数据报。最第12章 广播和多播使用131 终该数据报被丢弃。 指向子网的广播是我们应该使用的。在6 . 3节中,我们向测试网络(见扉页前图)中 I P地址 为140.252.13.63 的以太网发送数据报,并接收以太网中所有主机的应答。与子网广播地址关联 的每个接口是用于命令i f c o n f i g(见3 . 8节)的值。如果我们p i n g那个地址,预期的结果是: I P通过目的地址( 1 4 0 . 2 5 2 . 1 3 . 6 3)来确定,这是指向子网的广播地址,然后向链路层的 广播地址发送该数据报。 在6 . 3节提到的这种广播类型的接收对象为局域网中包括发送主机在内的所有主机,因此 可以看到除了收到网内其他主机的答复外,还收到来自发送主机( s u n)的答复。 在这个例子中,我们也显示了执行 p i n g广播地址前后A R P缓存的内容。这可以显示广播 与A R P之间的相互作用。执行 p i n g命令前A R P缓存是空的,而执行后是满的(也就是说,对 网内其他每个响应回显请求的主机在 A R P缓存中均有一个条目)。我们提到的该以太网数据帧 被传送到链路层的广播地址( 0 x ffffffff)是如何发生的呢?由 s u n主机发送的数据帧不需要 A R P。 如果使用t c p d u m p来观察p i n g的执行过程,可以看到广播数据帧的接收者在发送它的响 应之前,首先产生一个对 s u n主机的A R P请求,因为它的应答是单播的。在 4 . 5节我们介绍了 一个A R P请求的接收者(该例中是 s u n)通常在发送A R P应答外,还将请求主机的 I P地址和物 理地址加入到 A R P缓存中去。这基于这样一个假定:如果请求者向我们发送一个数据报,我 们也很可能想向它发回什么。 我们使用的p i n g程序有些特殊,原因在于它使用的编程接口(在大多数 U n i x实现中是低 级插口(raw socket))通常允许向一个广播地址发送数据报。如果使用不支持广播的应用如 T F T P,情况又如何呢?(T F T P将在第1 5章详细介绍。) bsdi % t f t p 启动客户程序 tftp> connect 140.252.13.63 说明服务器的 I P地址 tftp> get temp.foo 试图从服务器或获取一个文件 tftp: sendto: Permission denied tftp> q u i t 终止客户程序 在这个例子中,程序立即产生了一个差错,但不向网络发送任何信息。产生这一切的原因在 于,插口提供的应用程序接口A P I只有在进程明确打算进行广播时才允许它向广播地址发送U D P ARP高速缓存空 键入中断以停止显示 再检验ARP缓存数据报。这主要是为了防止用户错误地采用了广播地址(正如此例)而应用程序却不打算广播。 在广播U D P数据报之前,使用插口中A P I的应用程序必须设置S O _ B R O A D C A S T插 口选项。 并非所有系统均强制使用这个限制。某些系统中无需进程进行这个说明就能广播 UDP数据报。而某些系统则有更多的限制,需要有超级用户权限的进程才能广播。 下一个问题是是否转发广播数据。有些系统内核和路由器有一选项来控制允许或禁止这 一特性(见附录E)。 如果让路由器b s d i能够转发广播数据,然后在主机 s l i p上运行p i n g程序,就能够观察 到由路由器b s d i转发的子网广播数据报。转发广播数据报意味着路由器接收广播数据,确定 该目的地址是对哪个接口的广播,然后用链路层广播向对应的网络转发数据报。 我们观察到它的确正常工作了,同时也看到 B S D系统中的 p i n g程序检查重复的数据报序 列号。如果出现重复序列号的数据报就显示 D U P !,这意味着一个数据报已经在某处重复了, 然而它正是我们所期望看到的,因为我们正向一个广播地址发送数据。 我 们 还 可 以 从 远 离 广 播 所 指 向 的 网 络 上 的 主 机 上 来 进 行 这 个 试 验 。 在 主 机 a n g o g h . c x . b e r k e l e y . e d u(和我们的网络距离1 4跳)上运行p i n g程序,如果路由器s u n被设置 为能够转发所指向的广播,它还能正常工作。在这种情况下,这个I P数据报(传送I C M P回显请求) 被路径上的每个路由器像正常的数据报一样转发,它们均不知道传送的实际上是广播数据。接着最 后一个路由器n e t b看到主机号为6 3,就将其转发给路由器s u n。路由器s u n觉察到该目的I P地址事 实上是一个相连子网接口上的广播地址,就将该数据报以链路层广播传往相应网络。 广播是一种应该谨慎使用的功能。在许多情况下, I P多播被证明是一个更好的解决办法。 12.4 多播 I P多播提供两类服务: 1) 向多个目的地址传送数据。有许多向多个接收者传送信息的应用:例如交互式会议系 统和向多个接收者分发邮件或新闻。如果不采用多播,目前这些应用大多采用 T C P来完成 (向每个目的地址传送一个单独的数据复制)。然而,即使使用多播,某些应用可能继续采用 T C P来保证它的可靠性。 2) 客户对服务器的请求。例如,无盘工作站需要确定启动引导服务器。目前,这项服务 是通过广播来提供的(正如第 1 6章的B O O T P),但是使用多播可降低不提供这项服务主机的负 担。 132使用TCP/IP详解,卷1:协议 键入中断以停止显示12.4.1 多播组地址 图1 2 - 2显示了D类I P地址的格式。 图12-2 D类IP地址格式 不像图1 - 5所示的其他三类I P地址(A、B和C),分配的28 bit均用作多播组号而不再表示 其他。 多播组地址包括为 111 0的最高4 bit和多播组号。它们通常可表示为点分十进制数,范围 从2 2 4 . 0 . 0 . 0到2 3 9 . 2 5 5 . 2 5 5 . 2 5 5。 能够接收发往一个特定多播组地址数据的主机集合称为主机组 (host group)。一个主机组 可跨越多个网络。主机组中成员可随时加入或离开主机组。主机组中对主机的数量没有限制, 同时不属于某一主机组的主机可以向该组发送信息。 一些多播组地址被 I A N A确定为知名地址。它们也被当作永久主机组,这和 T C P及U D P中 的熟知端口相似。同样,这些知名多播地址在 R F C最新分配数字中列出。注意这些多播地址 所代表的组是永久组,而它们的组成员却不是永久的。 例如,2 2 4 . 0 . 0 . 1代表“该子网内的所有系统组”,2 2 4 . 0 . 0 . 2代表“该子网内的所有路由器 组”。多播地址2 2 4 . 0 . 1 . 1用作网络时间协议 N T P,2 2 4 . 0 . 0 . 9用作R I P - 2 (见1 0 . 5节),2 2 4 . 0 . 1 . 2用 作S G I公司的d o g f i g h t应用。 12.4.2 多播组地址到以太网地址的转换 I A N A拥有一个以太网地址块,即高位 24 bit为0 0 : 0 0 : 5 e(十六进制表示),这意味着该地 址块所拥有的地址范围从 0 0 : 0 0 : 5 e : 0 0 : 0 0 : 0 0到0 0 : 0 0 : 5 e : ff : ff : ff。I A N A将其中的一半分配为多播 地址。为了指明一个多播地址,任何一个以太网地址的首字节必须是 0 1,这意味着与 I P多播 相对应的以太网地址范围从 0 1 : 0 0 : 5 e : 0 0 : 0 0 : 0 0到0 1 : 0 0 : 5 e : 7 f : ff : ff。 这里对C S M A / C D或令牌网使用的是I n t e r n e t标准比特顺序,和在内存中出现的比特 顺序一样。这也是大多数程序设计员和系统管理员采用的顺序。 I E E E文档采用了这种 比特传输顺序。Assigned Numbers RFC给出了这些表示的差别。 这种地址分配将使以太网多播地址中的 2 3 b i t与I P多播组号对应起来,通过将多播组号中 的低位2 3 b i t映射到以太网地址中的低位 2 3 b i t实现,这个过程如图1 2 - 3所示。 由于多播组号中的最高 5 bit在映射过程中被忽略,因此每个以太网多播地址对应的多播 组是不唯一的。 3 2 个不同的多播组号被映射为一个以太网地址。例如,多播地址 2 2 4 . 1 2 8 . 6 4 . 3 2(十六进制e 0 . 8 0 . 4 0 . 2 0)和2 2 4 . 0 . 6 4 . 3 2(十六进制e 0 . 0 0 . 4 0 . 2 0)都映射为同一以 太网地址0 1 : 0 0 : 5 e : 0 0 : 4 0 : 2 0。 既然地址映射是不唯一的,那么设备驱动程序或 I P层(见图1 2 - 1)就必须对数据报进行过 滤。因为网卡可能接收到主机不想接收的多播数据帧。另外,如果网卡不提供足够的多播数 据帧过滤功能,设备驱动程序就必须接收所有多播数据帧,然后对它们进行过滤。 第12章 广播和多播使用133 D 类 28位 多播组ID134使用TCP/IP详解,卷1:协议 图12-3 D类IP地址到以太网多播地址的映射 局域网网卡趋向两种处理类型:一种是网卡根据对多播地址的散列值实行多播过 滤,这意味仍会接收到不想接收的多播数据;另一种是网卡只接收一些固定数目的多 播地址,这意味着当主机想接收超过网卡预先支持多播地址以外的多播地址时,必须 将网卡设置为“多播混杂(multicast promiscuous)”模式。因此,这两种类型的网卡仍需 要设备驱动程序检查收到的帧是否真是主机所需要的。 即使网卡实现了完美的多播过滤(基于48 bit的硬件地址),由于从D类I P地址到48 bit 的硬件地址的映射不是一对一的,过滤过程仍是必要的。 尽管存在地址映射不完美和需要硬件过滤的不足,多播仍然比广播好。 单个物理网络的多播是简单的。多播进程将目的 I P地址指明为多播地址,设备驱动程序将 它转换为相应的以太网地址,然后把数据发送出去。这些接收进程必须通知它们的 I P层,它们 想接收的发往给定多播地址的数据报,并且设备驱动程序必须能够接收这些多播帧。这个过程 就是“加入一个多播组”(使用“接收进程”复数形式的原因在于对一确定的多播信息,在同一 主机或多个主机上存在多个接收者,这也是为什么要首先使用多播的原因)。当一个主机收到多 播数据报时,它必须向属于那个多播组的每个进程均传送一个复制。这和单个进程收到单播 U D P数据报的U D P不同。使用多播,一个主机上可能存在多个属于同一多播组的进程。 当把多播扩展到单个物理网络以外需要通过路由器转发多播数据时,复杂性就增加了。 需要有一个协议让多播路由器了解确定网络中属于确定多播组的任何一个主机。这个协议就 是I n t e r n e t组管理协议(I G M P),也是下一章介绍的内容。 12.4.3 FDDI和令牌环网络中的多播 F D D I网络使用相同的D类I P地址到48 bit FDDI地址的映射过程[Katz 1990]。令牌环网络 通常使用不同的地址映射方法,这是因为大多数令牌控制中的限制。 12.5 小结 广播是将数据报发送到网络中的所有主机(通常是本地相连的网络),而多播是将数据报 发送到网络的一个主机组。这两个概念的基本点在于当收到送往上一个协议栈的数据帧时采 用不同类型的过滤。每个协议层均可以因为不同的理由丢弃数据报。 目前有四种类型的广播地址:受限的广播、指向网络的广播、指向子网的广播和指向所 有子网的广播。最常用的是指向子网的广播。受限的广播通常只在系统初始启动时才会用到。 多播组地址中的这 5 bit未用 作形成以太网地址 多播组地址中的低位23位复制到 对应的以太网地址中 D类IP地址 48位以太网地址试图通过路由器进行广播而发生的问题,常常是因为路由器不了解目的网络的子网掩码。 结果与多种因素有关:广播地址类型、配置参数等等。 D类I P地址被称为多播组地址。通过将其低位 23 bit映射到相应以太网地址中便可实现多 播组地址到以太网地址的转换。由于地址映射是不唯一的,因此需要其他的协议实现额外的 数据报过滤。 习题 12.1 广播是否增加了网络通信量? 12.2 考虑一个拥有5 0台主机的以太网:2 0台运行T C P / I P,其他3 0台运行其他的协议族。主机 如何处理来自运行另一个协议族主机的广播? 12.3 登录到一个过去从来没有用过的 U n i x系统,并且打算找出所有支持广播的接口的指向子 网的广播地址。如何做到这点? 12.4 如果我们用p i n g程序向一个广播地址发送一个长的分组,如 它正常工作,但将分组的长度再增加一个字节后出现如下差错: sun % ping 140.252.13.63 1473 PING 140.252.13.63: 1473 data bytes sendto: Message too long 究竟出了什么问题? 12.5 重做习题1 0 . 6,假定8个R I P报文是通过多播而不是广播(使用 RIP 版本2)。有什么变 化? 第12章 广播和多播使用135第13章 IGMP:Internet组管理协议 13.1 引言 1 2 . 4节概述了I P多播给出,并介绍了 D类I P地址到以太网地址的映射方式。也简要说明了 在单个物理网络中的多播过程,但当涉及多个网络并且多播数据必须通过路由器转发时,情 况会复杂得多。 本章将介绍用于支持主机和路由器进行多播的 I n t e r n e t组管理协议( I G M P)。它让一个物理网络上的所 有系统知道主机当前所在的多播组。多播路由器需要这 些信息以便知道多播数据报应该向哪些接口转发。 I G M P 在RFC 111 2中定义 [Deering 1989]。 正如 I C M P一样, I G M P 也被当作 I P 层的一部分。 I G M P报文通过I P数据报进行传输。不像我们已经见到的其他协议, I G M P有固定的报文长度, 没有可选数据。图1 3 - 1显示了I G M P报文如何封装在I P数据报中。 I G M P报文通过I P首部中协议字段值为2来指明。 13.2 IGMP报文 图1 3 - 2显示了长度为8字节的I G M P报文格式。 图13-2 IGMP报文的字段格式 这是版本为1的I G M P。I G M P类型为1说明是由多播路由器发出的查询报文,为 2说明是主 机发出的报告报文。检验和的计算和 I C M P协议相同。 组地址为D类I P地址。在查询报文中组地址设置为 0,在报告报文中组地址为要参加的组 地址。在下一节中,当介绍 I G M P如何操作时,我们将会更详细地了解它们。 13.3 IGMP 协议 13.3.1 加入一个多播组 多播的基础就是一个进程的概念(使用的术语进程是指操作系统执行的一个程序),该进 程在一个主机的给定接口上加入了一个多播组。在一个给定接口上的多播组中的成员是动态 图13-1 IGMP报文封装在IP数据报中 IP数据报 IP首部 IGMP报文 20字节 8字节 4位 IGMP 版本(1) 4位 IGMP 类型(1-2) 未用 检验和 32位组地址(D类IP地址) 8字节的— 它随时因进程加入和离开多播组而变化。 这里所指的进程必须以某种方式在给定的接口上加入某个多播组。进程也能离开先前加 入的多播组。这些是一个支持多播主机中任何 A P I所必需的部分。使用限定词“接口”是因为 多播组中的成员是与接口相关联的。一个进程可以在多个接口上加入同一多播组。 S t a n f o r d大学伯克利版U n i x中的IP 多播详细说明了有关socket API的变化,这些变 化在Solaris 2.x和ip(7)的文档中也提供了。 这里暗示一个主机通过组地址和接口来识别一个多播组。主机必须保留一个表,此表中 包含所有至少含有一个进程的多播组以及多播组中的进程数量。 13.3.2 IGMP 报告和查询 多播路由器使用I G M P报文来记录与该路由器相连网络中组成员的变化情况。使用规则如 下: 1) 当第一个进程加入一个组时,主机就发送一个 I G M P报告。如果一个主机的多个进程加 入同一组,只发送一个I G M P报告。这个报告被发送到进程加入组所在的同一接口上。 2) 进程离开一个组时,主机不发送 I G M P报告,即便是组中的最后一个进程离开。主机知 道在确定的组中已不再有组成员后,在随后收到的 I G M P查询中就不再发送报告报文。 3) 多播路由器定时发送I G M P查询来了解是否还有任何主机包含有属于多播组的进程。多 播路由器必须向每个接口发送一个 I G M P查询。因为路由器希望主机对它加入的每个多播组均 发回一个报告,因此I G M P查询报文中的组地址被设置为 0。 4) 主机通过发送I G M P报告来响应一个I G M P查询,对每个至少还包含一个进程的组均要 发回I G M P报告。 使用这些查询和报告报文,多播路由器对每个接口保持一个表,表中记录接口上至少还 包含一个主机的多播组。当路由器收到要转发的多播数据报时,它只将该数据报转发到(使 用相应的多播链路层地址)还拥有属于那个组主机的接口上。 图1 3 - 3显示了两个I G M P报文,一个是主机发送的报告,另一个是路由器发送的查询。该 路由器正在要求那个接口上的每个主机说明它加入的每个多播组。 图13-3 IGMP的报告和查询 对T T L字段我们将在本节的后面介绍。 13.3.3 实现细节 为改善该协议的效率,有许多实现的细节要考虑。首先,当一个主机首次发送 I G M P报告 第13章 IGMP:Internet组管理协议使用137 IGMP报告,TTL=1, IGMP组地址=组地址 目的IP地址=组地址 源IP地址=主机的IP地址 IGMP查询,TTL=1, IGMP组地址=0 目的IP地址=224.0.0.1 源IP地址=路由器IP地址 主机 多播路 由器(当第一个进程加入一个多播组)时,并不保证该报告被可靠接收(因为使用的是I P交付服务)。 下一个报告将在间隔一段时间后发送。这个时间间隔由主机在 0 ~ 1 0秒的范围内随机选择。 其次,当一个主机收到一个从路由器发出的查询后,并不立即响应,而是经过一定的时 间间隔后才发出一些响应(采用“响应”的复数形式是因为该主机必须对它参加的每个组均 发送一个响应)。既然参加同一多播组的多个主机均能发送一个报告,可将它们的发送间隔设 置为随机时延。在一个物理网络中的所有主机将收到同组其他主机发送的所有报告,因为如 图1 3 - 3所示的报告中的目的地址是那个组地址。这意味着如果一个主机在等待发送报告的过 程中,却收到了发自其他主机的相同报告,则该主机的响应就可以不必发送了。因为多播路 由器并不关心有多少主机属于该组,而只关心该组是否还至少拥有一个主机。的确,一个多 播路由器甚至不关心哪个主机属于一个多播组。它仅仅想知道在给定的接口上的多播组中是 否还至少有一个主机。 在没有任何多播路由器的单个物理网络中,仅有的 I G M P通信量就是在主机加入一个新的 多播组时,支持I P多播的主机所发出的报告。 13.3.4 生存时间字段 在图1 3 - 3中,我们注意到I G M P报告和查询的生存时间 ( T T L )均设置为1,这涉及到I P首部 中的T T L字段。一个初始 T T L为0的多播数据报将被限制在同一主机。在默认情况下,待传多 播数据报的T T L被设置为1,这将使多播数据报仅局限在同一子网内传送。更大的 T T L值能被 多播路由器转发。 回顾6 . 2节,对发往一个多播地址的数据报从不会产生 I C M P差错。当T T L值为0时,多播 路由器也不产生I C M P“超时”差错。 在正常情况下,用户进程不关心传出数据报的 T T L。然而,一个例外是Tr a c e r o u t e 程序(第8章),它主要依据设置T T L值来完成。既然多播应用必须能够设置要传送数 据报的TTL值,这意味着程序设计接口必须为用户进程提供这种能力。 通过增加T T L值的方法,一个应用程序可实现对一个特定服务器的扩展环搜索 ( e x p a n d i n g ring search)。第一个多播数据报以T T L等于1发送。如果没有响应,就尝试将 T T L设置为2,然 后3,等等。在这种方式下,该应用能找到以跳数来度量的最近的服务器。 从2 2 4 . 0 . 0 . 0到2 2 4 . 0 . 0 . 2 5 5的特殊地址空间是打算用于多播范围不超过 1跳的应用。不管 T T L值是多少,多播路由器均不转发目的地址为这些地址中的任何一个地址的数据报。 13.3.5 所有主机组 在图1 3 - 3中,我们看到了路由器的 I G M P查询被送到目的 I P地址2 2 4 . 0 . 0 . 1。该地址被称为 所有主机组地址。它涉及在一个物理网络中的所有具备多播能力的主机和路由器。当接口初 始化后,所有具备多播能力接口上的主机均自动加入这个多播组。这个组的成员无需发送 I G M P报告。 13.4 一个例子 现在我们已经了解了一些 I P多播的细节,再来看看所包含的信息。我们使 s u n主机能够支 138使用TCP/IP详解,卷1:协议第13章 IGMP:Internet组管理协议使用139 持多播,并将采用一些多播软件所提供的测试程序来观察具体的过程。 首先,采用一个经过修改的 n e t s t a t命令来报告每个接口上的多播组成员情况(在 3 . 9节 显示了n e t s t a t - n i命令的输出结果)。在下面的输出中,用黑体表示有关的多播组。 其中,- n参数将以数字形式显示 I P地址(而不是按名字来显示它们),- i参数将显示接 口的统计结果,- a参数将显示所有配置的接口。 输出结果中的第2行l e 0(以太网)显示了这个接口属于主机组 2 2 4 . 0 . 0 . 1(“所有主机”), 和两行地址,后一行显示相应的以太网地址为: 0 1 : 0 0 : 5 e : 0 0 : 0 0 : 0 1。这正是我们期望看到的以 太网地址,和 1 2 . 4节介绍的地址映射一致。我们还看到其他两个支持多播的接口: S L I P接口 s l 0和回送接口l o 0,它们也属于所有主机组。 我们也必须显示 I P路由表,用于多播的路由表同正常的路由表一样。黑体表项显示了所 有传往2 2 4 . 0 . 0 . 0的数据报均被送往以太网: 如果将这个路由表与 9 . 2节中 s u n路由器的路由表作比较,会发现只是多了有关多播的条 目。 现在使用一个测试程序来让我们能在一个接口上加入一个多播组(不再显示使用这个测 试程序的过程)。在以太网接口(1 4 0 . 2 5 2 . 1 3 . 3 3)上加入多播组2 2 4 . 1 . 2 . 3。执行n e t s t a t程序 看到内核已加入这个组,并得到期望的以太网地址。用黑体字来突出显示和前面 n e t s t a t输 出的不同。 我们在输出中再次显示了其他两个接口: s l 0和l o 0,目的是为了重申加入多播组只发生 在一个接口上。140使用TCP/IP详解,卷1:协议 图1 3 - 4显示了t c p d u m p对进程加入这个多播组的跟踪过程。 图13-4 当一个主机加入1个多播组时t c p d u m p 的输出结果 当主机加入多播组时产生第 1行的输出显示。第2行是经过时延后的I G M P报告,我们介绍 过报告重发的时延是1 0秒内的随机时延。 在两行中显示硬件地址证实了以太网目的地址就是正确的多播地址。我们也看到了源 I P 地址为相应的 s u n主机地址,而目的 I P地址是多播组地址。同时,报告的地址和期望的多播 组地址是一致的。 最后,我们注意到,正像指明的那样, T T L是1。当T T L的值为0或1时,t c p d u m p在打印 时用方括号将它们括起来,这是因为 T T L在正常情况下均高于这些值。然而,使用多播我们 期望看到许多T T L为1的I P数据报。 在这个输出中暗示了一个多播路由器必须接收在它所有接口上的所有多播数据报。路由 器无法确定主机可能加入哪个多播组。 多播路由器的例子 继续前面的例子,但我们将在 s u n主机中启动一个多播选路的守护程序。这里我们感兴 趣的并不是多播选路协议,而是要研究所交换的 I G M P查询和报告。即使多播选路守护程序只 运行在支持多播的主机( s u n)上,所有的查询和报告都将在那个以太网上进行多播,所以 我们在该以太网中的其他系统中也能观察到它们。 在启动选路守护程序之前,加入另外一个多播组 2 2 4 . 9 . 9 . 9,图1 3 - 5显示了输出的结果。 图13-5 当多播选路守护程序运行时t c p d u m p 的输出结果 在这个输出中没有包括以太网地址,因为已经证实了它们是正确的。也删去了 T T L等于1 的说明,同样因为它们也是我们期望的那样。 当选路守护程序启动时,输出第 1行。它发出一个已经加入了组 2 2 4 . 0 . 0 . 4的报告。多播地 址2 2 4 . 0 . 0 . 4是一个知名的地址,它被当前用于多播选路的距离向量多播选路协议 D V M R P(Distance Vector Multicast Routing Protocol)所使用(D V M R P在RFC 1075中定义[ Wa i t z m a n , Partridge, and Deering])。 在该守护程序启动时,它也发送一个 I G M P查询(第 2行)。该查询的目的 I P地址为 2 2 4 . 0 . 0 . 1(所有主机组),如图1 3 - 3所示。 第一个报告(第 3行)大约在5秒后收到,报告给组 2 2 4 . 9 . 9 . 9。这是在下一个查询发出之 前(第4行)收到的唯一报告。当守护程序启动后,两次查询(第 2行和第4行)发出的间隔很 短,这是因为守护程序要将其多播路由表尽快建立起来。 第5、6和7行正是我们期望看到的: s u n主机针对它所属的每个组发出一个报告。注意组 2 2 4 . 0 . 0 . 4是被报告的,而其他两个组则是明确加入的,因为只要选路守护程序还在运行,它 始终要属于组2 2 4 . 0 . 0 . 4。 下一个查询位于第 8行,大约在前一个查询的 2分钟后发出。它再次引发三个我们所期望 的报告(第9、1 0和11行)。这些报告的时间顺序与前面不同,因为接收查询和发送报告的时 间是随机的。 最后的查询在前一个查询的大约 2分钟后发出,我们再次得到了期望的响应。 13.5 小结 多播是一种将报文发往多个接收者的通信方式。在许多应用中,它比广播更好,因为多 播降低了不参与通信的主机的负担。简单的主机成员报告协议 ( I G M P )是多播的基本模块。 在一个局域网中或跨越邻近局域网的多播需要使用本章介绍的技术。广播通常局限在单 个局域网中,对目前许多使用广播的应用来说,可采用多播来替代广播。 然而,多播还未解决的一个问题是在广域网内的多播。 [Deering and Cheriton 1990] 提出 扩展目前的路由协议来支持多播。 9 . 1 3节中的[Perlman 1992]讨论了广域网多播的一些问题。 [Casner and Deering 1992] 介绍了使用多播和一个称为 M B O N E(多播主干)的虚拟网络 在整个I n t e r n e t上传送I E T F会议的情况。 习题 13.1 我们知道主机通过设置随机时延来调度 I G M P的发送。一个局域网中的主机采取什么措 施才能避免两台主机产生相同的随机时延? 13.2 在[Casner and Deering 1992]中,他们提到U D P缺少两个通过M B O N E传送音频采样数据 的条件:分组失序检测和分组重复检测。你怎样在 U D P上增加这些功能? 第13章 IGMP:Internet组管理协议使用141第14章 DNS:域名系统 14.1 引言 域名系统(D N S)是一种用于 T C P / I P应用程序的分布式数据库,它提供主机名字和 I P地 址之间的转换及有关电子邮件的选路信息。这里提到的分布式是指在 I n t e r n e t上的单个站点不 能拥有所有的信息。每个站点(如大学中的系、校园、公司或公司中的部门)保留它自己的 信息数据库,并运行一个服务器程序供 I n t e r n e t上的其他系统(客户程序)查询。 D N S提供了 允许服务器和客户程序相互通信的协议。 从应用的角度上看,对 D N S的访问是通过一个地址解析器( r e s o l v e r)来完成的。在U n i x 主机中,该解析器主要是通过两个库函数 g e t h o s t b y n a m e(3) 和g e t h o s t b y a d d r( 3 )来访问 的,它们在编译应用程序时与应用程序连接在一起。前者接收主机名字返回 I P地址,而后者 接收I P地址来寻找主机名字。解析器通过一个或多个名字服务器来完成这种相互转换。 图4 - 2中指出了解析器通常是应用程序的一部分。解析器并不像 T C P / I P协议那样是操作系 统的内核。该图指出的另一个基本概念就是:在一个应用程序请求 T C P打开一个连接或使用 U D P发送一个数据报之前。心须将一个主机名转换为一个 I P地址。操作系统内核中的 T C P / I P 协议族对于D N S一点都不知道。 本章我们将了解地址解析器如何使用 T C P / I P协议(主要是U D P)与名字服务器通信。我 们不介绍运行名字服务器或有关可选参数的细节,这些技术细节的内容可以覆盖整整一本书。 (见[Albitz and Liu 1992]标准U n i x解析器和名字服务器介绍)。 RFC 1034 [Mockapetris 1987a] 说明了D N S的概念和功能,RFC 1035 [Mockapetris 1987b] 详细说明了DNS 的规范和实现。D N S最常用的版本(包括解析器和名字服务器)是 B I N D— 伯克利I n t e r n e t域名服务器。该服务器称作 n a m e d。[ D a n z i g、O b r a c z k a和Kumar 1992]分析了 DNS 在广域网中产生的通信量。 14.2 DNS 基础 D N S的名字空间和U n i x的文件系统相似,也具有层次结构。图 14-1 显示了这种层次的组 织形式。 每个结点(图 1 4 - 1中的圆圈)有一个至多 6 3个字符长的标识。这颗树的树根是没有任何 标识的特殊结点。命名标识中一律不区分大写和小写。命名树上任何一个结点的域名就是将 从该结点到最高层的域名串连起来,中间使用一个点“.”分隔这些域名(注意这和 U n i x文件 系统路径的形成不同,文件路径是由树根依次向下的形成的)。域名树中的每个结点必须有一 个唯一的域名,但域名树中的不同结点可使用相同的标识。 以点“.”结尾的域名称为绝对域名或完全合格的域名 F Q D N(Full Qualified Domain N a m e),例如s u n . t u c . n o a o . e d u .。如果一个域名不以点结尾,则认为该域名是不完全的。 如何使域名完整依赖于使用的 D N S软件。如果不完整的域名由两个或两个以上的标号组成,第14章 DNS:域名系统使用143 则认为它是完整的;或者在该域名的右边加入一个局部后缀。例如域名 s u n通过加上局部后 缀. t u c . n o a o . e d u .成为完整的。 图14-1 DNS的层次组织 顶级域名被分为三个部分: 1) a r p a是一个用作地址到名字转换的特殊域(我们将在 1 4 . 5节介绍)。 2) 7个3字符长的普通域。有些书也将这些域称为组织域。 3) 所有2字符长的域均是基于 I S O 3 1 6 6中定义的国家代码,这些域被称为国家域,或地理 域。 图1 4 - 2列出了7个普通域的正式划分。 在D N S中,通常认为 3字符长的普通域仅 用于美国的组织机构, 2字符长的国家域则用 于每个国家,但情况并不总是这样。许多非美 国的组织机构仍然使用普通域,而一些美国的 组织机构也使用 . u s的国家域( RFC 1480 [Cooper and Postel 1993] 详细描述了. u s域)。 普通域中只有. g o v和. m i l域局限于美国。 许多国家将它们的二级域组织成类似于普通域的结构:例如, . a c . u k是英国研究机构的 二级域名,. c o . u k则是英国商业机构的二级域名。 D N S的一个没在如图 1 4 - 1中表示出来的重要特征是 D N S中域名的授权。没有哪个机构来 管理域名树中的每个标识,相反,只有一个机构,即网络信息中心 N I C负责分配顶级域和委派 其他指定地区域的授权机构。 未命名树根 顶级域 第二级域 普通域 阿拉伯联合 酋长国 津巴布韦 国家域 图14-2 3字符长的普通域 域 描 述 商业组织 教育机构 其他美国政府部门 国际组织 美国军事网点 网络 其他组织一个独立管理的 D N S子树称为一个区域 ( z o n e )。一个常见的区域是一个二级域,如 n o a o . e d u。许多二级域将它们的区域划分成更小的区域。例如,大学可能根据不同的系来 划分区域,公司可能根据不同的部门来划分区域。 如果你熟悉U n i x的文件系统,会注意到D N S树中区域的划分同一个逻辑U n i x文件 系统到物理磁盘分区的划分很相似。正如无法确定图 1 4 - 1中区域的具体位置,我们也 不知道一个Unix文件系统中的目录位于哪个磁盘分区。 一旦一个区域的授权机构被委派后,由它负责向该区域提供多个名字服务器。当一个新 系统加入到一个区域中时,该区域的 D N S管理者为该新系统申请一个域名和一个 I P地址,并 将它们加到名字服务器的数据库中。这就是授权机构存在的必要性。例如,在一个小规模的 大学,一个人就能完成每次新系统的加入。但对一个规模较大的大学来说,这一工作必须被 专门委派的机构(可能是系)来完成,因为一个人已无法维持这一工作。 一个名字服务器负责一个或多个区域。一个区域的管理者必须为该区域提供一个主名字 服务器和至少一个辅助名字服务器。主、辅名字服务器必须是独立和冗余的,以便当某个名 字服务器发生故障时不会影响该区域的名字服务。 主、辅名字服务器的主要区别在于主名字服务器从磁盘文件中调入该区域的所有信息, 而辅名字服务器则从主服务器调入所有信息。我们将辅名字服务器从主服务器调入信息称为 区域传送。 当一个新主机加入一个区域时,区域管理者将适当的信息(最少包括名字和 I P地址)加 入到运行在主名字服务器上的一个磁盘文件中,然后通知主名字服务器重新调入它的配置文 件。辅名字服务器定时(通常是每隔 3小时)向主名字服务器询问是否有新数据。如果有新数 据,则通过区域传送方式获得新数据。 当一个名字服务器没有请求的信息时,它将如何处理?它必须与其他的名字服务器联系。 (这正是D N S的分布特性)。然而,并不是每个名字服务器都知道如何同其他名字服务器联系。 相反,每个名字服务器必须知道如何同根的名字服务器联系。 1 9 9 3年4月时有8个根名字服务 器,所有的主名字服务器都必须知道根服务器的 I P地址(这些I P地址在主名字服务器的配置 文件中,主服务器必须知道根服务器的 I P地址,而不是它们的域名)。根服务器则知道所有二 级域中的每个授权名字服务器的名字和位置(即 I P地址)。这意味着这样一个反复的过程:正 在处理请求的名字服务器与根服务器联系,根服务器告诉它与另一个名字服务器联系。在本 章的后面我们将通过一些例子来详细了解这一过程。 你可以通过匿名的F T P获取当前的根服务器清单。具体是从f t p . r s . i n t e r n i c . n e t 或nic.ddn.mil 获取文件n e t i n f o / r o o t - s e r v e r s . t x t。 D N S的一个基本特性是使用超高速缓存。即当一个名字服务器收到有关映射的信息(主 机名字到 I P地址)时,它会将该信息存放在高速缓存中。这样若以后遇到相同的映射请求, 就能直接使用缓存中的结果而无需通过其他服务器查询。 1 4 . 7节显示了一个使用高速缓存的 例子。 14.3 DNS的报文格式 D N S定义了一个用于查询和响应的报文格式。图 1 4 - 3显示这个报文的总体格式。 144使用TCP/IP详解,卷1:协议图14-3 DNS查询和响应的一般格式 这个报文由1 2字节长的首部和4个长度可变的字段组成。 标识字段由客户程序设置并由服务器返回结果。客户程序通过它来确定响应与查询是否 匹配。 16 bit的标志字段被划分为若干子字段,如图 1 4 - 4所示。 图14-4 DNS报文首部中的标志字段 我们从最左位开始依次介绍各子字段: • QR 是1 bit字段:0表示查询报文,1表示响应报文。 • o p c o d e是一个4 bit字段:通常值为0(标准查询),其他值为1(反向查询)和2(服务器 状态请求)。 • A A是1 bit标志,表示“授权回答 (authoritative answer)”。该名字服务器是授权于该域 的。 • T C是1 bit字段,表示“可截断的 ( t r u n c a t e d )”。使用U D P时,它表示当应答的总长度超 过5 1 2字节时,只返回前5 1 2个字节。 • R D是1 bit字段表示“期望递归( recursion desired)”。该比特能在一个查询中设置,并 在响应中返回。这个标志告诉名字服务器必须处理这个查询,也称为一个递归查询。如 果该位为0,且被请求的名字服务器没有一个授权回答,它就返回一个能解答该查询的 其他名字服务器列表,这称为迭代查询。在后面的例子中,我们将看到这两种类型查询 的例子。 • R A是1 bit字段,表示“可用递归”。如果名字服务器支持递归查询,则在响应中将该比 特设置为1。在后面的例子中可看到大多数名字服务器都提供递归查询,除了某些根服 务器。 第14章 DNS:域名系统使用145 标识 标志 资源记录数 额外资源记录数 查询问题 回答 (资源记录数可变) 授权 (资源记录数可变) 额外信息 (资源记录数可变) 12字节问题数 授权资源记录数• 随后的3 bit字段必须为0。 • r c o d e是一个4 bit的返回码字段。通常的值为 0(没有差错)和3(名字差错)。名字差错 只有从一个授权名字服务器上返回,它表示在查询中制定的域名不存在。 随后的 4个16 bit字段说明最后 4个变长字段中包含的条目数。对于查询报文,问题 ( q u e s t i o n )数通常是1,而其他3项则均为0。类似地,对于应答报文,回答数至少是 1,剩下的 两项可以是0或非0。 14.3.1 DNS查询报文中的问题部分 问题部分中每个问题的格式如图 1 4 - 5所示,通常只有一个问题。 图14-5 DNS查询报文中问题部分的格式 查询名是要查找的名字,它是一个或多个标识符的序列。每个标识符以首字节的计数值 来说明随后标识符的字节长度,每个名字以最后字节为 0结束,长度为0的标识符是根标识符。 计数字节的值必须是 0 ~ 6 3的数,因为标识符的最大长度仅为 6 3(在本节的后面我们将看到计 数字节的最高两比特为1,即值1 9 2 ~ 2 5 5,将用于压缩格式)。不像我们已经看到的许多其他报 文格式,该字段无需以整32 bit边界结束,即无需填充字节。 图1 4 - 6显示了如何存储域名g e m i n i . t u c . n o a o . e d u。 图14-6 域名g e m i n i . t u c . n o a o . e d u 的表示 每个问题有一个查询类型,而每个响应(也称一个资源记录,我们下面将谈到)也有一 个类型。大约有2 0个不同的类型值,其中的一些目前已经过时。图 1 4 - 7显示了其中的一些值。 查询类型是类型的一个超集 ( s u p e r s e t ):图中显示的类型值中只有两个能用于查询类型。 图14-7 DNS问题和响应的类型值和查询类型值 146使用TCP/IP详解,卷1:协议 查询名 查询类型 0 15 16 31 查询类 计数 计数 计数 计数 计数 名 字 数 值 描 述 类型? 查询 类型 IP地址 名字服务器 规范名称 指针记录 主机信息 邮件交换记录 对区域转换的请求 对所有记录的请求或最常用的查询类型是 A类型,表示期望获得查询名的 I P地址。一个P T R查询则请求获得一 个I P地址对应的域名。这是一个指针查询,我们将在 1 4 . 5节介绍。其他的查询类型将在 1 4 . 6节 介绍。 查询类通常是1,指互联网地址(某些站点也支持其他非 I P地址)。 14.3.2 DNS响应报文中的资源记录部分 D N S报文中最后的三个字段,回答字段、授权字段和附加信息字段,均采用一种称为资 源记录R R(Resource Record)的相同格式。图1 4 - 8显示了资源记录的格式。 图14-8 DNS资源记录格式 域名是记录中资源数据对应的名字。它的格式和前面介绍的查询名字段格式(图 1 4 - 6) 相同。 类型说明 R R的类型码。它的值和前面介绍的查询类型值是一样的。类通常为 1,指 I n t e r n e t数据。 生存时间字段是客户程序保留该资源记录的秒数。资源记录通常的生存时间值为 2天。 资源数据长度说明资源数据的数量。该数据的格式依赖于类型字段的值。对于类型 1(A 记录)资源数据是4字节的I P地址。 现在已经介绍了D N S查询和响应的基本格式,我们将使用 t c p d u m p程序来观察具体的交 换过程。 14.4 一个简单的例子 让我们从一个简单的例子来了解一个名字解析器与一个名字服务器之间的通信过程。在 s u n主机上运行Te l n e t客户程序远程登录到g e m i n i主机上,并连接d a y t i m e服务器: 在这个例子中,我们引导 s u n主机(运行 Te l n e t客户程序)上的名字解析器来使用位于 n o a o . e d u(1 4 0 . 2 5 2 . 1 . 5 4)的名字服务器。图1 4 - 9显示了这三个系统的排列情况。 第14章 DNS:域名系统使用147 域名 类型 类 生存时间 资源数据长度 资源数据 前3行的输出是从Telnet客户 这是从daytime服务器的输出 这是从Telnet客户的输出和以前提到的一样,名字解析器是客户程序 的一部分,并且在 Te l n e t客户程序与 d a y t i m e服务 器建立T C P连接之前,名字解析器就能通过名字 服务器获取I P地址。 在这个图中,省略了 s u n主机与 1 4 0 . 2 5 2 . 1以 太网的连接实际上是一个 S L I P连接的细节(参见 封2的插图),因为它不影响我们的讨论。通过在 S L I P链路上运行t c p d u m p程序来了解名字解析器 与名字服务器之间的分组交换。 s u n主机上的文件/ e t c / r e s o l v . c o n f将告诉名字解析器作什么: sun % cat /etc/resolv.conf nameserver 140.252.1.54 domain tuc.noao.edu 第1行给出名字服务器— 主机n o a o . e d u的I P地址。最多可说明3个名字服务器行来提供 足够的后备以防名字服务器故障或不可达。域名行说明默认域名。如果要查找的域名不是一个 完全合格的域名(没有以句点结束),那末默认的域名. t u c . n o a o . e d u将加到待查名后。 图1 4 - 1 0显示了名字解析器与名字服务器之间的分组交换。 图14-10 向名字服务器查询主机名g e m i n i . t u c . n o a o . e d u 的输出 让t c p d u m p程序不再显示每个 I P数据报的源地址和目的地址。相反,它显示客户 (r e s o l v e r)的I P地址1 4 0 . 2 5 2 . 1 . 2 9和名字服务器的 I P地址1 4 0 . 2 5 2 . 1 . 5 4。客户的临时端口号为 1 4 4 7,而名字服务器则使用熟知端口 5 3。如果让t c p d u m p程序显示名字而不是 I P地址,它可 能会和同一个名字服务器联系(作指示查询),以致产生混乱的输出结果。 第1行中冒号后的字段(1 +)表示标识字段为1,加号“+”表示R D标志(期望递归)为1。 默认情况下,名字解析器要求递归查询方式。 下一个字段为A ?,表示查询类型为 A(我们需要一个I P地址),该问号指明它是一个查询 (不是一个响应)。待查名字显示在后面: g e m i n i . t u c . n o a o . e d u .。名字解析器在待查名 字后加上句点号指明它是一个绝对字段名。 在U D P数据报中的用户数据长度显示为 3 7字节:1 2字节为固定长度的报文首部(图 1 4 - 3);2 1字节为查询名字(图1 4 - 6),以及用于查询类型和查询类的 4个字节。在D N S报文中无 需填充数据。 t c p d u m p程序的第2行显示的是从名字服务器发回的响应。 1 *是标识字段,星号表示设置 A A标志(授权回答)(该服务器是n o a o . e d u域的主域名服务器,其回答在该域内是可相信的。) 输出结果2 / 0 / 0表示在响应报文中最后 3个变长字段的资源记录数:回答 R R数为2,授权 RR 和附加信息 R R数均为0。t c p d u m p仅显示第一个回答,回答类型为 A(I P地址),值为 1 4 0 . 2 5 2 . 1 . 11。 148使用TCP/IP详解,卷1:协议 图14-9 用于简单DNS例子的系统 名字服 务器 daytime 服务器 Telnet 客户为什么我们的查询会得到两个回答?这是因为 g e m i n i是多接口主机,因此得到两个 I P地 址。事实上,另一个有用的 D N S工具是一个称为h o s t的公开程序,它能将查询传递给名字服 务器,并显示返回的结果。如果使用这个程序,就能看到这个多地址主机的两个 I P地址: sun % host gemini gemini.tuc.noao.edu A 1 4 0 . 2 5 2 . 1 . 1 1 g e m i n i . t u c . n o a o . e d u A 1 4 0 . 2 5 2 . 3 . 5 4 图1 4 - 1 0中的第一个回答与 h o s t命令的第一行输出均是在同一子网( 1 4 0 . 2 5 2 . 1)的I P地 址。这不是偶然的。如果名字服务器和发出请求的主机位于相同的网络(或子网),那么 B I N D会排列显示的结果以便在相同网络的地址优先显示。 我们还可以使用其他的地址来访问g e m i n i主机,但它可能不太有效。在这个例子 中,使用t r a c e r o u t e显示出从子网1 4 0 . 2 5 2 . 1到1 4 0 . 2 5 2 . 3的正常路由不经过g e m i n i主机, 而是经过连接这两个网络的另一个路由器。因此在这种情况下,如果通过其他的I P地址 (1 4 0 . 2 5 2 . 3 . 5 4)来访问g e m i n i主机,所有分组均需经过额外的一跳。我们将在2 5 . 9节重 新回到这个例子来探讨替换路由,那时可使用S N M P来查看一个路由器的路由表。 还有其他一些程序能很容易地对D N S进行交互访问。n s l o o k u p是大多数D N S实现 中包含的程序。[Albitz and Liu 1992]的第10章详细介绍了该程序的使用方法。dig (“域 名I n t e r n e t搜索(Domain Internet Groper)”)程序是另一个查询D N S服务器的公开工具。 doc (“域名模糊控制(Domain Obscenity Control)”)是一个使用d i g的外壳脚本程序,它 能向合适的名字服务器发送查询来诊断含义不清的域名,并对返回的查询结果进行简 单的分析。附录F有如何获得这些程序的详细介绍。 在这个例子中要说明的最后一个问题是在查询结果中的 U D P数据长度:6 9字节。为说明 这些字节需要知道以下两点: 1) 在返回的结果中包含查询问题。 2) 在返回的结果中会有许多重复的域名,因此使用压缩方式。在这个例子中,域名 g e m i n i . t u c . n o a o . e d u出现了三次。 压缩方法很简单,当一个域名中的标识符是压缩的,它的单计数字节(范围由 0~6 3)中 的最高两位将被设置为 11。这表示它是一个16 bit指针而不再是8 bit的计数字节。指针中的剩 下14 bit说明在该D N S报文中标识符所在的位置(起始位置由标识字段的第一字节起算)。我 们明确说明只要一个标识符是压缩的,就可以使用这种指针,而不一定非要一个完整的域名 压缩时才能使用。因为一个指针可能指向一个完整的域名,也可能只指向域名的结尾部分 (这是因为给定域名的结尾标识符是相同的)。 图1 4 - 11显示了对应于图1 4 - 1 0的第2行的D N S应答的格式。我们也显示了 I P首部和U D P首 部来重申D N S报文被封装在U D P数据报中。还明确显示了在问题部分的域名中各标识符的计 数字节。返回的两个回答除了返回的 I P地址不同外,其余都是一样的。在这个例子中,每个 回答中的指针值为1 2,表示从D N S首部开始的偏移量。 在这个例子中最后要注意的是使用 t e l n e t命令后输出的第2行,这里重复一下: sun % telnet gemini daytime 我们只键入g e m i n i Trying 140.252.1.11 ... Connected to gemini.tuc.noao.edu. 但T e l n e t客户输出F Q D N 第14章 DNS:域名系统使用149图14-11 对应于图14-10中第2行DNS应答的格式 我们仅仅输入了主机名 (g e m i n i)而不是F Q D N,但Te l n e t客户程序部输出了 F Q D N。这是 由于Te l n e t程序通过调用名字解析器( g e t h o s t b y n a m e)对输入的名字进行查询,返回的结 果包括I P地址和F Q D N。Te l n e t程序就输出它试图与之建立 T C P连接的I P地址,当连接建立后, 它就输出F Q D N。 如果在输入Te l n e t命令后间隔很长时间才显示 I P地址,这个时延是由名字解析器和名字服 务器在由域名到I P地址的解析所引起的。而显示 Trying 到显示Connected to的时延则是 由客户与服务器建立T C P连接所引起的,与D N S无关。 14.5 指针查询 D N S中一直难于理解的部分就是指针查询方式,即给定一个 I P地址,返回与该地址对应 的域名。 首先回到图1 4 - 1,查看一下顶级域a r p a,及它下面的i n - a d d r域。当一个组织加入I n t e r n e t, 并获得D N S域名空间的授权,如n o a o . e d u,则它们也获得了对应I P地址的i n - a d d r . a r p a域名 空间的授权。在n o a o . e d u这个例子中,它是网络号为1 4 0 . 2 5 2的B类网络。在D N S树中结点i n - a d d r . a r p a的下一级必须是该I P地址的第一字节(例中为1 4 0),再下一级为该I P地址的下一个 字节(2 5 2),依此类推。但应牢记的是D N S名字是由D N S树的底部逐步向上书写的。这意味着 对于I P地址为1 4 0 . 2 5 2 . 1 3 . 3 3的s u n主机,它的D N S名字为3 3 . 1 3 . 2 5 2 . 1 4 0 . i n - a d d r . a r p a。 必须写出4字节的I P地址,因为授权的代表是基于网络号: A类地址是第一字节,B类地址 是第一、二字节,C类地址则是第一、二、三字节。 I P地址的第一字节一定位于i n - a d d r的下 一级,但F Q D N却是自树底往上书写的。如果F Q D N由顶往下书写,则这个I P地址的D N S名字将 是a r p a . i n - a d d r . 1 4 0 . 2 5 2 . 1 3 . 3 3,而它所对应的域名将是e d u . n o a o . t u c . s u n。 如果D N S树中没有独立的分支来处理这种地址—名字的转换,将无法进行这种反向转换, 除非从树根开始依次尝试每个顶级域。毫不夸张地说,这将需要数天或数周的时间。虽然反 写I P地址和特殊的域名会造成某些混乱,但 i n - a d d r解决方案仍是一种最有效的方式。 只有在使用h o s t程序或t c p d u m p程序直接同D N S打交道时,才会担心i n - a d d r域和反写I P 地址影响我们。从应用的角度上看,正常的名字解析器函数(g e t h o s t b y a d d r)将接收一个I P 地址并返回对应主机的有关信息。反转这些字节和添加i n - a d d r . a r p a域均由该函数自动完成。 150使用TCP/IP详解,卷1:协议 IP数据报 UDP数据报 DNS报文 IP首部 域名 UDP 首部 DNS 首部 类型 类 指针 类型 类 长度 地址 问题 (图14-5) 回答#1(RR) (图14-8) 回答#2(RR) (图14-8) 字节字节12字节 25字节 21字节 8字节20字节14.5.1 举例 使用h o s t程序完成一个指针查询,并使用 t c p d u m p程序来观察这些分组。例子中的设置 和图1 4 - 9相同,在s u n主机上运行 h o s t程序,名字服务器在主机 n o a o . e d u上。我们指明 s v r 4主机的I P地址: sun % host 140.252.13.34 Name: svr4.tuc.noao.edu Address: 140.252.13.34 既然I P地址是仅有的命令行参数, h o s t程序将自动产生指针查询。图 1 4 - 1 2显示了t c p d u m p 的输出。 图14-12 一个指针查询的t c p d u m p 输出 第1行显示标识符为 1,期望递归标志设置为 1(加号“+”),查询类型为 P T R(应注意:问号 “?”表示它是一个查询而不是响应)。4 4字节的数据包括1 2字节的D N S报文首部、2 8字节的 域名标识符和4字节的查询类型和查询类。 查询结果包含一个回答 R R,且为授权回答比特置 1(带星号)。R R的类型是P T R,资源数 据中包含该域名。 从名字解析器传递给名字服务器的指针查询不再是 32 bit的 I P地址,而是域名 3 4 . 1 3 . 2 5 2 . 1 4 0 . i n - a d d r . a r p a。 14.5.2 主机名检查 当一个I P数据报到达一个作为服务器的主机时,无论是 U D P数据报还是T C P连接请求,服 务器进程所能获得的是客户的 I P地址和端口号( U D P或T C P)。某些服务器需要客户的 I P地址 来获得在D N S中的指针记录。在2 7 . 3节会看到这样的例子,从未知的 I P地址使用匿名F T P访问 服务器。 其他的一些服务器如R l o g i n服务器(第2 6章)不但需要客户的I P地址来获得指针记录,还 要向D N S询问该I P地址所对应的域名,并检查返回的地址中是否有地址与收到的数据报中的 源I P地址匹配。该检查是因为 . r h o s t s文件(见2 6 . 2节)中的条目仅包含主机名,而没有 I P 地址,因此主机需要证实该主机名是否对应源 I P地址。 某些厂商将该项检查自动并入其名字解析器的例程中,特别是函数 g e t h o s t b y a d d r。 这使得任何使用名字解析器的程序均可获得这种检查,而无需在应用中人为地进行这项检查。 来看一个使用SunOS 4.13名字解析器库的例子。我们编制了一个简单的程序通过调用函数 g e t h o s t b y a d d r来完成一个指针查询。我们已在文件/ e t c / r e s o l v . c o n f中将名字服务器设 置为n o a o . e d u,s u n主机通过S L I P链路与它相连。图1 4 - 1 3显示了当调用函数g e t h o s t b y a d d r 获取与I P地址1 4 0 . 2 5 2 . 1 . 2 9(s u n主机)对应的名字时,t c p d u m p在S L I P链路上收到的内容。 第1行是预期的指针查询,第 2行是预期的响应。但第 3行显示了该名字解析器函数自动对 第2行返回的名字发出一个I P地址查询。既然s u n主机有两个I P地址,第4行的响应就包括两个 第14章 DNS:域名系统使用151回答记录。如果这两个地址中没有与 g e t h o s t b y a d d r输入参数匹配的地址,函数会向系统 的日志发送一条报文,并向应用程序返回差错。 图14-13 调用名字解析器函数执行指针查询 14.6 资源记录 至今我们已经见到了一些不同类型的资源记录(R R):I P地址查询为A类型,指针查询为类型 P T R。也已看到了由名字服务器返回的资源记录:回答R R、授权R R和附加信息R R。现有大约2 0种 不同类型的资源记录,下面将介绍其中的一些。另外,随着时间的推移,会加入更多类型的R R。 A 一个A记录定义了一个I P地址,它存储32 bit的二进制数。 P T R 指针记录用于指针查询。 I P地址被看作是 i n - a d d r . a r p a域下的一个域名 (标识符串)。 C N A M E 这表示“规范名字 (canonical name)”。它用来表示一个域名(标识符串),而 有规范名字的域名通常被称为别名 ( a l i a s )。某些F T P服务器使用它向其他的系 统提供一个易于记忆的别名。 例如,g a t e d服务器(1 0 . 3节提到)可通过匿名F T P从g a t e d . c o r n e l l . e d u 获得,但这里并没有叫做g a t e d的系统,这仅是为其他系统提供的别名。其他 系统的规范名为g a t e d . c o r n e l l . e d u。 sun % host -t cname gated.cornell.edu gated.cornell.edu CNAM COMET.CIT.CORNELL.EDU 这里使用的-t选项来指明它是特定的查询类型。 H I N F O 表示主机信息:包括说明主机 C P U和操作系统的两个字符串。并非所有的站 点均提供它们系统的H I N F O记录,并且提供的信息也可能不是最新的。 sun % host -t hinfo sun sun.tuc.noao.edu HINFO Sun-4/25 Sun4.1.3 M X 邮件交换记录,用于以下一些场合:(1)一个没有连到I n t e r n e t的站点能将一个 连到I n t e r n e t的站点作为它的邮件交换器。这两个站点能够用一种交替的方式交 换到达的邮件,而通常使用的协议是U U C P协议。(2)M X记录提供了一种将无 法到达其目的主机的邮件传送到一个替代主机的方式。(3)M X记录允许机构 提供供他人发送邮件的虚拟主机,如c s . u n i v e r s i t y . e d u,即使这样的主机 名根本不存在。(4)防火墙网关能使用M X记录来限制外界与内部系统的连接。 许多不能与I n t e r n e t连接的站点通过 U U C P链路与一个连接在 I n t e r n e t上的站点 如U U N E T相连接。通过M X记录能使用u s e r @ h o s t这种邮件地址向那个站点 发送电子邮件。例如,一个假想的域 f o o . c o m可能有下面的M X记录: 152使用TCP/IP详解,卷1:协议第14章 DNS:域名系统使用153 sun % host -t mx foo.com foo.com MX r e l a y 1 . U U . N E T foo.com MX relay2.UU.NET M X记录能被连接在互联网主机中的邮件处理器使用。在这个例子中,其他的 邮件处理器则被告知“如果有邮件要发往 u s e r @ f o o . c o m,就将邮件送到 r e l a y 1 . u u . n e t或r e l a y 2 . u u . n e t。” 每个M X记录被赋于一个 16 bit的整数值,该值称为优先值。如果一个目的主 机有多个M X记录,它们按优先值由小到大的顺序使用。 另一个M X记录的例子是处理主机脱机工作或不可达的情况。邮件处理器仅在 无法使用T C P与目的主机连接时才使用 M X记录。作者的主系统通过 S L I P链路 与互联网相连,它在大多数时间内是脱机工作的,我们有 为了显示优先值,我们使用了- v选项(该选项也会导致其他字段的输出)。第 二个字段,8 6 4 0 0,是寿命值,单位为秒。因此该 T T L值为2 4小时(2 4×6 0× 6 0)。第3列,I N,是(I n t e r n e t)类。我们看到直接传送给主机自身(第一个 M X记录)有最低的优先值0。如果没有工作(即S L I P链路断开),会使用下一 个更高优先值( 1 0)的邮件记录,并试图向主机 n o a o . e d u传送。如果它仍 没有成功,发送将超时并在以后重新发送。 N S 名字服务器记录。它说明一个域的授权名字服务器。它由域名表示(符号串)。 在下节将看到这些类型的例子。 这些是R R的常用类型。将在后面的例子中遇到它们。 14.7 高速缓存 为了减少I n t e r n e t上D N S的通信量,所有的名字服务器均使用高速缓存。在标准的 U n i x实 现中,高速缓存是由名字服务器而不是由名字解析器维护的。既然名字解析器作为每个应用 的一部分,而应用又不可能总处于工作状态,因此将高速缓存放在只要系统(名字服务器) 处于工作状态就能起作用的程序中显得很重要。这样任何一个使用名字服务器的应用均可获 得高速缓存。在该站点使用这个名字服务器的任何其他主机也能共享服务器的高速缓存。 在迄今为止(图 1 4 - 9)所举例子的网络环境中,在 s u n主机上运行客户程序,通过主机 n o a o . e d u的S L I P链路访问名字服务器。现在将改变这种设置,在 s u n主机上运行名字服务 器。在这种情况下,如果使用 t c p d u m p监视在S L I P链路上的D N S通信量,将只能看到服务器 因超出其高速缓存而不能处理的查询。 在默认情况下,名字解析器将在本地主机上( U D P端口号为5 3或T C P端口号为5 3)寻找 名字服务器。从名字解析器文件中删除 n a m e s e r v e r行,而留下d o m a i n行: sun % cat /etc/resolv.conf domain tuc.noao.edu 在这个文件中缺少n a m e r s e r v e r指示将导致名字解析器使用本地主机上的名字服务器。使用h o s t命令执行下列查询: sun % host ftp.uu.net f t p . u u . n e t A 1 9 2 . 4 8 . 9 6 . 9 图1 4 - 1 4显示了这个查询的输出结果。 图14-14 执行host ftp.uu.net后的t c p d u m p 输出 这次在t c p d u m p中使用了新的选项。使用- w选项来收集进出U D P或TCP 53号端口 的所有数据。将这些原始数据记录在一个文件中供以后处理,同时防止 t c p d u m p试图 调用名字解析器来显示与那个I P地址相对应的域名。执行查询后,终止 t c p d u m p并使 用- r选项再次运行它。它会读取含有原始数据的文件并产生正式的输出显示(如图 1 4 - 14)。这个过程要花费几秒钟,因为t c p d u m p调用了它自己的名字解析器。 在t c p d u m p输出中要注意的第一点是标识符 ( i d e n t i f i e r )是小整数(2和3)。这是因为我们 关闭这个名字服务器,后又重新启动它来强制清空它的高速缓存。当名字服务器启动时,它 将标识符初始化为1。 当键入查询,查找主机 f t p . u u . n e t的I P地址,该名字服务器就同 8个根名字服务器中的 一个n s . n i c . d d n . m i l(第1行)取得联系。这是以前见到的正常的 A类型查询,但要注意 的是它的期望递归表示没有说明(如果该标志被设置,在标识符 2的后边会跟着一个加号)。 在以前的例子中,经常看到名字解析器设置期望递归标志,但这里的名字服务器在与某个根 服务器联系时没有设置这个标志。这是因为不应该向根名字服务器发出期望递归的查询,它 们仅用来寻找其他授权名字服务器的地址。 第2行显示返回的响应中没有回答资源记录,而包含 5个授权资源记录和5个附加信息资源 记录。标识符2后的减号表示期望递归标志( R A)没有被设置。即使我们要求进行递归查询, 这个根名字服务器也不会回答期望递归查询。 尽管t c p d u m p没有显示返回的1 0个资源记录,我们也能执行h o s t命令来查看高速缓存的内容: 154使用TCP/IP详解,卷1:协议第14章 DNS:域名系统使用155 这次采用- v选项查看的不仅仅只是 A记录。它显示出对于域 u u . n e t有5个授权名字服务 器,而由根名字服务器返回的 5个附加信息资源记录中含有这 5个名字服务器的 I P地址。这避 免了在查找其中的某个名字服务器的地址时,无需再次与根名字服务器联系。这是 D N S中的 另一个实现优化。 h o s t命令指出这个回答不是授权的,这是因为这个回答来自名字服务器的高速缓存,而 不是来自授权名字服务器。 回到图1 4 - 1 4中的第3行,我们的名字服务器与第一个授权名字服务器( n s . u u . n e t)询 问同一个问题: f t p . u u . n e t的I P地址?这次我们的服务器设置了期望递归标志。返回的应 答(第4行)包含一个回答资源记录。 而后我们再次执行h o s t命令,询问相同的名字: sun % host ftp.uu.net ftp.uu.net A 1 9 2 . 4 8 . 9 6 . 9 这时t c p d u m p没有输出,这正是我们所期望的,因为由 h o s t命令返回的回答来自于名字 服务器的高速缓存。 再次执行h o s t命令,查找f t p . e e . l b l . g o v的地址: sun % host ftp.ee.lbl.gov f t p . e e . l b l . g o v CNAME ee.lbl.gov e e . l b l . g o v A 128.3.112.20 图1 4 - 1 5显示了这时的t c p d u m p输出。 图14-15 对f t p . e e . l b l . g o v 主机的t c p d u m p 输出 这时第1行显示我们的服务器与另一个根名字服务器(c . n y s e r . n e t)联系。一个名 字服务器通常轮询不同的根名字服务器来获得往返时间估计,然后选择往返时间最小 的服务器。 既然我们的服务器向一个根服务器发出查询,那么期望递归标志不应被设置。正如我们 在图1 4 - 1 4中所看到的该名字服务器并不清除期望递归标志(即便这样,一个名字服务器还是 不应该向一个根名字服务器发出期望递归的查询)。 在第2行返回的响应中不包含回答资源记录,但含有4个授权记录和4个附加信息资源记录。 正如我们所猜测的那样, 4个授权资源记录是供主机 f t p . e e . l b l . g o v进行域名服务的名字 服务器名,其他4个记录则是这4个服务器的I P地址。 第3行是向名字服务器 n s l . l b l . g o v(第2行中返回的4个名字服务器中的第一个)发出 的查询请求。它的期望递归标志是被设置的。 第4行返回的响应和以往的响应不同。返回了两个回答资源记录, t c p d u m p指出其中的第 一个是C N A M E资源记录。f t p . e e . l b l . g o v的规范名称是e e . l b l . g o v。156使用TCP/IP详解,卷1:协议 这是C N A M E记录常见的用法。L B L的F T P站点的名字通常是以f t p开始的,但它 可能不时地从一个主机移到另一个主机。用户只需要知道f t p . e e . l b l . g o v,必要时 DNS会用它的规范名进行替换。 记得我们在运行 h o s t程序时,它显示了规范域名的 C N A M E和I P地址。这是因为响应 (图1 4 - 1 5中的第4行)中含有两个回答资源记录,第一个是 C N A M E,而第二个是 A记录。如 果A记录没有随C N A M E记录返回,我们的服务器将发出另一个查询请求,询问 e e . l b l . g o v 的I P地址。这是另一个D N S的实现优化— 在一个响应中同时返回一个规范域名的 C N A M E记 录和A记录。 14.8 用UDP还是用TCP 注意到D N S名字服务器使用的熟知端口号无论对 U D P还是T C P都是5 3。这意味着D N S均 支持U D P和T C P访问,但我们使用 t c p d u m p观察的所有例子都是采用 U D P。那么这两种协议 都在什么情况下采用以及采用的理由都是什么呢? 当名字解析器发出一个查询请求,并且返回响应中的 T C(删减标志)比特被设置为 1时, 它就意味着响应的长度超过了 5 1 2个字节,而仅返回前 5 1 2个字节。在遇到这种情况时,名字 解析器通常使用T C P重发原来的查询请求,它将允许返回的响应超过 5 1 2个字节(回想在11 . 1 0 节讨论的U D P数据报的最大长度)。既然T C P能将用户的数据流分为一些报文段,它就能用多 个报文段来传送任意长度的用户数据。 此外,当一个域的辅助名字服务器在启动时,将从该域的主名字服务器执行区域传送。 我们也说过辅助服务器将定时(通常是 3小时)向主服务器进行查询以便了解主服务器数据是 否发生变动。如果有变动,将执行一次区域传送。区域传送将使用 T C P,因为这里传送的数 据远比一个查询或响应多得多。 既然D N S主要使用U D P,无论是名字解析器还是名字服务器都必须自己处理超时和重传。 此外,不像其他的使用 U D P的I n t e r n e t应用(T F T P、B O O T P和S N M P),大部分操作集中在局 域网上,D N S查询和响应通常经过广域网。分组丢失率和往返时间的不确定性在广域网上比 局域网上更大。这样对于D N S客户程序,一个好的重传和超时程序就显得更重要了。 14.9 另一个例子 让我们通过另一个例子将已经介绍的许多 D N S特性作一个综合性回顾。先启动 Rlogin 客 户程序,然后连接到一个位于其他域的 R l o g i n服务器。图1 4 - 1 6显示了发生的分组交换过程。 下面发生的11个步骤都假定客户和服务器的高速缓存中没有任何信息。 1) 客户程序启动后,调用它的名字解析器函数将我们键入的主机名转换为一个 I P地址。 一个A类型的查询请求被送往一个根服务器。 2) 由根服务器返回的响应中包含为该服务器所在域服务的名字服务器名。 3) 客户端的名字解析器将向该服务器的名字服务器重发上述 A类型查询,这个查询通常 是将期望递归标志设置为1。 4) 返回的应答中包含R l o g i n服务器的I P地址。 5) Rlogin客户和R l o g i n服务器建立一个 T C P连接(第1 8章将提供该步骤的细节)。客户和 服务器的T C P模块间将交换3个分组。图14-16 启动Rlogin客户和服务器的分组交换过程 6) Rlogin服务器收到来自客户的连接请求后,调用它的名字解析器通过 T C P连接请求中的 I P地址获得客户主机名。这是一个 P T R查询请求,由一个根名字服务器处理。这个根名字服 务器可以不同于步骤1中客户使用的根名字服务器。 7) 这个根名字服务器的响应中含有为客户的 i n - a d d r . a r p a域的名字服务器。 8) 服务器上的名字解析器将向客户的名字服务器重传上述 P T R查询。 9) 返回的P T R应答中含有客户主机的F Q D N。 10) 服务器的名字解析器向客户的名字服务器发送一个 A类型查询请求,查找前一步返回 的名字对应的I P地址。这可能由服务器中的 g e t h o s t b y a d d r函数自动完成,正如我们在 1 4 . 5 节中介绍的那样,否则 R l o g i n服务器将完成这一步。此外,客户的名字服务器常常就是客户 的i n - a d d r . a r p a名字服务器,但这不是必需的。 11) 从客户的名字服务器返回的响应含有客户主机的 A记录。R l o g i n服务器将客户的 T C P 连接请求中的I P地址与A记录作比较。 高速缓存将减少这个图中交换的分组数目。 14.10 小结 D N S是任何与I n t e r n e t相连主机必不可少的一部分,同时它也广泛用于专用的互联网。层 次树是组成D N S域名空间的基本组织形式。 应用程序通过名字解析器将一个主机名转换为一个 I P地址,也可将一个 I P地址转换为与 之对应的主机名。名字解析器将向一个本地名字服务器发出查询请求,这个名字服务器可能 通过某个根名字服务器或其他名字服务器来完成这个查询。 所有的D N S查询和响应都有相同的报文格式。这个报文格式中包含查询请求和可能的回答资 源记录、授权资源记录和附加资源记录。通过许多例子了解了名字解析器的配置文件以及D N S的 优化措施:指向域名的指针(减少报文的长度)、查询结果的高速缓存、i n - a d d r . a r p a域(查 找I P地址对应的域名)以及返回的附加资源记录(避免主机重发同一查询请求)。 习题 14.1 讨论一个DNS 名字解析器和一个 D N S名字服务器作为客户程序、服务器或同时作为客 第14章 DNS:域名系统使用157 根名字 服务器 根名字 服务器 Rlogin 服务器 服务器的名 字服务器 客户的名 字服务器 R l o g i n 客户户和服务器的情况。 14.2 说明图1 4 - 1 2中构成响应的7 5个字节的含义。 14.3 在1 2 . 3节我们指出,一个既可接受点分十进制形式的 I P地址、也可接收主机名的应用程 序,应先假定输入的是 I P地址,如果失败,再假定是主机名。如果改变这个测试顺序会 出现什么情况? 14.4 每个U D P数据报有一个相应的长度。一个接收 U D P数据报的进程将被告知这个长度。当 名字解析器使用T C P而不是U D P来处理查询请求时,由于 T C P是没有任何记录标记的字 节流,那么应用程序是如何知道有多少数据返回?注意在 D N S的报文首部(图1 4 - 3)中 没有任何长度字段(提示:查阅 RFC 1035) 14.5 我们说一个名字服务器必须知道根名字服务器的 I P地址,这一信息可通过匿名 F T P获得。 不幸的是当根名字服务器表发生变化时,并不是所有的系统管理员都会更新他们的 D N S 配置文件(根名字服务表的确会发生变化,尽管不是经常的)你认为 D N S如何处理这个 问题? 14.6 利用习题1 . 8指明的文件来确定谁应负责维护根名字服务器。名字服务器更新的频度是 怎样的? 14.7 维护一个名字服务器和一个无状态的名字解析器高速缓存的问题分别是什么? 14.8 在图1 4 - 1 0的讨论中,我们指出名字服务器将对 A类型记录进行排序以便在公共网中的地 址先出现。谁对A类型记录进行这种排序,是名字服务器还是名字解析器 ? 158使用TCP/IP详解,卷1:协议第15章 TFTP:简单文件传送协议 15.1 引言 T F T P ( Trivial File Transfer Protocol)即简单文件传送协议,最初打算用于引导无盘系统 (通常是工作站或 X终端)。和将在第2 7章介绍的使用T C P的文件传送协议( F T P)不同,为了 保持简单和短小, T F T P将使用U D P。T F T P的代码(和它所需要的 U D P、I P和设备驱动程序) 都能适合只读存储器。 本章对T F T P只作一般介绍,因为在下一章引导程序协议( Bootstrap Protocol)中还会遇 到T F T P。在图5 - 1中,当从网络上引导 s u n主机时,也曾遇到过 T F T P,s u n主机通过R A R P获 得它的I P地址后,将发出一个T F T P请求。 RFC 1350 [Sollins 1992]是第2版T F T P的正式规范。第 1 2章 [Stevens 1990] 提供了实现 T F T P客户和服务器的全部源代码,并介绍了一些使用 T F T P的编程技术。 15.2 协议 在开始工作时,T F T P的客户与服务器交换信息,客户发送一个读请求或写请求给服务器。 在一个无盘系统进行系统引导的正常情况下,第一个请求是读请求( R R Q)。图1 5 - 1显示了5 种T F T P报文格式(操作码为1和2的报文使用相同的格式)。 T F T P报文的头两个字节表示操作码。对于读请求和写请求( W R Q),文件名字段说明客 户要读或写的位于服务器上的文件。这个文件字段以 0字节作为结束(见图 1 5 - 1)。模式字段 是一个A S C I I码串n e t a s c i i或o c t e t(可大小写任意组合),同样以0字节结束。n e t a s c i i 表示数据是以成行的A S C I I码字符组成,以两个字节— 回车字符后跟换行字符(称为 C R / L F) 作为行结束符。这两个行结束字符在这种格式和本地主机使用的行定界符之间进行转化。 o c t e t则将数据看作8 bit一组的字节流而不作任何解释。 每个数据分组包含一个块编号字段,它以后要在确认分组中使用。以读一个文件作为例 子,T F T P客户需要发送一个读请求说明要读的文件名和文件模式 ( m o d e )。如果这个文件能被 这个客户读取, T F T P服务器就返回一个块编号为 1的数据分组。T F T P客户又发送一个块编号 为1的A C K。T F T P服务器随后发送块编号为 2的数据。T F T P客户发回块编号为2的A C K。重复 这个过程直到这个文件传送完。除了最后一个数据分组可含有不足 5 1 2字节的数据,其他每个 数据分组均含有5 1 2字节的数据。当T F T P客户收到一个不足5 1 2字节的数据分组,就知道它收 到最后一个数据分组。 在写请求的情况下,TFTP 客户发送W R Q指明文件名和模式。如果该文件能被 该客户写, TFTP 服务器就返回块编号为 0的A C K包。该客户就将文件的头 5 1 2字节以块编号为1发出。服 务器则返回块编号为1的A C K。 这种类型的数据传输称为停止等待协议。它只用在一些简单的协议如 T F T P中。在2 0 . 3节 中将看到T C P提供了不同形式的确认,能提供更高的系统吞吐量。 T F T P的优点在于实现的简单而不是高的系统吞吐量。 图15-1 5种TFTP报文格式 最后一种T F T P报文类型是差错报文,它的操作码为 5。它用于服务器不能处理读请求或 写请求的情况。在文件传输过程中的读和写差错也会导致传送这种报文,接着停止传输。差 错编号字段给出一个数字的差错码,跟着是一个 A S C I I表示的差错报文字段,可能包含额外的 操作系统说明的信息。 既然T F T P使用不可靠的U D P,T F T P就必须处理分组丢失和分组重复。分组丢失可通过发 送方的超时与重传机制解决(注意存在一种称为“魔术新手综合症 ( s o r c e r e r’s apprentice s y n d r o m e )”的潜在问题,如果双方都超时与重传,就可能出现这个问题。 12.2 节 [ S t e v e n s 1990] 介绍了这个问题是如何发生的 )。和许多U D P应用程序一样,T F T P报文中没有检验和, 它假定任何数据差错都将被 U D P的检验和检测到(参见11 . 3节)。 15.3 一个例子 让我们通过观察协议的工作情况来了解 T F T P。在b s d i主机上运行TFTP 客户程序,并从 主机s v r 4读取一个文本文件: 最先引起我们注意的是在 U n i x系统下接收的文件长度是 9 1 4字节,而T F T P则传送了9 6 2个 字节。使用w c程序我们看到文件共有 4 8行,因此4 8个U n i x的换行符被转化成 4 8个C R / C F对, 160使用TCP/IP详解,卷1:协议 IP数据报 IP首部 UDP首部 2字节 文件名 模式 N字节N字节 块编号 块编号 差错码 差错信息 操作码 ( 3 = d a t a) 操作码 ( 4 = A C K) 操作码 ( 5 = e r r o r) 20字节 8字节 2字节 2字节 2字节 2字节 2字节 2字节 N字节 数 据 0-512字节 操作码 (1=RRQ) (2=WRQ) UDP报文 TFTP数据报 启动TFTP客户进程 从服务器读取文件 结束 查看我们读取的文件大小 文件行数?因为默认情况下T F T P使用n e t a s c i i模式传送。 图1 5 - 2显示了发生的分组交换过程。 图15-2 使用TFTP传输一个文件的分组交换过程 第1行显示了客户向服务器发送的读请求。由于目的 U D P端口是T F T P熟知端口( 6 9), t c p d u m p将解释T F T P分组,并显示 R R Q和文件名。1 9字节的U D P数据包括2字节的操作码, 7字节的的文件名,1字节的0,8字节的n e t a s c i i模式以及另1字节的0结束。 下一个分组由服务器发回(第 2行),共包含5 1 6字节:2字节的操作码,2字节的数据块号 和5 1 2字节的数据。第3行是这个数据块的确认,它包括 2字节的操作码和2字节的数据块号。 最后的数据分组(第4行)包含4 5 0字节的数据。这4 5 0字节的数据加上第2行的5 1 2字节的 数据就是向该客户传送的9 6 2字节的数据。注意t c p d u m p仅在第1行解释T F T P报文,而在2~5 行都不显示任何 T F T P协议信息。这是因为服务器进程的端口在第 1行和第2行发生了变化。 T F T P协议需要客户进程向服务器进程的 U D P熟知端口(6 9)发送第一个分组(R R Q或W R Q)。 之后服务器进程便向服务器主机申请一个尚未使用的端口( 1 0 7 7,见图1 5 - 2),服务器进程使 用这个端口来进行请求客户进程与服务器进程间的其他数据交换。客户进程的端口号(在这 个例子中为11 0 6)没有变化。t c p d u m p无法知道主机s r v 4上的1 0 7 7端口是一个T F T P服务器进 程。 服务器进程端口变化的原因是服务器进程不能占用这个熟知端口来完成需一些时间的文 件传输(可能是几十秒甚至数分钟)。相反,在传输当前文件的过程中,这个熟知端口要留出 来供其他的T F T P客户进程发送它们的请求。 回顾图1 0 - 6,当R I P服务器向客户发送的数据超过 5 1 2字节,两个U D P数据报都使用服务 器的熟知端口。在那个例子中,即使服务器进程必须写多个数据报以便将所有数据发回,服 务器进程也是先写一个,再写一个,它们都使用它的熟知端口。然而, T F T P协议与它不同, 因为客户与服务器间的连接需要持续一个较长的时间(可能是数秒或数分钟)。如果一个服务 器进程使用熟知端口来进行文件传输,那么在文件传输期间,它要么拒绝任何来自其他客户 的请求,要么一个服务器进程在同一端口( 6 9)同时对多个客户进程进行多个文件传输。最 简单的办法是让服务器进程在收到 R R Q或W R Q后,改用新的端口。当然,客户进程在收到第 一个数据分组(图 1 5 - 2的第2行)后必须探测到这个新的端口,并将之后的所有确认(第 3行 和第5行)发送到那个新的端口。 在1 6 . 3节我们将看到当X终端在进行系统引导时将使用 T F T P。 15.4 安全性 注意在T F T P分组(图1 5 - 1)中并不提供用户名和口令。这是 T F T P的一个特征(即“安全 漏洞”)。由于T F T P是设计用于系统引导进程,它不可能提供用户名和口令。 T F T P的这一特性被许多解密高手用于获取 U n i x口令文件的复制,然后来猜测用户口令。 第15章 TFTP:简单文件传送协议使用161为防止这种类型的访问,目前大多数 T F T P服务器提供了一个选项来限制只能访问特定目录下 的文件(U n i x系统中通常是/ t f t p b o o t)。这个目录中只包含无盘系统进行系统引导时所需 的文件。 对其他的安全性,U n i x系统下的T F T P服务器通常将它的用户 I D和组I D设置为不会赋给任 何真正用户的值。这只允许访问具有读或写属性的文件。 15.5 小结 T F T P是一个简单的协议,适合于只读存储器,仅用于无盘系统进行系统引导。它只使用 几种报文格式,是一种停止等待协议。 为了允许多个客户端同时进行系统引导, T F T P服务器必须提供一定形式的并发。因为 U D P在一个客户与一个服务器之间并不提供唯一连接( T C P也一样),T F T P服务器通过为每 个客户提供一个新的 U D P端口来提供并发。这允许不同的客户输入数据报,然后由服务器中 的U D P模块根据目的端口号进行区分,而不是由服务器本身来进行区分。 T F T P协议没有提供安全特性。大多数执行指望 T F T P服务器的系统管理员来限制客户的访 问,只允许它们访问引导所必须的文件。 第2 7章介绍的文件传输协议(F T P)是设计用于一般目的的、高吞吐量的文件传输。 习题 15.1 阅读Host Requirements RFC,了解如果一个TFTP 服务器收到的请求的目的 I P地址是一 个广播地址,它将做什么。 15.2 当T F T P块号由6 5 5 3 5跳回到0时,你认为会发生什么? RFC 1350提到了如何处理这一问 题吗? 15.3 T F T P发送方采用超时重发来处理分组丢失。当 T F T P作为引导进程的一部分时,这种方 法对T F T P的使用有何影响? 15.4 使用T F T P时,影响传输文件所需时间的限制性因素是什么? 162使用TCP/IP详解,卷1:协议第16章 BOOTP:引导程序协议 16.1 引言 在第5章我们介绍了一个无盘系统,它在不知道自身 I P地址的情况下,在进行系统引导时 能够通过R A R P来获取它的I P地址。然而使用 R A R P有两个问题:(1)I P地址是返回的唯一结 果;(2)既然R A R P使用链路层广播, R A R P请求就不会被路由器转发(迫使每个实际网络 设置一个RARP 服务器)。本章将介绍一种用于无盘系统进行系统引导的替代方法,又称为引 导程序协议,或B O O T P。 B O O T P使用 U D P,且通常需与 T F T P(参见第 1 5章)协同工作。 RFC 951 [Croft and Gilmore 1985]是B O O T P的正式规范,RFC 1542 [Wimer 1993]则对它作了说明。 16.2 BOOTP 的分组格式 BOOTP 请求和应答均被封装在U D P数据报中,如图1 6 - 1所示。 图16-1 BOOTP 请求和应答封装在一个UDP数据报内 图1 6 - 2显示了长度为3 0 0字节的B O O T P请求和应答的格式。 “操作码”字段为1表示请求,为2表示应答。硬件类型字段为 1表示10 Mb/s的以太网,这 和A R P请求或应答(图4 - 3)中同名字段表示的含义相同。类似地,对于以太网,硬件地址长 度字段为6字节。 “跳数”字段由客户设置为 0,但也能被一个代理服务器设置(参见 1 6 . 5节)。 “事务标识”字段是一个由客户设置并由服务器返回的 32 bit整数。客户用它对请求和应 答进行匹配。对每个请求,客户应该将该字段设置为一个随机数。 客户开始进行引导时,将“秒数”字段设置为一个时间值。服务器能够看到这个时间值, 备用服务器在等待时间超过这个时间值后才会响应客户的请求,这意味着主服务器没有启动。 如果该客户已经知道自身的 I P地址,它将写入“客户 I P地址”字段。否则,它将该字段 设置为0。对于后面这种情况,服务器用该客户的 I P地址写入“你的 I P地址”字段。“服务器 I P地址”字段则由服务器填写。如果使用了某个代理服务器(见 1 6 . 5节),则该代理服务器就 填写“网关I P地址”字段。 客户必须设置它的“客户硬件地址”字段。尽管这个值与以太网数据帧头中的值相同, U D P数据报中也设置这个字段,但任何接收这个数据报的用户进程能很容易地获得它(例如 IP数据报 UDP数据报 IP首部 UDP首部 BOOTP请求/应答 20字节 8字节 300字节一个BOOTP 服务器)。一个进程通过查看 U D P数据报来确定以太网帧首部中的该字段通常是 很困难的(或者说是不可能的)。 图16-2 BOOTP请求和应答的格式 “服务器主机名”字段是一个空值终止串,由服务器填写。服务器还将在“引导文件名字 段”填入包括用于系统引导的文件名及其所在位置的路径全名。 “特定厂商区域”字段用于对 B O O T P进行不同的扩展。1 6 . 6节将介绍这些扩展中的一些。 当一个客户使用 B O O T P(操作码为 1)进行系统引导时,引导请求通常是采用链路层广 播, I P首部中的目的 I P地址为 2 5 5 . 2 5 5 . 2 5 5 . 2 5 5(受限的广播, 1 2 . 2节)。源 I P地址通常是 0 . 0 . 0 . 0,因为此时客户还不知道它本身的 I P地址。回顾图3 - 9,在系统进行自引导时, 0 . 0 . 0 . 0 是一个有效的I P地址。 端口号 B O O T P有两个熟知端口: BOOTP 服务器为6 7,BOOTP 客户为6 8。这意味着BOOTP 客 户不会选择未用的临时端口,而只用端口 6 8。选择两个端口而不是仅选择一个端口为 B O O T P 服务器用的原因是:服务器的应答可以进行广播(但通常是不用广播的)。 如果服务器的应答是通过广播传送的,同时客户又选择未用的临时端口,那么这些广播 164使用TCP/IP详解,卷1:协议 操作码 (1=请求,2=应答) 硬件类型 (1=以太网) 硬件地址长度 (以太网为6) 跳数 事务标识 秒数 未使用 300字节 客户IP地址 你的IP地址 服务器IP地址 网关IP地址 客户主机硬件地址(16字节) 服务器主机名(64字节) 特定厂商信息(64字节) 引导文件名(128字节)也能被其他的主机中碰巧使用相同临时端口的应用进程接收到。因此,采用随机端口(即临 时端口)对广播来说是一个不好的选择。 如果客户也使用服务器的知名端口( 6 7)作为它的端口,那么网络内的所有服务器会被 唤醒来查看每个广播应答(如果所有的服务器都被唤醒,它们将检查操作码,如果是一个应 答而不是请求,就不作处理)。因此可以让所有的客户使用与服务器知名端口不同的同一知名 端口。 如果多个客户同时进行系统引导,并且服务器广播所有应答,这样每个客户都会收到其 他客户的应答。客户可以通过 B O O T P首部中的事务标识字段来确认应答是否与请求匹配,或 者可以通过检查返回的客户硬件地址加以区分。 16.3 一个例子 让我们看一个用 B O O T P引导一个X终端的例子。图1 6 - 3显示了t c p d u m p的输出结果(例 中客户名为p r o t e u s,服务器名为m e r c u r y。这个t c p d u m p的输出是在不同的网络上获得 的,这个应用程序是其他例子中一直使用的)。 图16-3 用BOOTP引导一个X终端的例子 在第1行中,我们看到客户请求来自 0 . 0 . 0 . 0 . 6 8,发送目的站是 2 5 5 . 2 5 5 . 2 5 5 . 2 5 5 . 6 7。该客 户已经填写的字段是秒数和自身的以太网地址。我们看到客户通常将秒数设置为 1 0 0。 t c p d u m p没有显示跳数和事务标识,因为它们均为 0 (事务标识为 0表示该客户忽略这个字段, 第16章 BOOTP:引导程序协议使用165 这里删除了许多行因为如果打算对返回响应进行验证,它将把这个字段设置为一个随机数值 )。 第2行是服务器返回的应答。由服务器填写的字段是该客户的 I P地址(t c p d u m p显示为名 字p r o t e u s)、服务器的 I P地址(显示为名字 m e r c u r y)、网关的 I P地址(显示为名字 m e r c u r y)和引导文件名。 在收到B O O T P应答后,该客户立即发送一个A R P请求来了解网络中其他主机是否有I P地址。 跟在w h o - h a s后的名字p r o t e u s对应目的I P地址(图4 - 3),发送者的I P地址被设置为0 . 0 . 0 . 0。 它在0 . 5秒后再发一个相同的A R P请求,之后再过0 . 5秒又发一个。在第3个A R P请求(第5行)中, 它将发送者的I P地址改变为它自己的I P地址。这是一个没有意义的A R P请求(见4 . 7节)。 第6行显示该客户在等待另一个 0 . 5秒后,广播另一个B O O T P请求。这个请求与第1行的唯 一不同是此时客户将它的I P地址写入I P首部中。它收到来自同一个服务器的相同应答(第7行)。 该客户在等待 2秒后,又广播一个 B O O T P请求(第8行),同样收到来自同一服务器的相同应 答。 该客户等待2秒后,向它的服务器 m e r c u r y发送一个A R P请求(第1 0行)。收到这个A R P 应答后,它立即发送一个 T F T P读请求,请求读取它的引导文件(第 1 2行)。文件传送过程包 括2 4 6 4个T F T P数据分组和确认,传送的数据量为 5 1 2×2463 + 224 = 1 261 280字节。这将操 作系统调入X终端。我们已在图1 6 - 3中删除了大多数T F T P行。 当和图1 5 - 2比较T F T P的数据交换过程时,要注意的是这儿的客户在整个传输过程中使用 T F T P的知名端口(6 9)。既然通信双方中的一方使用了端口 6 9,t c p d u m p就知道这些分组是 T F T P报文,因此它能用T F T P协议来解释每个分组。这就是为什么图 1 6 - 3能指明哪些包含有数 据,哪些包含有确认,以及每个分组的块编号。在图 1 5 - 2中我们并不能获得这些额外的信息, 因为通信双方均没有使用 T F T P的知名端口进行数据传送。由于 TFTP 服务器作为一个多用户 系统,且使用T F T P的知名端口,因此通常T F T P客户不能使用那个端口。但这里的系统处于正 被引导的过程中,无法提供一个 T F T P服务器,因此允许该客户在传输期间使用 T F T P的知名端 口。这也暗示在m e r c u r y上的T F T P服务器并不关心客户的端口号是什么— 它只将数据传送 到客户的端口上,而不管发生了什么。 从图1 6 - 3可以看出在9秒内共传送了1 261 280字节。数据速率大约为140 000 bps。这比大 多数以F T P文件传送形式访问一个以太网要慢,但对于一个简单的停止等待协议如 T F T P来说 已经很好了。 X终端系统引导后,还需使用 T F T P传送终端的字体文件、某些 D N S名字服务器查询,然 后进行X协议的初始化。图 1 6 - 3中的所有步骤大概需要 1 5秒钟,其余的步骤需要 6秒钟,这样 无盘X终端系统引导的总时间是2 1秒。 16.4 BOOTP服务器的设计 B O O T P客户通常固化在无盘系统只读存储器中,因此了解 BOOTP 服务器的实现将更有 意义。 首先,BOOTP 服务器将从它的熟知端口( 6 7)读取U D P数据报。这没有特别的地方。它 不同于RARP 服务器 (5 . 4节),它必须读取类型字段为“ R A R P请求”的以太网帧。 B O O T P 协议通过将客户的硬件地址放入 B O O T P分组中,使得服务器很容易获取客户的硬件地址 (图 1 6 - 2 )。 166使用TCP/IP详解,卷1:协议这里出现了一个有趣的问题: TFTP 服务器如何能将一个响应直接送回 BOOTP 客户?这 个响应是一个 U D P数据报,而服务器知道该客户的 I P地址(可能通过读取服务器上的配置文 件)。但如果这个客户向那个 I P地址发送一个 U D P数据报(正常情况下会处理 U D P的输出), BOOTP 服务器的主机就可能向那个 I P地址发送一个A R P请求。但这个客户不能响应这个 A R P 请求,因为它还不知道它自己的 I P地址!(这就是在R F C 9 5 1中被称作“鸡和蛋”的问题。) 有两种解决办法:第一种,通常被 Unix 服务器采用,是服务器发一个 i o c t l ( 2 )请求给内核, 为该客户在A R P高速缓存中设置一个条目(这就是命令 a r p - s所做的工作,见 4 . 8节)。服务 器能一直这么做直到它知道客户的硬件地址和 I P地址。这意味着当服务器发送 U D P数据报 (即B O O T P应答)时,服务器的A R P将在ARP 高速缓存中找到该客户的I P地址。 另一种可选的解决办法是服务器广播这个 B O O T P应答而不直接将应答发回该客户。既然 通常期望网络广播越少越好,因此这种解决方案应该只在服务器无法在它的 ARP 高速缓存设 置一个条目的情况下使用。通常只有拥有超级用户权限才能在 A R P高速缓存设置一个条目, 如果没有这种权限就只能广播 B O O T P应答。 16.5 BOOTP穿越路由器 我们在5 . 4节中提到R A R P的一个缺点就是它使用链路层广播,这种广播通常不会由路由 器转发。这就需要在每个物理网络内设置一个 RARP 服务器。如果路由器支持 B O O T P协议, 那么B O O T P能够由路由器转发(绝大多数路由器厂商的产品都支持这个功能)。 这个功能主要用于无盘路由器,因为如果在磁盘的多用户系统被用作路由器,它就能够 自己运行 BOOTP 服务器。此外,常用的 Unix BOOTP服务器(附录 F)支持这种中继模式 (relay mode)。但如果在这个物理网络内运行一个 BOOTP 服务器,通常没有必要将B O O T P请 求转发到在另外网络中的另一个服务器。 研究一下当路由器(也称作“ BOOTP 中继代理”)在服务器的熟知端口( 6 7)接收到 B O O T P请求时将会发生什么。当收到一个 B O O T P请求时,中继代理将它的 I P地址填入收到 B O O T P请求中的“网关 I P地址字段”,然后将该请求发送到真正的 B O O T P服务器(由中继代 理填入网关字段的地址是收到的 B O O T P请求接口的I P地址)。该代理中继还将跳数字段值加 1 (这是为防止请求被无限地在网络内转发。 RFC 951认为如果跳数值到达3就可以丢弃该请求)。 既然发出的请求是一个单播的数据报(与发起的客户的请求是广播的相反),它能按照一定的 路由通过其他的路由器到达真正的 B O O T P服务器。真正的B O O T P服务器收到这个请求后,产 生B O O T P应答,并将它发回中继代理,而不是请求的客户。既然请求网关字段不为零,真正 的B O O T P服务器知道这个请求是经过转发的。中继代理收到应答后将它发给请求的客户。 16.6 特定厂商信息 在图1 6 - 2中我们看到了 6 4字节的“特定厂商区域”。RFC 1533 [Alexander and Droms 1993] 定义了这个区域的格式。这个区域含有服务器返回客户的可选信息。 如果有信息要提供,这个区域的前 4个字节被设置为 I P地址9 9 . 1 3 0 . 8 3 . 9 9。这可称作魔术 甜饼(magic cookie),表示该区域内包含信息。 这个区域的其余部分是一个条目表。每个条目的开始是 1字节标志字段。其中的两个条目 仅有标志字段:标志为 0的条目作为填充字节(为使后面的条目有更好的字节边界),标志为 第16章 BOOTP:引导程序协议使用1672 5 5的条目表示结尾条目。第一个结尾条目后剩余的字节都应设置为这个数值( 2 5 5)。 除了这两个1字节的条目,其他的条目还包含一个单字节的长度字段,后面是相应的信息。 图1 6 - 4显示了厂商说明区域中一些条目的格式。 图16-4 厂商说明区域中一些条目的格式 子网掩码条目和时间值条目都是定长条目,因为它们的值总是占 4个字节。时间偏移值是 从1 9 0 0年1月1日0时以来的秒数(U T C)。 网关条目是变长条目。长度通常是 4 的倍数,这个值是一个或多个供客户使用的网关(路 由器)的I P地址。返回的第一个必须是首选的网关。 RFC 1533还定义了其他 1 4个条目。其中最重要的可能是 D N S名字服务器的 I P地址条目, 条目的志为6。其他的条目包括打印服务器、时间服务器等的 I P地址。详细情况可参考 R F C文 档。 回到在图1 6 - 3中的例子,我们从未看到客户广播一个 I C M P地址掩码请求(6 . 3节)来获取 它的子网掩码。尽管t c p d u m p不能显示出来,但我们可认为客户所在网络的子网掩码在返回的 B O O T P应答的厂商说明区域内。 Host Requirements RFC文档推荐一个系统使用B O O T P来获悉它的子网掩码,而不是采用 I C M P。 厂商说明区域的大小被限制为 6 4字节。这对某些应用是个约束。一个新的称为动态主机 配置协议D H C P(Dynamic Host Configuration Protocol)已经出现,但它不是替代 B O O T P的。 D H C P将这个区域的长度扩展到3 1 2字节,它在RFC 1541 [Droms 1993] 中定义。 16.7 小结 B O O T P使用U D P,它为引导无盘系统获得它的 I P地址提供了除R A R P外的另外一种选择。 168使用TCP/IP详解,卷1:协议 1字节 填充: 子网掩码: 时间偏移: 网关: 结尾: 1字节 1字节 1字节 1字节 1字节 4字节 1字节 1字节 4字节 4字节 4字节 N字节 tag=1 tag=2 tag=3 len=4 len=4 len=N 子网掩码 时间 首选网关的IP地址 14个其他条目:tag=4~17 网关IP地址B O O T P还能返回其他的信息,如路由器的 I P地址、客户的子网掩码和名字服务器的 I P地址。 既然B O O T P用于系统引导过程,一个无盘系统需要下列协议才能在只读存储器中完成: B O O T P、T F T P、U D P、I P和一个局域网的驱动程序。 B O O T P服务器比R A R P服务器更易于实现,因为 B O O T P请求和应答是在 U D P数据报中, 而不是特殊的数据链路层帧。一个路由器还能作为真正 B O O T P服务器的代理,向位于不同网 络的真正B O O T P服务器转发客户的B O O T P请求。 习题 16.1 我们说B O O T P优于R A R P的一个方面是B O O T P能穿越路由器,而R A R P由于使用链路层 广播则不能。在1 6 . 5节为使B O O T P穿越路由器,我们必须定义特殊的方式。如果在路由 器中增加允许转发R A R P请求的功能会发生什么? 16.2 我们说过,当有多个客户程序同时向一个服务器发出引导请求时,因为服务器要广播多 个B O O T P应答,BOOTP 客户就必须使用事务标识来使响应与请求相匹配。但在图 1 6 - 3 中,事务标识为 0,表示这个客户不考虑事务标识。你认为这个客户将如何将这些响应 与其请求匹配。 第16章 BOOTP:引导程序协议使用169第17章 TCP:传输控制协议 17.1 引言 本章将介绍T C P为应用层提供的服务,以及 T C P首部中的各个字段。随后的几章我们在了 解T C P的工作过程中将对这些字段作详细介绍。 对T C P的介绍将由本章开始,并一直包括随后的 7章。第1 8章描述如何建立和终止一个 T C P连接,第1 9和第2 0章将了解正常的数据传输过程,包括交互使用(远程登录)和批量数 据传送(文件传输)。第2 1章提供T C P超时及重传的技术细节,第 2 2和第2 3章将介绍两种其他 的定时器。最后,第2 4章概述T C P新的特性以及T C P的性能。 17.2 TCP的服务 尽管T C P和U D P都使用相同的网络层(I P),T C P却向应用层提供与U D P完全不同的服务。 T C P提供一种面向连接的、可靠的字节流服务。 面向连接意味着两个使用 T C P的应用(通常是一个客户和一个服务器)在彼此交换数据 之前必须先建立一个 T C P连接。这一过程与打电话很相似,先拨号振铃,等待对方摘机说 “喂”,然后才说明是谁。在第 1 8章我们将看到一个 T C P连接是如何建立的,以及当一方通信 结束后如何断开连接。 在一个T C P连接中,仅有两方进行彼此通信。在第 1 2章介绍的广播和多播不能用于 T C P。 T C P通过下列方式来提供可靠性: • 应用数据被分割成 T C P认为最适合发送的数据块。这和 U D P完全不同,应用程序产生的 数据报长度将保持不变。由 T C P传递给I P的信息单位称为报文段或段( s e g m e n t)(参见 图1 - 7)。在1 8 . 4节我们将看到T C P如何确定报文段的长度。 • 当T C P发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能 及时收到一个确认,将重发这个报文段。在第 2 1章我们将了解T C P协议中自适应的超时 及重传策略。 • 当T C P收到发自T C P连接另一端的数据,它将发送一个确认。这个确认不是立即发送, 通常将推迟几分之一秒,这将在 1 9 . 3节讨论。 • T C P将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输 过程中的任何变化。如果收到段的检验和有差错, T C P将丢弃这个报文段和不确认收到 此报文段(希望发端超时并重发)。 • 既然T C P报文段作为I P数据报来传输,而 I P数据报的到达可能会失序,因此 T C P报文段 的到达也可能会失序。如果必要, T C P将对收到的数据进行重新排序,将收到的数据以 正确的顺序交给应用层。 • 既然I P数据报会发生重复,T C P的接收端必须丢弃重复的数据。 • T C P还能提供流量控制。 T C P连接的每一方都有固定大小的缓冲空间。 T C P的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲 区溢出。 两个应用程序通过T C P连接交换8 bit字节构成的字节流。T C P不在字节流中插入记录标识 符。我们将这称为字节流服务( byte stream service)。如果一方的应用程序先传 1 0字节,又传 2 0字节,再传5 0字节,连接的另一方将无法了解发方每次发送了多少字节。收方可以分 4次接 收这8 0个字节,每次接收 2 0字节。一端将字节流放到 T C P连接上,同样的字节流将出现在 T C P连接的另一端。 另外,T C P对字节流的内容不作任何解释。 T C P不知道传输的数据字节流是二进制数据, 还是A S C I I字符、E B C D I C字符或者其他类型数据。对字节流的解释由 T C P连接双方的应用层 解释。 这种对字节流的处理方式与U n i x操作系统对文件的处理方式很相似。 U n i x的内核 对一个应用读或写的内容不作任何解释,而是交给应用程序处理。对U n i x的内核来说, 它无法区分一个二进制文件与一个文本文件。 17.3 TCP的首部 T C P数据被封装在一个I P数据报中,如图1 7 - 1所示。 图17-1 TCP数据在IP数据报中的封装 图1 7 - 2显示T C P首部的数据格式。如果不计任选字段,它通常是 2 0个字节。 图17-2 TCP包首部 第17章 TCP:传输控制协议使用171 IP数据报 TCP报文段 IP首部 20字节 20字节 TCP首部 TCP数据 16位源端口号 16位目的端口号 32位序号 32位确认序号 16位窗口大小 16位紧急指针16位检验和 保留(6位) 选项 数据 4位首部 长度每个T C P段都包含源端和目的端的端口号,用于寻找发端和收端应用进程。这两个值加 上I P首部中的源端I P地址和目的端I P地址唯一确定一个T C P连接。 有时,一个I P地址和一个端口号也称为一个插口( s o c k e t)。这个术语出现在最早的 T C P 规范(R F C 7 9 3)中,后来它也作为表示伯克利版的编程接口(参见 1 . 1 5节)。插口对(s o c k e t p a i r)(包含客户I P地址、客户端口号、服务器 I P地址和服务器端口号的四元组 )可唯一确定互 联网络中每个T C P连接的双方。 序号用来标识从T C P发端向T C P收端发送的数据字节流,它表示在这个报文段中的的第一 个数据字节。如果将字节流看作在两个应用程序间的单向流动,则 T C P用序号对每个字节进 行计数。序号是32 bit的无符号数,序号到达23 2-1后又从0开始。 当建立一个新的连接时, S Y N标志变1。序号字段包含由这个主机选择的该连接的初始序 号I S N(Initial Sequence Number)。该主机要发送数据的第一个字节序号为这个 I S N加1,因为 S Y N标志消耗了一个序号(将在下章详细介绍如何建立和终止连接,届时我们将看到 F I N标志 也要占用一个序号)。 既然每个传输的字节都被计数,确认序号包含发送确认的一端所期望收到的下一个序号。 因此,确认序号应当是上次已成功收到数据字节序号加 1。只有A C K标志(下面介绍)为 1时 确认序号字段才有效。 发送A C K无需任何代价,因为 32 bit的确认序号字段和A C K标志一样,总是T C P首部的一 部分。因此,我们看到一旦一个连接建立起来,这个字段总是被设置, A C K标志也总是被设 置为1。 T C P为应用层提供全双工服务。这意味数据能在两个方向上独立地进行传输。因此,连 接的每一端必须保持每个方向上的传输数据序号。 T C P可以表述为一个没有选择确认或否认的滑动窗口协议(滑动窗口协议用于数据传输 将在2 0 . 3节介绍)。我们说T C P缺少选择确认是因为 T C P首部中的确认序号表示发方已成功收 到字节,但还不包含确认序号所指的字节。当前还无法对数据流中选定的部分进行确认。例 如,如果1~1 0 2 4字节已经成功收到,下一报文段中包含序号从 2 0 4 9~3 0 7 2的字节,收端并不 能确认这个新的报文段。它所能做的就是发回一个确认序号为 1 0 2 5的A C K。它也无法对一个 报文段进行否认。例如,如果收到包含 1 0 2 5~2 0 4 8字节的报文段,但它的检验和错, T C P接 收端所能做的就是发回一个确认序号为 1 0 2 5的A C K。在2 1 . 7节我们将看到重复的确认如何帮 助确定分组已经丢失。 首部长度给出首部中 32 bit字的数目。需要这个值是因为任选字段的长度是可变的。这个 字段占4 bit,因此T C P最多有6 0字节的首部。然而,没有任选字段,正常的长度是 2 0字节。 在T C P首部中有6个标志比特。它们中的多个可同时被设置为 1。我们在这儿简单介绍它 们的用法,在随后的章节中有更详细的介绍。 U R G 紧急指针(u rgent pointer)有效(见2 0 . 8节)。 A C K 确认序号有效。 P S H 接收方应该尽快将这个报文段交给应用层。 R S T 重建连接。 S Y N 同步序号用来发起一个连接。这个标志和下一个标志将在第 1 8章介绍。 F I N 发端完成发送任务。 172使用TCP/IP详解,卷1:协议T C P的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始 于确认序号字段指明的值,这个值是接收端正期望接收的字节。窗口大小是一个 16 bit字段, 因而窗口大小最大为 6 5 5 3 5字节。在2 4 . 4节我们将看到新的窗口刻度选项,它允许这个值按比 例变化以提供更大的窗口。 检验和覆盖了整个的T C P报文段:T C P首部和T C P数据。这是一个强制性的字段,一定是 由发端计算和存储,并由收端进行验证。 T C P检验和的计算和 U D P检验和的计算相似,使用 如11 . 3节所述的一个伪首部。 只有当U R G标志置1时紧急指针才有效。紧急指针是一个正的偏移量,和序号字段中的值 相加表示紧急数据最后一个字节的序号。 T C P的紧急方式是发送端向另一端发送紧急数据的 一种方式。我们将在2 0 . 8节介绍它。 最常见的可选字段是最长报文大小,又称为 MSS (Maximum Segment Size)。每个连接方 通常都在通信的第一个报文段(为建立连接而设置 S Y N标志的那个段)中指明这个选项。它 指明本端所能接收的最大长度的报文段。我们将在 1 8 . 4节更详细地介绍M S S选项,T C P的其他 选项中的一些将在第2 4章中介绍。 从图1 7 - 2中我们注意到T C P报文段中的数据部分是可选的。我们将在 1 8章中看到在一个连 接建立和一个连接终止时,双方交换的报文段仅有 T C P首部。如果一方没有数据要发送,也 使用没有任何数据的首部来确认收到的数据。在处理超时的许多情况中,也会发送不带任何 数据的报文段。 17.4 小结 T C P提供了一种可靠的面向连接的字节流运输层服务。我们简单地介绍了 T C P首部中的各 个字段,并在随后的几章里详细讨论它们。 T C P将用户数据打包构成报文段;它发送数据后启动一个定时器;另一端对收到的数据 进行确认,对失序的数据重新排序,丢弃重复数据; T C P提供端到端的流量控制,并计算和 验证一个强制性的端到端检验和。 许多流行的应用程序如Te l n e t、R l o g i n、F T P和S M T P都使用T C P。 习题 17.1 我们已经介绍了以下几种分组格式: I P、I C M P、I G M P、U D P和T C P。每一种格式的首 部中均包含一个检验和。对每种分组,说明检验和包括 I P数据报中的哪些部分,以及该 检验和是强制的还是可选的。 17.2 为什么我们已经讨论的所有 I n t e r n e t协议(I P, ICMP, IGMP, UDP, TCP)收到有检验和错 的分组都仅作丢弃处理? 17.3 T C P提供了一种字节流服务,而收发双方都不保持记录的边界。应用程序如何提供它们 自己的记录标识? 17.4 为什么在T C P首部的开始便是源和目的的端口号? 17.5 为什么T C P首部有一个首部长度字段而 U D P首部(图11 - 2)中却没有? 第17章 TCP:传输控制协议使用173第18章 TCP连接的建立与终止 18.1 引言 T C P是一个面向连接的协议。无论哪一方向另一方发送数据之前,都必须先在双方之间 建立一条连接。本章将详细讨论一个 T C P连接是如何建立的以及通信结束后是如何终止的。 这种两端间连接的建立与无连接协议如 U D P不同。我们在第 11章看到一端使用 U D P向另 一端发送数据报时,无需任何预先的握手。 18.2 连接的建立与终止 为了了解一个T C P连接在建立及终止时发生了什么,我们在系统 s v r 4上键入下列命令: t e l n e t命令在与丢弃 ( d i s c a r d )服务(参见1 . 1 2节)对应的端口上与主机 b s d i建立一条 T C P连接。这服务类型正是我们需要观察的一条连接建立与终止的服务类型,而不需要服务 器发起任何数据交换。 18.2.1 t c p d u m p的输出 图1 8 - 1显示了这条命令产生T C P报文段的t c p d u m p输出。 图18-1 TCP连接建立与终止的t c p d u m p 输出显示 这7个T C P报文段仅包含T C P首部。没有任何数据。 对于T C P段,每个输出行开始按如下格式显示: 键入Ctrl和右括号,使Telnet客户进程终止连接源 > 目的: 标志 这里的标志代表 T C P首部(图1 7 - 2)中6个标志比特中的4个。图1 8 - 2显示了表示标志的 5 个字符的含义。 图18-2 t c p d u m p 对TCP首部中部分标志比特的字符表示 在这个例子中,我们看到了 S、F和句点“.”标志符。我们将在以后看到其他的两个标志( R 和P)。T C P首部中的其他两个标志比特— ACK 和 U R G— t c p d u m p将作特殊显示。 图1 8 - 2所示的4个标志比特中的多个可能同时出现在一个报文段中,但通常一次只见到一个。 RFC 1025 [Postel 1987], “TCP and IP Bake Off”,将一种报文段称为K a m i k a z e分组 , 在这样的报文段中有最大数量的标志比特同时被置为1(SYN, URG, PSH, FIN和1字节的 数据)。这样的报文段也叫作nastygram, 圣诞树分组,灯测试报文段(lamp test segment)。 在第1行中,字段1 4 1 5 5 3 1 5 2 1 : 1 4 1 5 5 3 1 5 2 1 ( 0 )表示分组的序号是1 4 1 5 5 3 1 5 2 1,而报文段中 数据字节数为 0。t c p d u m p显示这个字段的格式是开始的序号、一个冒号、隐含的结尾序号 及圆括号内的数据字节数。显示序号和隐含结尾序号的优点是便于了解数据字节数大于 0时的 隐含结尾序号。这个字段只有在满足条件( 1)报文段中至少包含一个数据字节;或者( 2) S Y N、F I N或R S T被设置为1时才显示。图1 8 - 1中的第1、2、4和6行是因为标志比特被置为 1而 显示这个字段的,在这个例子中通信双方没有交换任何数据。 在第2行中,字段ack 1415531522表示确认序号。它只有在首部中的 A C K标志比特被 设置1时才显示。 每行显示的字段 win 4096表示发端通告的窗口大小。在这些例子中,我们没有交换任 何数据,窗口大小就维持默认情况下的 4 0 9 6(我们将在2 0 . 4节中讨论T C P窗口大小)。 图1 8 - 1中的最后一个字段 表示由发端指明的最大报文段长度选项。发端将 不接收超过这个长度的 T C P报文段。这通常是为了避免分段(见 11 . 5节)。我们将在1 8 . 4节讨 论最大报文段长度,而在1 8 . 1 0节介绍不同TCP 选项的格式。 18.2.2 时间系列 图1 8 - 3显示了这些分组序列的时间系列(在图 6 - 11中已经首次介绍了这些时间系列的一些 基本特性)。这个图显示出哪一端正在发送分组。我们也将对 t c p d u m p输出作一些扩展(例如, 印出S Y N而不是S)。在这个时间系列中也省略窗口大小的值,因为它和我们的讨论无关。 18.2.3 建立连接协议 现在让我们回到图1 8 - 3所示的T C P协议中来。为了建立一条T C P连接: 第18章 TCP连接的建立与终止使用175 标志 3字符缩写 描 述 同步序号 发送方完成数据发送 复位连接 尽可能快地将数据送往接收进程 以上四个标志比特均置0 K a m i k a z e是神风队队员或神风队所使用的飞机。在第二次世界大战末期,日本空军的神风队队员驾驶满载 炸弹的飞机去撞击轰炸目标,企图与之同归于尽。176使用TCP/IP详解,卷1:协议 1) 请求端(通常称为客户)发送一个 S Y N段指明客户打算连接的服务器的端口,以及初 始序号(I S N,在这个例子中为1 4 1 5 5 3 1 5 2 1)。这个S Y N段为报文段1。 2) 服务器发回包含服务器的初始序号的 S Y N报文段(报文段2)作为应答。同时,将确认 序号设置为客户的I S N加1以对客户的S Y N报文段进行确认。一个S Y N将占用一个序号。 3) 客户必须将确认序号设置为服务器的 I S N加1以对服务器的S Y N报文段进行确认(报文 段3)。 这三个报文段完成连接的建立。这个过程也称为三次握手( three-way handshake)。 图18-3 连接建立与终止的时间系列 发送第一个S Y N的一端将执行主动打开( active open)。接收这个S Y N并发回下一个S Y N 的另一端执行被动打开(passive open)(在1 8 . 8节我们将介绍双方如何都执行主动打开)。 当一端为建立连接而发送它的 S Y N时,它为连接选择一个初始序号。 I S N随时间而变化, 因此每个连接都将具有不同的 I S N。RFC 793 [Postel 1981c]指出I S N可看作是一个3 2比特的计 数器,每4 m s加1。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而 导致某个连接的一方对它作错误的解释。 如何进行序号选择? 在4 . 4 B S D(和多数的伯克利的实现版)中,系统初始化时初 始的发送序号被初始化为1。这种方法违背了Host Requirements RFC(在这个代码中的 一个注释确认这是一个错误)。这个变量每0 . 5秒增加6 4 0 0 0,并每隔9 . 5小时又回到0 (对应这个计数器每8 ms加1,而不是每4 ms加1)。另外,每次建立一个连接后,这个 变量将增加64000。 报文段3与报文段4之间4 . 1秒的时间间隔是建立 T C P连接到向t e l n e t键入q u i t命令来中止该 连接的时间。 报文段1 报文段3 报文段4 报文段7 报文段6 报文段5 报文段218.2.4 连接终止协议 建立一个连接需要三次握手,而终止一个连接要经过 4次握手。这由T C P的半关闭(h a l f - c l o s e)造成的。既然一个T C P连接是全双工(即数据在两个方向上能同时传递),因此每个方 向必须单独地进行关闭。这原则就是当一方完成它的数据发送任务后就能发送一个 F I N来终止 这个方向连接。当一端收到一个 F I N,它必须通知应用层另一端几经终止了那个方向的数据传 送。发送F I N通常是应用层进行关闭的结果。 收到一个F I N只意味着在这一方向上没有数据流动。一个 T C P连接在收到一个 F I N后仍能 发送数据。而这对利用半关闭的应用来说是可能的,尽管在实际应用中只有很少的 T C P应用 程序这样做。正常关闭过程如图 1 8 - 3所示。我们将在1 8 . 5节中详细介绍半关闭。 首先进行关闭的一方(即发送第一个 F I N)将执行主动关闭,而另一方(收到这个 F I N) 执行被动关闭。通常一方完成主动关闭而另一方完成被动关闭,但我们将在 1 8 . 9节看到双方 如何都执行主动关闭。 图1 8 - 3中的报文段4发起终止连接,它由Te l n e t客户端关闭连接时发出。这在我们键入 q u i t 命令后发生。它将导致T C P客户端发送一个F I N,用来关闭从客户到服务器的数据传送。 当服务器收到这个 F I N,它发回一个 A C K,确认序号为收到的序号加 1(报文段 5)。和S Y N一样,一个F I N将占用一个序号。 同时 T C P服务器还向应用程序(即丢弃服 务器)传送一个文件结束符。接着这个服 务器程序就关闭它的连接,导致它的 T C P 端发送一个F I N(报文段6),客户必须发回 一个确认,并将确认序号设置为收到序号 加1(报文段7)。 图1 8 - 4显示了终止一个连接的典型握手 顺序。我们省略了序号。在这个图中,发 送F I N将导致应用程序关闭它们的连接,这 些F I N的A C K是由T C P软件自动产生的。 连接通常是由客户端发起的,这样第一个 S Y N从客户传到服务器。每一端都能主动关闭 这个连接(即首先发送 F I N)。然而,一般由客户端决定何时终止连接,因为客户进程通常由 用户交互控制,用户会键入诸如“ q u i t”一样的命令来终止进程。在图 1 8 - 4中,我们能改变上 边的标识,将左方定为服务器,右方定为客户,一切仍将像显示的一样工作(例如在 1 4 . 4节 中的第一个例子中就是由d a y t i m e服务器关闭连接的)。 18.2.5 正常的t c p d u m p输出 对所有的数值很大的序号进行排序是很麻烦的,因此默认情况下 t c p d u m p只在显示S Y N 报文段时显示完整的序号,而对其后的序号则显示它们与初始序号的相对偏移值(为了得到 图1 8 - 1的输出显示必须加上- S选项)。对应于图1 8 - 1的正常t c p d u m p显示如图1 8 - 5所示: 除非我们需要显示完整的序号,否则将在以下的例子中使用这种形式的输出显示。 第18章 TCP连接的建立与终止使用177 图18-4 连接终止期间报文段的正常交换 应用程 序关闭 客户 服务器 应用程 序关闭 向应用程 序交付E O F图18-5 连接建立与终止的正常t c p d u m p 输出 18.3 连接建立的超时 有很多情况导致无法建立连接。一种情况是服务器主机没有处于正常状态。为了模拟这种情 况,我们断开服务器主机的电缆线,然后向它发出t e l n e t命令。图1 8 - 6显示了t c p d u m p的输出。 图18-6 建立连接超时的t c p d u m p 输出 在这个输出中有趣的一点是客户间隔多长时间发送一个 S Y N,试图建立连接。第2个S Y N 与第1个的间隔是5 . 8秒,而第3个与第2个的间隔是2 4秒。 作为一个附注,这个例子运行3 8分钟后客户重新启动。这对应初始序号为291 008 001 (约为3 8×6 0×6 4 0 0 0×2)。我们曾经介绍过使用典型的伯克利实现版的系统将初始序号初 始化为1,然后每隔0 . 5秒就增加64 000。 另外,因为这是系统启动后的第一个TCP连接,因此客户的端口号是1024。 图1 8 - 6中没有显示客户端在放弃建立连接尝试前进行 S Y N重传的时间。为了了解它我们 必须对t e l n e t命令进行计时: 时间差值是 7 6秒。大多数伯克利系统将建立一个新连接的最长时间限制为 7 5秒。我们将在 2 1 . 4节看到由客户发出的第 3个分组大约在1 6 : 2 5 : 2 9超时, 客户在它第3个分组发出后4 8秒而 不是7 5秒后放弃连接。 18.3.1 第一次超时时间 在图1 8 - 6中一个令人困惑的问题是第一次超时时间为 5 . 8秒,接近6秒,但不准确,相比之 178使用TCP/IP详解,卷1:协议第18章 TCP连接的建立与终止使用179 下第二个超时时间几乎准确地为 2 4秒。运行十多次测试,发现第一次超时时间在 5 . 5 9秒~ 5 . 9 3 秒之间变化。然而,第二次超时时间则总是 2 4 . 0 0秒(精确到小数点后面两位)。 这是因为B S D版的T C P软件采用一种500 ms的定时器。这种500 ms的定时器用于确定本章 中所有的各种各样的T C P超时。当我们键入t e l n e t命令,将建立一个6秒的定时器(1 2个时钟滴 答(t i c k)),但它可能在之后的 5 . 5秒~ 6秒内的任意时刻超时。图 1 8 - 7显示了这一发生过程。 尽管定时器初始化为 1 2个时钟滴答,但定时计数器会在设置后的第一个 0~500 ms中的任意时 刻减1。从那以后,定时计数器大约每隔 500 ms减1,但在第1个500 ms内是可变的(我们使用 限定词“大约”是因为在 T C P每隔500 ms获得系统控制的瞬间,系统内核可能会优先处理其 他中断)。 图18-7 TCP的500 ms定时器 当滴答计数器为 0时,6秒的定时器便会超时(见图 1 8 - 7),这个定时器会在以后的 2 4秒 (4 8个滴答)重新复位。之后的下一个定时器将更接近 2 4秒,因为当T C P的500 ms定时器被内 核调用时,它就会被修改一次。 18.3.2 服务类型字段 在图1 8 - 6中,出现了符号 [ tos 0x10 ]。这是I P数据报内的服务类型(TO S)字段(参见图 3 - 2)。B S D / 3 8 6中的Te l n e t客户进程将这个字段设置为最小时延。 18.4 最大报文段长度 最大报文段长度( M S S)表示T C P传往另一端的最大块数据的长度。当一个连接建立时, 连接的双方都要通告各自的 M S S。我们已经见过 M S S都是1 0 2 4。这导致I P数据报通常是4 0字 节长:2 0字节的T C P首部和2 0字节的I P首部。 在有些书中,将它看作可“协商”选项。它并不是任何条件下都可协商。当建立一个连 接时,每一方都有用于通告它期望接收的 M S S选项(M S S选项只能出现在S Y N报文段中)。如 果一方不接收来自另一方的 M S S值,则M S S就定为默认值5 3 6字节(这个默认值允许 2 0字节的 I P首部和2 0字节的T C P首部以适合5 7 6字节I P数据报)。 一般说来,如果没有分段发生, M S S还是越大越好(这也并不总是正确,参见图 2 4 - 3和 图2 4 - 4中的例子)。报文段越大允许每个报文段传送的数据就越多,相对 I P和T C P首部有更高 的网络利用率。当 T C P发送一个S Y N时,或者是因为一个本地应用进程想发起一个连接,或 者是因为另一端的主机收到了一个连接请求,它能将 M S S值设置为外出接口上的 M T U长度减 去固定的I P首部和T C P首部长度。对于一个以太网, M S S值可达1 4 6 0字节。使用IEEE 802.3的 封装(参见2 . 2节),它的M S S可达1 4 5 2字节。 在本章见到的涉及 B S D / 3 8 6和S V R 4的M S S为1 0 2 4,这是因为许多 B S D的实现版本需要 应用程序在此刻使 TCP设置一个6秒(12 滴答)的定时器 每滴答500毫秒 11时钟滴答×500ms/滴答=5.5 TCP重新设置一个 24秒的定时器 秒180使用TCP/IP详解,卷1:协议 M S S为5 1 2的倍数。其他的系统,如SunOS 4.1.3、Solaris 2.2 和AIX 3.2.2,当双方都在一个本 地以太网上时都规定 M S S为1 4 6 0。[Mogul 1993] 的比较显示了在以太网上 1 4 6 0的M S S在性能 上比1 0 2 4的M S S更好。 如果目的I P地址为“非本地的 ( n o n l o c a l )”,M S S通常的默认值为 5 3 6。而区分地址是本地 还是非本地是简单的,如果目的 I P地址的网络号与子网号都和我们的相同,则是本地的;如 果目的I P地址的网络号与我们的完全不同,则是非本地的;如果目的 I P地址的网络号与我们 的相同而子网号与我们的不同,则可能是本地的,也可能是非本地的。大多数 T C P实现版都 提供了一个配置选项(附录E和图E - 1),让系统管理员说明不同的子网是属于本地还是非本地。 这个选项的设置将确定 M S S可以选择尽可能的大(达到外出接口的 M T U长度)或是默认值 5 3 6。 M S S让主机限制另一端发送数据报的长度。加上主机也能控制它发送数据报的长度,这 将使以较小M T U连接到一个网络上的主机避免分段。 考虑我们的主机s l i p,通过M T U为2 9 6的S L I P链路连接到路由器b s d i上。图1 8 - 8显示这 些系统和主机s u n。 图18-8 显示s u n 与s l i p 间TCP连接的MSS值 从s u n向s l i p发起一个T C P连接,并使用t c p d u m p来观察报文段。图 1 8 - 9显示这个连接 的建立(省略了通告窗口大小)。 图18-9 t c p d u m p 显示了从s u n 向s l i p 建立连接的过程 在这个例子中,s u n发送的报文段不能超过 2 5 6字节的数据,因为它收到的 M S S选项值为 2 5 6(第2行)。此外,由于 s l i p知道它外出接口的 M T U长度为2 9 6,即使s u n已经通告它的 M S S为1 4 6 0,但为避免将数据分段,它不会发送超过 2 5 6字节数据的报文段。系统允许发送的 数据长度小于另一端的M S S值。 只有当一端的主机以小于5 7 6字节的M T U直接连接到一个网络中,避免这种分段才会有效。 如果两端的主机都连接到以太网上,都采用 5 3 6的M S S,但中间网络采用 2 9 6的M T U,也将会 出现分段。使用路径上的M T U发现机制(参见2 4 . 2节)是关于这个问题的唯一方法。 18.5 TCP的半关闭 T C P提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。这就是所谓的半关闭。正如我们早些时候提到的只有很少的应用程序使用它。 为了使用这个特性,编程接口必须为应用程序提供一种方式来说明“我已经完成了数据 传送,因此发送一个文件结束( F I N)给另一端,但我还想接收另一端发来的数据,直到它给 我发来文件结束(F I N)”。 如果应用程序不调用c l o s e而调用s h u t d o w n,且第2个参数值为1,则插口的A P I支持 半关闭。然而,大多数的应用程序通过调用close终止两个方向的连接。 图1 8 - 1 0显示了一个半关闭的典型例 子。让左方的客户端开始半关闭,当然也 可以由另一端开始。开始的两个报文段和 图1 8 - 4是相同的:初始端发出的 F I N,接 着是另一端对这个 F I N的A C K报文段。但 后面就和图1 8 - 4不同,因为接收半关闭的 一方仍能发送数据。我们只显示一个数据 报文段和一个A C K报文段,但可能发送了 许多数据报文段(将在第 1 9章讨论数据报 文段和确认报文段的交换)。当收到半关 闭的一端在完成它的数据传送后,将发送 一个F I N关闭这个方向的连接,这将传送 一个文件结束符给发起这个半关闭的应用 进程。当对第二个 F I N进行确认后,这个 连接便彻底关闭了。 为什么要有半关闭?一个例子是 U n i x中的r s h( 1 )命令,它将完成在另一个系统上执行一 个命令。命令 sun % rsh bsdi sort < datafile 将在主机b s d i上执行s o r t排序命令,r s h命令的标准输入来自文件 d a t a f i l e。r s h将在它 与在另一主机上执行的程序间建立一个 T C P 连接。 r s h 的操作很简单:它将标准输入 (d a t a f i l e)复制给T C P连接,并将结果从 T C P连接中复制给标准输出(我们的终端)。图 1 8 - 11显示了这个建立过程(牢记 T C P连接是全双工的)。 图18-11 命令:rsh bsdi sort < datafile 在远端主机b s d i上,r s h d服务器将执行s o r t程序,它的标准输入和标准输出都是 T C P 连接。第1 4章的 [Stevens 1990] 详细介绍了有关U n i x进程的结构,但这儿涉及的是使用 T C P连 接以及需要使用T C P的半关闭。 s o r t程序只有读取到所有输入数据后才能产生输出。所有的原始数据通过 T C P连接从 r s h客户端传送到s o r t服务器进行排序。当输入( d a t a f i l e)到达文件尾时, r s h客户端 第18章 TCP连接的建立与终止使用181 图18-10 TCP半关闭的例子 应用进程 shutdown 客户 服务器 应用进程 read 向应用进程 交付EOF 向应用进程 交付EOF 应用进程write 应用进程close 标准输入 TCP连接 主机sun 主机bsdi 标准输出 终端执行这个T C P连接的半关闭。接着 s o r t服务器在它的标准输入(这个 T C P连接)上收到一个 文件结束符,对数据进行排序,并将结果写在它的标准输出上( T C P连接)。r s h客户端继续 接收来自T C P连接另一端的数据,并将排序的文件复制到它的标准输出上。 没有半关闭,需要其他的一些技术让客户通知服务器, 客户端已经完成了它的数据传送,但 仍要接收来自服务器的数据。使用两个T C P连接也可作为一个选择,但使用半关闭的单连接更好。 18.6 TCP的状态变迁图 我们已经介绍了许多有关发起和终止 T C P连接的规则。这些规则都能从图 1 8 - 1 2所示的状 态变迁图中得出。 图18-12 TCP的状态变迁图 在这个图中要注意的第一点是一个状态变迁的子集是“典型的”。我们用粗的实线箭头表 示正常的客户端状态变迁,用粗的虚线箭头表示正常的服务器状态变迁。 182使用TCP/IP详解,卷1:协议 开始 应用进程:被动打开 发送:无 被动打开 SYN收到 应用进程: 关闭 发: FIN 收:SYN 发:SYN,ACF 同时打开 数据传送状态 收: FIN 发: ACK 应用进程: 关闭 发: FIN 收: FIN 发: ACK 同时关闭 被动关闭 发送:无 收: ACK 发送 无 收: ACK 发送: 无 收: ACK 收: FIN 发: ACK 主动关闭 说明客户的正常状态变迁 说明服务器的正常状态变迁 说明当应用执行某种操作时发生的状态变迁 说明当收到TCP报文段时状态的变迁 说明为了进行某个状态变迁要发送的TCP报文段 2MSL超时 主动打开 应用进程: 关闭 或超时 应用进程: 收: 发:第18章 TCP连接的建立与终止使用183 第二点是两个导致进入E S TA B L I S H - E D状态的变迁对应打开一个连接,而两 个导致从E S TA B L I S H E D状态离开的变迁 对应关闭一个连接。E S TA B L I S H E D状态 是连接双方能够进行双向数据传递的状 态。以后的章节将介绍这个状态。 将图中左下角 4个状态放在一个虚 线框内,并标为“主动关闭”。其他两 个状态(C L O S E _ WA I T和L A S T _ A C K) 也用虚线框住,并标为“被动关闭”。 在 这 个 图 中 1 1 个 状 态 的 名 称 (CLOSED, LISTEN, SYN_SENT等) 是有意与n e t s t a t命令显示的状态名 称一致。n e t s t a t对状态的命名几乎 与 在 RFC 793中 的 最 初 描述 一 致 。 C L O S E D状态不是一个真正的状态, 而是这个状态图的假想起点和终点。 从L I S T E N到S Y N _ S E N T的变迁是 正确的,但伯克利版的T C P软件并不支持它。 只有当S Y N _ R C V D状态是从L I S T E N状态(正常情况)进入,而不是从 S Y N _ S E N T状态 (同时打开)进入时,从 S Y N _ R C V D回到L I S T E N的状态变迁才是有效的。这意味着如果我们 执行被动关闭(进入L I S T E N),收到一个S Y N,发送一个带A C K的S Y N(进入S Y N _ R C V D), 然后收到一个R S T,而不是一个A C K,便又回到L I S T E N状态并等待另一个连接请求的到来。 图1 8 - 1 3显示了在正常的T C P连接的建立与终止过程中,客户与服务器所经历的不同状态。 它是图1 8 - 3的再现,不同的是仅显示了一些状态。 假定在图1 8 - 1 3中左边的客户执行主动打开,而右边的服务器执行被动打开。尽管图中显 示出由客户端执行主动关闭,但和早前我们提到的一样,另一端也能执行主动关闭。 可以使用图1 8 - 1 2的状态图来跟踪图1 8 - 1 3的状态变化过程,以便明白每个状态的变化。 18.6.1 2MSL等待状态 T I M E _ WA I T状态也称为2 M S L等待状态。每个具体 T C P实现必须选择一个报文段最大生 存时间M S L(Maximum Segment Lifetime)。它是任何报文段被丢弃前在网络内的最长时间。 我们知道这个时间是有限的,因为 T C P报文段以I P数据报在网络内传输,而I P数据报则有限制 其生存时间的T T L字段。 RFC 793 [Postel 1981c] 指出MSL为2分钟。然而,实现中的常用值是30秒,1分钟, 或2分钟。 从第8章我们知道在实际应用中,对 I P数据报T T L的限制是基于跳数,而不是定时器。 对一个具体实现所给定的 M S L值,处理的原则是:当 T C P执行一个主动关闭,并发回最 图18-13 TCP正常连接建立和终止所对应的状态 主动关闭 (被动 关闭) (被动打开) 主动打开 客户 服务器后一个A C K,该连接必须在T I M E _ WA I T状态停留的时间为 2倍的M S L。这样可让T C P再次发 送最后的A C K以防这个A C K丢失(另一端超时并重发最后的 F I N)。 这种2 M S L等待的另一个结果是这个 T C P连接在2 M S L等待期间,定义这个连接的插口 (客户的I P地址和端口号,服务器的 I P地址和端口号)不能再被使用。这个连接只能在 2 M S L 结束后才能再被使用。 遗憾的是,大多数 T C P实现(如伯克利版)强加了更为严格的限制。在 2 M S L等待期间, 插口中使用的本地端口在默认情况下不能再被使用。我们将在下面看到这个限制的例子。 某些实现和A P I提供了一种避开这个限制的方法。使用插口A P I时,可说明其中的 S O _ R E U S E A D D R选项。它将让调用者对处于2 M S L等待的本地端口进行赋值,但我们 将看到TCP原则上仍将避免使用仍处于2MSL连接中的端口。 在连接处于2 M S L等待时,任何迟到的报文段将被丢弃。因为处于 2 M S L等待的、由该插 口对(socket pair)定义的连接在这段时间内不能被再用,因此当要建立一个有效的连接时,来 自该连接的一个较早替身( i n c a r n a t i o n)的迟到报文段作为新连接的一部分不可能不被曲解 (一个连接由一个插口对来定义。一个连接的新的实例( i n s t a n c e)称为该连接的替身)。 我们说图1 8 - 1 3中客户执行主动关闭并进入 T I M E _ WA I T是正常的。服务器通常执行被动 关闭,不会进入T I M E _ WA I T状态。这暗示如果我们终止一个客户程序,并立即重新启动这个 客户程序,则这个新客户程序将不能重用相同的本地端口。这不会带来什么问题,因为客户 使用本地端口,而并不关心这个端口号是什么。 然而,对于服务器,情况就有所不同,因为服务器使用熟知端口。如果我们终止一个已 经建立连接的服务器程序,并试图立即重新启动这个服务器程序,服务器程序将不能把它的 这个熟知端口赋值给它的端点,因为那个端口是处于 2 M S L连接的一部分。在重新启动服务器 程序前,它需要在1 ~ 4分钟。 可以通过s o c k程序看到这一切。我们启动服务器程序,从一个客户程序进行连接,然后 停止这个服务器程序。 当重新启动服务器程序时,程序报告一个差错信息说明不能绑定它的熟知端口,因为该端口 已被使用(即它处于2 M S L等待)。 运行n e t s t a t程序来查看连接的状态,以证实它的确处于 2 M S L等待状态。 如果我们一直试图重新启动服务器程序,并测量它直到成功所需的时间,我们就 能确定出2 M S L值。对于SunOS 4.1.3、S V R 4、B S D / 3 8 6和AIX 3.2.2,它需要1分钟才能 重新启动服务器程序,这意味着它们的M S L值为3 0秒。而对于Solaris 2.2 ,它需要4分 184使用TCP/IP详解,卷1:协议 启动服务器进程,在端口6666监听(在bsdi上执行客 户进程与该端口进行连接) 键入中断键停止服务器进程 并立即在同一端口重启服务器进程 检测连接状态 删除了许多其他行第18章 TCP连接的建立与终止使用185 钟才能重新启动服务器程序,这表示它的MSL值为2分钟。 如果一个客户程序试图申请一个处于 2 M S L等待的端口(客户程序通常不会这么做),就 会出现同样的差错。 我们在第1次执行客户程序时采用 - v选项来查看它使用的本地端口为( 11 6 2)。第2次执行客 户程序时则采用- b选项来选择端口 11 6 2为它的本地端口。正如我们所预料的那样,客户程序 无法那么做,因为那个端口是一个还处于 2 M S L等待连接的一部分。 需要再次强调2 M S L等待的一个效果,因为我们将在第 2 7章的文件传输协议F T P中遇到它。 和以前介绍的一样,一个插口对(即包含本地 I P地址、本地端口、远端 I P地址和远端端口的 4 元组)在它处于2 M S L等待时,将不能再被使用。尽管许多具体的实现中允许一个进程重新使 用仍处于2 M S L等待的端口(通常是设置选项 S O _ R E U S E A D D R),但T C P不能允许一个新的连 接建立在相同的插口对上。可通过下面的试验来看到这一点: 在第1次运行s o c k程序中,我们将它作为服务器程序,端口号为 6 6 6 6,并从主机b s d i上的一 个客户程序与它连接,这个客户程序使用的端口为 1 0 9 8。我们终止服务器程序,因此它将执 行主动关闭。这将导致 4元组 1 4 0 . 2 5 2 . 1 3 . 3 3(本地 I P地址)、6 6 6 6 (本地端口号)、 1 4 0 . 2 5 2 . 1 3 . 3 5(另一端I P地址)和1 0 9 8(另一端的端口号)在服务器主机进入 2 M S L等待。 在第2次运行s o c k程序时,我们将它作为客户程序,并试图将它的本地端口号指明为 6 6 6 6,同时与主机b s d i在端口1 0 9 8上进行连接。但这个程序在试图将它的本地端口号赋值为 6 6 6 6时产生了一个差错,因为这个端口是处于 2 M S L等待4元组的一部分。 为了避免这个差错,我们再次运行这个程序,并使用选项- A来设置前面提到的 S O _ R E U S E A D D R。这将让s o c k程序能将它的本地端口号设置为 6 6 6 6,但当我们试图进行主 动打开时,又出现了一个差错。即使它能将它的本地端口设置为 6 6 6 6,但它仍不能和主机 b s d i在端口1 0 9 8上进行连接,因为定义这个连接的插口对仍处于 2 M S L等待状态。 如果我们试图从其他主机来建立这个连接会如何?首先我们必须在 s u n上以-A标记来重新 启动服务器程序,因为它需要的端口( 6 6 6 6)是还处于2 M S L等待连接的一部分。 sun % sock -A -s 6666 启动服务器程序,在端口 6 6 6 6监听 接着,在2 M S L等待结束前,我们在b s d i上启动客户程序: bsdi % sock -b1098 sun 6666 启动客户进程,与回显服务器进程连接 键入这一行 这一行应被服务器进程回显 键入文件结束符终止客户进程 启动服务器进程,在端口6666监听(在bsdi上执行 客户进程与该端口进行连接) 键入中断键停止服务器进程 尝试在本地端口6666启动客户进程 再次尝试,加上-A选项connected on 140.252.13.35.1098 to 140.252.13.33.6666 不幸的是它成功了!这违反了 T C P规范,但被大多数的伯克利版实现所支持。这些实现允许 一个新的连接请求到达仍处于 T I M E _ WA I T状态的连接,只要新的序号大于该连接前一个替身 的最后序号。在这个例子中,新替身的 I S N被设置为前一个替身最后序号与 128 000的和。附 录的RFC 1185 [Jacobsan、B r a d e n和Zhang 1990] 指出了这项技术仍可能存在缺陷。 对于同一连接的前一个替身,这个具体实现中的特性让客户程序和服务器程序能连续地 重用每一端的相同端口号,但这只有在服务器执行主动关闭才有效。我们将在图 2 7 - 8中使用 F T P时看到这个2 M S L等待条件的另一个例子。也见习题 1 8 . 5。 18.6.2 平静时间的概念 对于来自某个连接的较早替身的迟到报文段, 2 M S L等待可防止将它解释成使用相同插口 对的新连接的一部分。但这只有在处于 2 M S L等待连接中的主机处于正常工作状态时才有效。 如果使用处于2 M S L等待端口的主机出现故障,它会在 M S L秒内重新启动,并立即使用故 障前仍处于2 M S L的插口对来建立一个新的连接吗?如果是这样,在故障前从这个连接发出而 迟到的报文段会被错误地当作属于重启后新连接的报文段。无论如何选择重启后新连接的初 始序号,都会发生这种情况。 为了防止这种情况,RFC 793指出T C P在重启动后的M S L秒内不能建立任何连接。这就称 为平静时间(quiet time)。 只有极少的实现版遵守这一原则,因为大多数主机重启动的时间都比MSL秒要长。 18.6.3 FIN_WAIT_2 状态 在F I N _ WA I T _ 2状态我们已经发出了 F I N,并且另一端也已对它进行确认。除非我们在实 行半关闭,否则将等待另一端的应用层意识到它已收到一个文件结束符说明,并向我们发一 个F I N来关闭另一方向的连接。只有当另一端的进程完成这个关闭,我们这端才会从 F I N _ WA I T _ 2状态进入T I M E _ WA I T状态。 这意味着我们这端可能永远保持这个状态。另一端也将处于 C L O S E _ WA I T状态,并一直 保持这个状态直到应用层决定进行关闭。 许多伯克利实现采用如下方式来防止这种在F I N _ WA I T _ 2状态的无限等待。如果执 行主动关闭的应用层将进行全关闭,而不是半关闭来说明它还想接收数据,就设置一 个定时器。如果这个连接空闲1 0分钟7 5秒,T C P将进入C L O S E D状态。在实现代码的注 释中确认这个实现代码违背协议的规范。 18.7 复位报文段 我们已经介绍了T C P首部中的R S T比特是用于“复位”的。一般说来,无论何时一个报文 段发往基准的连接( referenced connection)出现错误,T C P都会发出一个复位报文段(这里 提到的“基准的连接”是指由目的 I P地址和目的端口号以及源 I P地址和源端口号指明的连接。 这就是为什么RFC 793称之为插口)。 186使用TCP/IP详解,卷1:协议第18章 TCP连接的建立与终止使用187 18.7.1 到不存在的端口的连接请求 产生复位的一种常见情况是当连接请求到达时,目的端口没有进程正在听。对于 U D P, 我们在6 . 5节看到这种情况,当一个数据报到达目的端口时,该端口没在使用,它将产生一个 I C M P端口不可达的信息。而T C P则使用复位。 产生这个例子也很容易,我们可使用 Te l n e t客户程序来指明一个目的端口没在使用的情 况: bsdi % telnet svr4 20000 端口2 0 0 0 0未使用 Trying 140.252.13.34... telnet: Unable to connect to remote host: Connection refused Te l n e t客户程序会立即显示这个差错信息。图 1 8 - 1 4显示了对应这个命令的分组交换过程。 1 0.0 bsdi.1087 > svr4.20000: S 297416193:297416193(0) win 4096 [tos 0x10] 2 0.003771 (0.0038) svr4.20000 > bsdi.1087: R 0:0(0) ack 297416194 win 0 图18-14 试图在不存在的端口上打开连接而产生的复位 在这个图中需要注意的值是复位报文段中的序号字段和确认序号字段。因为 A C K比特在 到达的报文段中没有被设置为 1,复位报文段中的序号被置为 0,确认序号被置为进入的 I S N加 上数据字节数。尽管在到达的报文段中没有真正的数据,但 S Y N比特从逻辑上占用了 1字节的 序号空间;因此,在这个例子中复位报文段中确认序号被置为 I S N与数据长度(0)、S Y N比特 所占的1的总和。 18.7.2 异常终止一个连接 我们在 1 8 . 2节中看到终止一个连接的正常方式是一方发送 F I N。有时这也称为有序释放 (orderly release),因为在所有排队数据都已发送之后才发送 F I N,正常情况下没有任何数据 丢失。但也有可能发送一个复位报文段而不是 F I N来中途释放一个连接。有时称这为异常释放 (abortive release)。 异常终止一个连接对应用程序来说有两个优点:(1)丢弃任何待发数据并立即发送复位 报文段;(2)R S T的接收方会区分另一端执行的是异常关闭还是正常关闭。应用程序使用的 A P I必须提供产生异常关闭而不是正常关闭的手段。 使用s o c k程序能够观察这种异常关闭的过程。 Socket API通过“linger on close”选项 (S O _ L I N G E R)提供了这种异常关闭的能力。我们加上 - L选项并将停留时间设为 0。这将导 致连接关闭时进行复位而不是正常的 F I N。我们连接到处于服务器上的 s o c k程序,并键入一 输入行: bsdi % sock -L0 svr4 8888 这是客户程序,服务器程序显示后面 hello, world 键入一行输入,它被发往到另一端 ^ D 键入文件结束符,终止客户程序 图1 8 - 1 5是这个例子的t c p d u m p输出显示(在这个图中我们已经删除了所有窗口大小的说 明,因为它们与讨论无关)。 第1 ~ 3行显示出建立连接的正常过程。第 4行发送我们键入的数据行( 1 2个字符和U n i x换行符),第5行是对收到数据的确认。 图18-15 使用复位(RST)而不是FIN来异常终止一个连接 第6行对应为终止客户程序而键入的文件结束符(C o n t r o l _ D)。由于我们指明使用异常关闭 而不是正常关闭(命令行中的- L 0选项),因此主机b s d i端的T C P发送一个R S T而不是通常的F I N。 R S T报文段中包含一个序号和确认序号。需要注意的是 R S T报文段不会导致另一端产生任何响 应,另一端根本不进行确认。收到R S T的一方将终止该连接,并通知应用层连接复位。 我们在服务器上得到下面的差错信息: svr4 % sock -s 8888 作为服务器进程运行,在端口 8 8 8 8监听 hello, world 这行是客户端发送的 read error: Connection reset by peer 这个服务器程序从网络中接收数据并将它接收的数据显示到其标准输出上。通常,从它 的T C P上收到文件结束符后便将结束,但这里我们看到当收到 R S T时,它产生了一个差错。这 个差错正是我们所期待的:连接被对方复位了。 18.7.3 检测半打开连接 如果一方已经关闭或异常终止连接而另一方却还不知道,我们将这样的 T C P连接称为半 打开(H a l f - O p e n)的。任何一端的主机异常都可能导致发生这种情况。只要不打算在半打开 连接上传输数据,仍处于连接状态的一方就不会检测另一方已经出现异常。 半打开连接的另一个常见原因是当客户主机突然掉电而不是正常的结束客户应用程序后 再关机。这可能发生在使用 P C机作为Te l n e t的客户主机上,例如,用户在一天工作结束时关 闭P C机的电源。当关闭P C机电源时,如果已不再有要向服务器发送的数据,服务器将永远不 知道客户程序已经消失了。当用户在第二天到来时,打开 P C机,并启动新的Te l n e t客户程序, 在服务器主机上会启动一个新的服务器程序。这样会导致服务器主机中产生许多半打开的 T C P连接(在第2 3章中我们将看到使用T C P的k e e p a l i v e选项能使T C P的一端发现另一端已经消 失)。 能很容易地建立半打开连接。在 b s d i上运行Te l n e t客户程序,通过它和s v r 4上的丢弃服务 器建立连接。我们键入一行字符,然后通过 t c p d u m p进行观察,接着断开服务器主机与以太 网的电缆,并重启服务器主机。这可以模拟服务器主机出现异常(在重启服务器之前断开以 太网电缆是为了防止它向打开的连接发送 F I N,某些T C P在关机时会这么做)。服务器主机重 启后,我们重新接上电缆,并从客户向服务器发送另一行字符。由于服务器的 T C P已经重新 启动,它将丢失复位前连接的所有信息,因此它不知道数据报文段中提到的连接。 T C P的处 理原则是接收方以复位作为应答。 188使用TCP/IP详解,卷1:协议图1 8 - 1 6是这个例子的t c p d u m p输出显示(已从这个输出中删除了窗口大小的说明、服务 类型信息和M S S声明,因为它们与讨论无关)。 图18-16 复位作为半打开连接上数据段的应答 第1 ~ 3行是正常的连接建立过程。第 4行向丢弃服务器发送字符行“ h i t h e r e”,第5行是确 认。 然后是断开s v r 4的以太网电缆,重新启动s v r 4,并重新接上电缆。这个过程几乎需要 1 9 0 秒。接着从客户端输入下一行(即“ another line”),当我们键入回车键后,这一行被发往服 务器(图1 8 - 1 6的第6行)。这导致服务器产生一个响应,但要注意的是由于服务器主机经过重 新启动,它的 A R P高速缓存为空,因此需要一个 A R P请求和应答(第 7、8行)。第9行表示 R S T被发送出去。客户收到复位报文段后显示连接已被另一端的主机终止( Te l n e t客户程序发 出的最后信息不再有什么价值)。 18.8 同时打开 两个应用程序同时彼此执行主动打开的情况是可能的,尽管发生的可能性极小。每一方 必须发送一个 S Y N,且这些S Y N必须传递给对方。这需要每一方使用一个对方熟知的端口作 为本地端口。这又称为同时打开( simultaneous open)。 例如,主机A中的一个应用程序使用本地端口 7 7 7 7,并与主机B的端口8 8 8 8执行主动打开。 主机B中的应用程序则使用本地端口 8 8 8 8,并与主机A的端口7 7 7 7执行主动打开。 这与下面的情况不同:主机A中的Te l n e t客户程序和主机B中Te l n e t的服务器程序建立连接, 与此同时,主机 B中的Te l n e t客户程序与主机A的Te l n e t服务器程序也建立连接。在这个 Te l n e t 例子中,两个Te l n e t服务器都执行被动打开,而不是主动打开,并且 Te l n e t客户选择的本地端 口不是另一端Te l n e t服务器进程所熟悉的端口。 T C P是特意设计为了可以处理同时打开,对于同时打开它仅建立一条连接而不是两条连 接(其他的协议族,最突出的是 O S I运输层,在这种情况下将建立两条连接而不是一条连接)。 当出现同时打开的情况时,状态变迁与图 1 8 - 1 3所示的不同。两端几乎在同时发送 S Y N, 并进入S Y N _ S E N T状态。当每一端收到 S Y N时,状态变为S Y N _ R C V D(如图1 8 - 1 2),同时它 第18章 TCP连接的建立与终止使用189 启动客户进程 运行已正确发送 重新启动服务器主机 导致连接复位们都再发S Y N并对收到的S Y N进行确认。当双方都收到 S Y N及相应的A C K时,状态都变迁为 E S TA B L I S H E D。图1 8 - 1 7显示了这些状态变迁过程。 图18-17 同时打开期间报文段的交换 一个同时打开的连接需要交换 4个报文段,比正常的三次握手多一个。此外,要注意的是 我们没有将任何一端称为客户或服务器,因为每一端既是客户又是服务器。 一个例子 尽管很难,但仍有可能产生一个同时打开的连接。两端必须几乎在同时启动,以便收到 彼此的S Y N。只要两端有较长的往返时间就能保证这一点。这样我们将一端设置在主机 b s d i 上,另一端则设置在主机 v a n g o g h . c s . b e r k e l e y . e d u上。由于两端之间有一条拨号链路 S L I P,它的往返时间对保证双方同步收到 S Y N是足够长的(几百毫秒)。 一端(b s d i)将本地端口设置为 8 8 8 8(使用命令行选项 - b),并对另一端主机端口 7 7 7 7 执行主动打开。 另一端也几乎在同一时间将本地端口设置为 7 7 7 7,并对端口8 8 8 8执行主动打开。 我们指明带- v标志的s o c k程序来验证连接两端的 I P地址和端口号。这个选项也显示每一 端的M S S值。为证实两端确实在相互交谈,我们在每一端还输入一行字符,看它们是否会被 送到另一端并显示出来。 图1 8 - 1 8显示了这个连接的段交换过程(我们删除了出现在来自 v a n g o g h第一个S Y N中的 一些新的T C P选项,因为v a n g o g h使用4 . 4 B S D系统。将在1 8 . 1 0节介绍这些较新的选项)。注 意两个S Y N(第1 ~ 2行)后跟着两个带A C K的S Y N(第3 ~ 4行)。它们将执行同时打开。 第5行显示了由b s d i发送给v a n g o g h的输入行“hello, world”,第6行对此进行确认。第 7 ~ 8行对应另一方向的输入行“ and hi there”和确认。第9 ~ 1 2行显示正常的连接关闭。 许多伯克利版的T C P实现都不能正确地支持同时打开。在这些系统中,如果能够 190使用TCP/IP详解,卷1:协议 (主动打开)(主动打开) 键入该行 这是另一端键入的行 键入这行 键入文件结束符EOF 在另一端键入这一行 当收到FIN时的输出显示进行S Y N的同步接收,你将经历极多的报文段交换过程才能关闭它们。每个报文段交 换过程包括每个方向上的一个 S Y N和一个 A C K。图1 8 - 1 2中从S Y N _ S E N T到状态 SYN_RCVD的变迁在许多TCP实现中很少测试过。 图18-18 同时打开期间的报文段交换过程 18.9 同时关闭 我们在以前讨论过一方(通常但不总是客户方)发送第一个 F I N执行主动关闭。双方都执 行主动关闭也是可能的,T C P协议也允许这样的同时关闭( simultaneous close)。 在图1 8 - 1 2中,当应用层发出关闭命令时,两端均从 E S TA B L I S H E D变为F I N _ WA I T _ 1。 这将导致双方各发送一个 F I N,两个F I N经过网络传送后分别到达另一端。收到 F I N后,状态 由F I N _ WA I T _ 1变迁到C L O S I N G,并发送最后的 A C K。当收到最后的 A C K时,状态变化为 T I M E _ WA I T。图1 8 - 1 9总结了这些状态的变化。 图18-19 同时关闭期间的报文段交换 同时关闭与正常关闭使用的段交换数目相同。 18.10 TCP 选项 T C P首部可以包含选项部分(图 1 7 - 2)。仅在最初的T C P规范中定义的选项是选项表结束、 无操作和最大报文段长度。在我们的例子中,几乎每个 S Y N报文段中我们都遇到过M S S选项。 新的R F C,主要是RFC 1323 [Jacobson, Braden和Borman 1992],定义了新的T C P选项, 第18章 TCP连接的建立与终止使用191 (主动关闭)(主动关闭)这些选项的大多数只在最新的 T C P实现中才能见到(我们将在第 2 4章介绍这些新选项)。图 1 8 - 2 0显示了当前T C P选项的格式,这些选项的定义出自于 RFC 793和RFC 1323。 图18-20 TCP选项 每个选项的开始是1字节k i n d字段,说明选项的类型。k i n d字段为0和1的选项仅占1个字节。 其他的选项在k i n d字节后还有l e n字节。它说明的长度是指总长度,包括 k i n d字节和l e n字节。 设置无操作选项的原因在于允许发方填充字段为 4字节的倍数。如果我们使用 4 . 4 B S D系统 进行初始化T C P连接,t c p d u m p将在初始的S Y N上显示下面T C P选项: M S S选项设置为5 1 2,后面是N O P,接着是窗口扩大选项。第一个 N O P用来将窗口扩大选项填 充为4字节的边界。同样, 1 0字节的时间戳选项放在两个 N O P后,占1 2字节,同时使两个 4字 节的时间戳满足4字节边界。 其他k i n d值为4、5、6和7的四个选项称为选择A C K及回显选项。由于回显选项已 被时间戳选项取代,而目前定义的选择 A C K选项仍未定论,并未包括在 RFC 1323中, 因此图1 8 - 2 0没有将它们列出。另外,作为 T C P事务(第2 4 . 7节)的T / T C P建议也指明 kind为11, 12和 13的三个选项。 18.11 TCP 服务器的设计 我们在1 . 8节说过大多数的T C P服务器进程是并发的。当一个新的连接请求到达服务器时, 服务器接受这个请求,并调用一个新进程来处理这个新的客户请求。不同的操作系统使用不 同的技术来调用新的服务器进程。在 U n i x系统下,常用的技术是使用 f o r k函数来创建新的进 程。如果系统支持,也可使用轻型进程,即线程( t h r e a d)。 我们感兴趣的是 T C P与若干并发服务器的交互作用。需要回答下面的问题:当一个服务 器进程接受一来自客户进程的服务请求时是如何处理端口的?如果多个连接请求几乎同时到 192使用TCP/IP详解,卷1:协议 选项表结束: 1字节 1字节 1字节 1字节 2字节 1字节 1字节 1字节 4字节 4字节 1字节 1字节 移位 数 时间戳值 时间戳回显应答 最大报文段 长度 无操作: 最大报文段长度: 窗口扩大因子: 时间戳:第18章 TCP连接的建立与终止使用193 达会发生什么情况? 18.11.1 TCP服务器端口号 通过观察任何一个 T C P服务器,我们能了解 T C P如何处理端口号。我们使用 n e t s t a t 命令来观察 Te l n e t服务器。下面是在没有 Te l n e t连接时的显示(只留下显示 Te l n e t服务器的 行)。 sun % netstat -a -n -f inet Active Internet connections (including servers) Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp 0 0 *.23 *.* LISTEN - a标志将显示网络中的所有主机端,而不仅仅是处于 E S TA B L I S H E D的主机端。- n标志 将以点分十进制的形式显示 I P地址,而不是通过 D N S将地址转化为主机名,同时还要求显示 端口号(例如为 2 3)而不是服务名称(如 Te l n e t)。-f inet选项则仅要求显示使用 T C P或 U D P的主机。 显示的本地地址为 * . 2 3,星号通常又称为通配符。这表示传入的连接请求(即 S Y N)将 被任何一个本地接口所接收。如果该主机是多接口主机,我们将制定其中的一个 I P地址为本 地I P地址,并且只接收来自这个接口的连接(在本节后面我们将看到这样的例子)。本地端口 为2 3,这是Te l n e t的熟知端口号。 远端地址显示为 * . *,表示还不知道远端 I P地址和端口号,因为该端还处于 L I S T E N状态, 正等待连接请求的到达。 现在我们在主机 s l i p(1 4 0 . 2 5 2 . 1 3 . 6 5)启动一个Te l n e t客户程序来连接这个 Te l n e t服务器。 以下是n e t s t a t程序的输出行: Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp 0 0 140.252.13.33.23 140.252.13.65.1029 ESTABLISHED tcp 0 0 *.23 *.* LISTEN 端口为2 3的第1行表示处于E S TABLISHED 状态的连接。另外还显示了这个连接的本地 I P 地址、本地端口号、远端 I P地址和远端端口号。 本地I P地址为该连接请求到达的接口(以太 网接口,1 4 0 . 2 5 2 . 1 3 . 3 3)。 处于L I S T E N状态的服务器进程仍然存在。这个服务器进程是当前 Te l n e t服务器用于接收 其他的连接请求。当传入的连接请求到达并被接收时,系统内核中的 T C P模块就创建一个处 于E S TA B L I S H E D状态的进程。另外,注意处于 E S TA B L I S H E D状态的连接的端口不会变化: 也是2 3,与处于L I S T E N状态的进程相同。 现在我们在主机s l i p上启动另一个Te l n e t客户进程,并仍与这个 Te l n e t服务器进行连接。以 下是n e t s t a t程序的输出行: Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp 0 0 140.252.13.33.23 140.252.13.65.1030 ESTABLISHED tcp 0 0 140.252.13.33.23 140.252.13.65.1029 ESTABLISHED tcp 0 0 *.23 *.* LISTEN 现在我们有两条从相同主机到相同服务器的处于 E S TA B L I S H E D的连接。它们的本地端口号均 为2 3。由于它们的远端端口号不同,这不会造成冲突。因为每个 Te l n e t客户进程要使用一个外设端口,并且这个外设端口会选择为主机( s l i p)当前未曾使用的端口,因此它们的端口号 肯定不同。 这个例子再次重申 T C P使用由本地地址和远端地址组成的 4元组:目的I P地址、目的端口 号、源I P地址和源端口号来处理传入的多个连接请求。 T C P仅通过目的端口号无法确定那个 进程接收了一个连接请求。另外,在三个使用端口 2 3的进程中,只有处于 L I S T E N的进程能够 接收新的连接请求。处于 E S TA B L I S H E D的进程将不能接收 S Y N报文段,而处于L I S T E N的进 程将不能接收数据报文段。 下面我们从主机s o l a r i s上启动第3个Te l n e t客户进程,这个主机通过 S L I P链路与主机s u n相 连,而不是以太网接口。 Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp 0 0 140.252.1.29.23 140.252.1.32.34603 ESTABLISHED tcp 0 0 140.252.13.33.23 140.252.13.65.1030 ESTABLISHED tcp 0 0 140.252.13.33.23 140.252.13.65.1029 ESTABLISHED tcp 0 0 *.23 *.* LISTEN 现在第一个 E S TA B L I S H E D连接的本地 I P地址对应多地址主机 s u n中的 S L I P链路接口地址 (1 4 0 . 2 5 2 . 1 . 2 9)。 18.11.2 限定的本地IP地址 我们来看看当服务器不能任选其本地 I P地址而必须使用特定的 I P地址时的情况。如果我 们为s o c k程序指明一个 I P地址(或主机名),并将它作为服务器,那么该 I P地址就成为处于 L I S T E N服务器的本地I P地址。例如 sun % sock -s 140.252.1.29 8888 使这个服务器程序的连接仅局限于来自 S L I P接口(1 4 0 . 2 5 2 . 1 . 2 9)。n e t s t a t的显示说明了这 一点: Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp 0 0 140.252.1.29.8888 *.* LISTEN 如果我们从主机s o l a r i s通过S L I P链路与这个服务器相连接,它将正常工作。 Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp 0 0 140.252.1.29.8888 140.252.1.32.34614 ESTABLISHED tcp 0 0 140.252.1.29.8888 *.* LISTEN 但如果我们试图从以太网( 1 4 0 . 2 5 2 . 1 3)中的主机与这个服务器进行连接,连接请求将被 T C P模块拒绝。如果使用t c p d u m p来观察这一切,对连接请求 S Y N的响应是一个如图1 8 - 2 1所 示的R S T。 图18-21 具有限定本地IP地址服务器对连接请求的拒绝 这个连接请求将不会到达服务器的应用程序,因为它根据应用程序中指定的本地 I P地址 被内核中的T C P模块拒绝。 194使用TCP/IP详解,卷1:协议第18章 TCP连接的建立与终止使用195 18.11.3 限定的远端IP地址 在11 . 1 2节,我们知道U D P服务器通常在指定 I P本地地址和本地端口外,还能指定远端 I P 地址和远端端口。RFC 793中显示的接口函数允许一个服务器在执行被动打开时,可指明远端 插口(等待一个特定的客户执行主动打开),也可不指明远端插口(等待任何客户)。 遗憾的是,大多数A P I都不支持这么做。服务器必须不指明远端插口,而等待连接请求的 到来,然后检查客户端的I P地址和端口号。 图1 8 - 2 2总结了T C P服务器进行连接时三种类型的地址绑定。在三种情况中, l p o r t是服务 器的熟知端口,而l o c a l I P必须是一个本地接口的I P地址。表中行的顺序正是 T C P模块在收到一 个连接请求时确定本地地址的顺序。最常使用的绑定(第 1行,如果支持的话)将最先尝试, 最不常用的(最后一行两端的 I P地址都没有制定)将最后尝试。 图18-22 TCP服务器本地和远端IP地址及端口号的规范 18.11.4 呼入连接请求队列 一个并发服务器调用一个新的进程来处理每个客户请求,因此处于被动连接请求的服务 器应该始终准备处理下一个呼入的连接请求。那正是使用并发服务器的根本原因。但仍有可 能出现当服务器在创建一个新的进程时,或操作系统正忙于处理优先级更高的进程时,到达 多个连接请求。当服务器正处于忙时, T C P是如何处理这些呼入的连接请求? 在伯克利的T C P实现中采用以下规则: 1) 正等待连接请求的一端有一个固定长度的连接队列,该队列中的连接已被 T C P接受 (即三次握手已经完成),但还没有被应用层所接受。 注意区分T C P接受一个连接是将其放入这个队列,而应用层接受连接是将其从该队列 中移出。 2) 应用层将指明该队列的最大长度,这个值通常称为积压值 ( b a c k l o g )。它的取值范围是 0 ~ 5之间的整数,包括0和5(大多数的应用程序都将这个值说明为 5)。 3) 当一个连接请求(即S Y N)到达时,T C P使 用一个算法,根据当前连接队列中的连接数 来确定是否接收这个连接。我们期望应用层 说明的积压值为这一端点所能允许接受连接 的最大数目,但情况不是那么简单。图1 8 - 2 3 显示了积压值与传统的伯克利系统和 S o l a r i s 2 . 2所能允许的最大接受连接数之间的关系。 注意,积压值说明的是 T C P监听的端点已 被T C P接受而等待应用层接受的最大连接数。这个积压值对系统所允许的最大连接数, 或者并发服务器所能并发处理的客户数,并无影响。 在这个图中,S o l a r i s系统规定的值正如我们所期望的。而传统的B S D系统,将这个 本地地址 远端地址 描 述 限制到一个客户进程(通常不支持) 限制为到达一个本地接口:Local IP的连接 接收发往Lport的所有连接 图18-23 对正在听的端点所允许接受的 最大连接数 积压值 最大排队的连接数 传统的BSD值(由于某些原因)设置为积压值乘3除以2,再加1。 4) 如果对于新的连接请求,该 T C P监听的端点的连接队列中还有空间(基于图 1 8 - 2 3), T C P模块将对S Y N进行确认并完成连接的建立。但应用层只有在三次握手中的第三个 报文段收到后才会知道这个新连接时。另外,当客户进程的主动打开成功但服务器的 应用层还不知道这个新的连接时,它可能会认为服务器进程已经准备好接收数据了 (如果发生这种情况,服务器的 T C P仅将接收的数据放入缓冲队列 )。 5) 如果对于新的连接请求,连接队列中已没有空间, T C P将不理会收到的 S Y N。也不发 回任何报文段(即不发回 R S T)。如果应用层不能及时接受已被 T C P接受的连接,这些 连接可能占满整个连接队列,客户的主动打开最终将超时。 通过s o c k程序能了解这种情况。我们调用它,并使用新的选项( - O)。让它在创建一个 新的服务器进程后而没有接受任何连接请求之前暂停下来。如果在它暂停期间又调用了多个 客户进程,它将导致接受连接队列被填满,通过 t c p d u m p能够看到这一切。 bsdi % sock -s -v -q1 -O30 5555 - q 1选项将服务器端的积压值置 1。在这种情况下,传统的 B S D系统中的队列允许接受两 个连接请求(图 1 8 - 2 3)。- O 3 0选项使程序在接受任何客户连接之前暂停 3 0秒。在这3 0秒内, 我们可启动其他客户进程来填充这个队列。在主机 s u n上启动4个客户进程。 图1 8 - 2 4显示了 t c p d u m p的输出,首先是第 1个客户进程的第 1个S Y N(省略窗口大小和 M S S声明。当T C P连接建立时,将客户进程的端口号用粗体标出)。 端口为1 0 9 0的第一个客户连接请求被 T C P接受(报文段1 ~ 3)。端口为1 0 9 1的第2个客户连 接请求也被 T C P接受(报文段 4 ~ 6)。而服务器的应用仍处于休眠状态,还未接受任何连接。 目前的一切工作都由内核中的 T C P模块完成。另外,两个客户进程已经成功地完成了它们的 主动打开,因为它们建立连接的三次握手已经完成。 图18-24 积压值例子的t c p d u m p 输出 196使用TCP/IP详解,卷1:协议我们接着在报文段 7(端口1 0 9 2)和报文段8(端口1 0 9 3)启动第3和第4个客户进程。由 于服务器的连接队列已满, T C P将不理会两个S Y N。这两个客户进程在报文段 9, 10, 11, 12, 15 重发它们的S Y N。第4个客户进程的第 3个S Y N重传被接受了,因为服务器程序的 3 0秒休眠结 束后,它将已接受的两个连接从队列中移出,使连接队列变空(服务器程序接收连接的时间 是2 8 . 1 9,小于3 0的原因在于启动服务器程序后它需要几秒的时间来启动第 1个客户进程(报文 段1,显示的就是启动时间))。第3个客户进程的第4个S Y N重传这时将被接受(报文段1 5 ~ 1 7)。 服务器程序先接受第4个客户连接(端口1 0 9 3)的原因是服务器程序 3 0秒休眠与客户程序重传 之间的定时交互作用。 我们期望接收连接队列按先进先出顺序传递给应用层。如 T C P接受了端口为1 0 9 0 和1 0 9 1的连接,我们希望应用层先接受端口为 1 0 9 0的连接,然后再接受端口为1 0 9 1的 连接。但许多伯克利的T C P实现都出现按后进先出的传递顺序,这个错误已存在了多 年。产商最近已开始改正这个错误,但在如SunOS 4.13等系统中仍存在这个问题。 当队列已满时,T C P将不理会传入的S Y N,也不发回R S T作为应答,因为这是一个软错误, 而不是一个硬错误。通常队列已满是由于应用程序或操作系统忙造成的,这样可防止应用程 序对传入的连接进行服务。这个条件在一个很短的时间内可以改变。但如果服务器的 T C P以 系统复位作为响应,客户进程的主动打开将被废弃(如果服务器程序没有启动我们就会遇到)。 由于不应答S Y N,服务器程序迫使客户 T C P随后重传S Y N,以等待连接队列有空间接受新的 连接。 这个例子中有一个巧妙之处,这在大多 T C P / I P的具体实现中都能见到,就是如果服务器 的连接队列未满时, T C P将接受传入的连接请求(即 S Y N),但并不让应用层了解该连接源于 何处(即不告知源 I P地址和源端口)。这不是T C P所要求的,而只是共同的实现技术(如伯克 利源代码通常都这么做)。如果一个A P I如T L I(见1 . 1 5节)向应用程序提供了解连接请求的到 来的方法,并允许应用程序选择是否接受连接。当应用程序假定被告知连接请求已经到来时, T C P的三次握手已经结束!其他运输层的实现可能将连接请求的到达与接受分开(如 O S I的运 输层),但T C P不是这样。 Solaris 2.2 提供了一个选项使 T C P只有在应用程序说可以接受( t c p _ e a g e r _ l i s t e n e r s见E . 4),才允许接受传入的连接请求。 这种行为也意味着 T C P服务器无法使客户进程的主动打开失效。当一个新的客户连接传 递给服务器的应用程序时, T C P的三次握手就结束了,客户的主动打开已经完全成功。如果 服务器的应用程序此时看到客户的 I P地址和端口号,并决定是否为该客户进行服务,服务器 所能做的就是关闭连接(发送 F I N),或者复位连接(发送 R S T)。无论哪种情况,客户进程都 认为一切正常,因为它的主动打开已经完成,并且已经向服务器程序发送过请求。 18.12 小结 两个进程在使用 T C P交换数据之前,它们之间必须建立一条连接。完成后,要关闭这 个连接。本章已经详细介绍了如何使用三次握手来建立连接以及使用 4个报文段来关闭连 接。 我们用t c p d u m p程序显示了T C P首部中的各个字段。也了解了连接建立是如何超时,连 第18章 TCP连接的建立与终止使用197接复位是如何发送,使用半打开连接发生的情况以及 T C P是如何提供半关闭、同时打开和同 时关闭。 弄清T C P操作的关键在于它的状态变迁图。我们跟踪了连接建立与关闭的步骤以及它们的 状态变迁过程。还讨论了在设计T C P并发服务器时T C P连接建立的具体实现方法。 一个T C P连接由一个4元组唯一确定:本地 I P地址、本地端口号、远端 I P地址和远端端口 号。无论何时关闭一个连接,一端必须保持这个连接,我们看到 T I M E _ WA I T状态将处理这个 问题。处理的原则是执行主动打开的一端在进入这个状态时要保持的时间为 T C P实现中规定 的M S L值的两倍。 习题 18.1 在1 8 . 2节我们说初始序号( I S N)正常情况下由1开始,并且每0 . 5秒增加6 4 0 0 0,每次执 行一个主动打开。这意味着 I S N的最低三位通常总是 0 0 1。但在图1 8 - 3中,两个方向上 I S N中的最低三位都是5 2 1。究竟是怎么回事? 18.2 在图1 8 - 1 5中,我们键入 1 2个字符,看到 T C P发送了1 3个字节。在图 1 8 - 1 6中我们键入8 个字符,但T C P发送了1 0个字符。为什么在第 1种情况下增加1个字节,而在第 2种情况 下增加2个字节? 18.3 半打开连接和半关闭连接的区别是什么? 18.4 如果启动s o c k程序作为一个服务器程序,然后终止它(还没有客户进程与它相连接), 我们能立即重新启动这个服务器程序。这意味着它没有经历 2 M S L等待状态。用状态变 迁来解释这一切。 18.5 在1 8 . 6节我们知道一个客户进程不能重新使用同一个本地端口,如果该端口是仍处于 2 M S L等待连接的一部分。但如果 s o c k程序作为客户程序连续运行两次,并且连接到 d a y t i m e服务器上,我们就能重新使用同一本地端口。另外,对一个仍处于 2 M S L等待的 连接,也能为它创建一个替身。这将如何做? 18.6 在1 8 . 6节的最后,我们介绍了 F I N _ WA I T _ 2状态,提到如果应用程序仅过 11分钟后实行 完全关闭(不是半关闭),许多具体的实现都将一个连接由这个状态转移到 C L O S E D状 态。如果另一端(处于 C L O S E _ WA I T状态)在宣布关闭(即发送 F I N)之前等待了1 2分 钟,这一端的T C P将如何响应这个F I N? 18.7 对于一个电话交谈,哪一方是主动打开,哪一方是被动打开?是否允许同时打开?是否 允许同时关闭? 18.8 在图1 8 - 6中,我们没有见到一个A R P请求或一个A R P应答。显然主机s v r 4的硬件地址一 定在b s d i的A R P高速缓存中。如果这个A R P高速缓存不存在,这个图会有什么变化? 18.9 解释如下的t c p d u m p输出,并和图1 8 - 1 3进行比较。 198使用TCP/IP详解,卷1:协议 重用相同的本地端口号18.10 为什么图1 8 - 4中的服务器不将对客户 F I N的A C K与自己的F I N合并,从而将报文段数减 少为3个? 1 8 . 11 在图1 8 - 1 6中,R S T的序号为什么是2 6 3 6 8 0 0 2 ? 18.12 TCP向链路层查询M T U是否违反分层的规则? 18.13 假定在图1 4 . 1 6中,每个D N S使用T C P而不是U D P进行查询,试问需要交换多少个报文 段? 18.14 假定M S L为1 2 0秒,试问系统能够初始化一个新连接然后进行主动关闭的最大速率是多 少? 18.15 阅读RFC 793,分析处于T I M E _ WA I T状态的主机收到使其进入此状态的重复的 F I N时 所发生的情况。 18.16 阅读RFC 793,分析处于T I M E _ WA I T状态的主机收到一个R S T时所发生的情况。 18.17 阅读Host Requirements RFC并找出半双工T C P关闭的定义。 18.18 在图1 - 8中,我们曾提到到来的 T C P报文段可根据其目的端口号进行分用,请问这种说 法是否正确? 第18章 TCP连接的建立与终止使用199第19章 TCP的交互数据流 19.1 引言 前一章我们介绍了 T C P连接的建立与释放,现在来介绍使用 T C P进行数据传输的有关问 题。 一些有关T C P通信量的研究如[Caceres et al. 1991]发现,如果按照分组数量计算,约有一 半的T C P报文段包含成块数据(如 F T P、电子邮件和 U s e n e t新闻),另一半则包含交互数据 (如Te l n e t和R l o g i n)。如果按字节计算,则成块数据与交互数据的比例约为 9 0 %和1 0 %。这是 因为成块数据的报文段基本上都是满长度( f u l l - s i z e d)的(通常为5 1 2字节的用户数据),而 交互数据则小得多(上述研究表明 Te l n e t和R l o g i n分组中通常约9 0 %左右的用户数据小于 1 0个 字节)。 很明显,T C P需要同时处理这两类数据,但使用的处理算法则有所不同。本章将以 R l o g i n 应用为例来观察交互数据的传输过程。将揭示经受时延的确认是如何工作的以及 N a g l e算法怎 样减少了通过广域网络传输的小分组的数目,这些算法也同样适用于 Te l n e t应用。下一章我们 将介绍成块数据的传输问题。 19.2 交互式输入 首先来观察在一个 R l o g i n连接上键入一个交互命令时所产生的数据流。许多 T C P / I P的初 学者很吃惊地发现通常每一个交互按键都会产生一个数据分组,也就是说,每次从客户传到 服务器的是一个字节的按键(而不是每次一行)。而且,R l o g i n需要远程系统(服务器)回显 我们(客户)键入的字符。这样就会产 生4个报文段:(1)来自客户的交互按 键;(2)来自服务器的按键确认;(3) 来自服务器的按键回显;( 4)来自客 户的按键回显确认。图 1 9 - 1表示了这个 数据流。 然而,我们一般可以将报文段 2和 3进行合并— 按键确认与按键回显一 起发送。下一节将描述这种合并的技术 (称为经受时延的确认)。 本章我们特意使用 R l o g i n作为例 子,因为它每次总是从客户发送一个字节到服务器。在第 2 6章讲到Te l n e t的时候,将会发现它 有一个选项允许客户发送一行到服务器,通过使用这个选项可以减少网络的负载。 图1 9 - 2显示的是当我们键入5个字符d a t e \ n时的数据流(我们没有显示连接建立的过程, 并且去掉了所有的服务类型输出。 B S D / 3 8 6通过设置一个R l o g i n连接的TO S来获得最小时延)。 服务器 按键 客户 服务器 显示 回显 图19-1 一种可能的处理远程交互按键回显的方法第19章 TCP的交互数据流使用201 第1行客户发送字符d到服务器。第2行是该字符的确认及回显(也就是图 1 9 - 1的中间两部分数 据的合并)。第3行是回显字符的确认。与字符 a有关的是第4 ~ 6行,与字符t有关的是第7 ~ 9行, 第1 0 ~ 1 2行与字符e有关。第3 ~ 4、6 ~ 7、9 ~ 1 0和1 2 ~ 1 3行之间半秒左右的时间差是键入两个字 符之间的时延。 注意到1 3 ~ 1 5行稍有不同。从客户发送到服务器的是一个字符(按下 R E T U R N键后产生的 U N I X系统中的换行符),而回显的则是两个字符。这两个字符分别是回车和换行字符 (C R / L F),它们的作用是将光标回移到左边并移动到下一行。 第1 6行是来自服务器的d a t e命令的输出。这3 0个字节由2 8个字符与最后的C R / L F组成。紧 接着从服务器发往客户的7个字符(第1 8行)是在服务器主机上的客户提示符: svr4 % 。第1 9 行确认了这7个字符。 图19-2 当在Rlogin连接上键入date时的数据流 注意T C P是怎样进行确认的。第 1行以序号0发送数据字节,第 2行通过将确认序号设为 1, 也就是最后成功收到的字节的序号加 1,来对其进行确认(也就是所谓的下一个期望数据的序 号)。在第2行中服务器还向客户发送了一序号为 1的数据,客户在第 3行中通过设置确认序号 为2来对该数据进行确认。 19.3 经受时延的确认 在图1 9 - 2中有一些与本节将要论及的时间有关的细微之处。图 1 9 - 3表示了图1 9 - 2中数据交 换的时间系列(在该时间系列中,去掉了所有的窗口通告,并增加了一个记号来表明正在传 输何种数据)。 把从b s d i发送到s r v 4的7个A C K标记为经受时延的A C K。通常T C P在接收到数据时并不 立即发送A C K;相反,它推迟发送,以便将 A C K与需要沿该方向发送的数据一起发送(有时 称这种现象为数据捎带 A C K)。绝大多数实现采用的时延为 200 ms,也就是说,T C P将以最大 200 ms 的时延等待是否有数据一起发送。 如果观察b s d i接收到数据和发送A C K之间的时间差,就会发现它们似乎是随机的: 1 2 3 . 5、202使用TCP/IP详解,卷1:协议 6 5 . 6、1 0 9 . 0、1 3 2 . 2、4 2 . 0、1 4 0 . 3和195.8 ms。相反,观察到发送A C K的实际时间(从0开始) 为:1 3 9 . 9、5 3 9 . 3、9 4 0 . 1、1 3 3 9 . 9、1 7 3 9 . 9、1 9 4 0 . 1和2140.1 ms(在图1 9 - 3中用星号标出)。 这些时间之间的差则是 200 ms的整数倍,这里所发生的情况是因为 T C P使用了一个200 ms的 定时器,该定时器以相对于内核引导的 200 ms固定时间溢出。由于将要确认的数据是随机到 达的(在时刻 16.4, 474.3, 831.1等),T C P在内核的200 ms定时器的下一次溢出时得到通知。 这有可能是将来1~200 ms中的任何一刻。 图19-3 在rlogin连接上键入date命令时的数据流时间系列 如果观察s v r 4为产生所收到的每个字符的回显所使用的时间,则这些时间分别为 1 6 . 5、 1 6 . 3、1 6 . 5、1 6 . 4和17.3 ms。由于这个时间小于200 ms,因此我们在另一端从来没有观察到一 个经受时延的A C K。在经受时延的定时器溢出前总是有数据需要发送(如果有一个约为 16 ms 等待时间越过了内核的 200 ms时钟滴答的边界,则仍可以看到一个经受时延的 A C K。在本例 中我们一个也没有看到)。 在图1 8 - 7中,当为检测超时而使用500 ms的T C P定时器时,我们会看到同样的情况。这两 时延的确认 时延的确认 时延的确认 时延的确认 时延的确认 时延的确认 时延的确认 (新行)第19章 TCP的交互数据流使用203 个200 ms和500 ms的定时器都在相对于内核引导的时间处溢出。不论 T C P何时设置一个定时 器,该定时器都可能在将来 1~200 ms和1~500 ms的任一处溢出。 Host Requirements RFC声明T C P需要实现一个经受时延的A C K,但时延必须小于 500 ms。 19.4 Nagle算法 在前一节我们看到 , 在一个R l o g i n连接上客户一般每次发送一个字节到服务器,这就产生 了一些4 1字节长的分组:2 0字节的I P首部、2 0字节的T C P首部和1个字节的数据。在局域网上, 这些小分组(被称为微小分组( t i n y g r a m))通常不会引起麻烦,因为局域网一般不会出现拥 塞。但在广域网上,这些小分组则会增加拥塞出现的可能。一种简单和好的方法就是采用 RFC 896 [Nagle 1984]中所建议的N a g l e算法。 该算法要求一个 T C P连接上最多只能有一个未被确认的未完成的小分组,在该分组的确 认到达之前不能发送其他的小分组。相反, T C P收集这些少量的分组,并在确认到来时以一 个分组的方式发出去。该算法的优越之处在于它是自适应的:确认到达得越快,数据也就发 送得越快。而在希望减少微小分组数目的低速广域网上,则会发送更少的分组(我们将在 2 2 . 3节看到“小”的含义是小于报文段的大小)。 在图1 9 - 3中可以看到,在以太网上一个字节被发送、确认和回显的平均往返时间约为 1 6 m s。为了产生比这个速度更快的数据,我们每秒键入的字符必须多于 6 0个。这表明在局域网 环境下两个主机之间发送数据时很少使用这个算法。 但是,当往返时间( RT T)增加时,如通过一个广域网,情况就会发生变化。看一下在 主机s l i p和主机v a n g o g h . c s . b e r k e l e y . e d u之间的R l o g i n连接工作的情况。为了从我们 的网络中出去(参看原书封面内侧),需要使用两个 S L I P链路和I n t e r n e t。我们希望获得更长 的往返时间。图 1 9 - 4显示了当在客户端快速键入字符(像一个快速打字员一样)时一些数据 流的时间系列(去掉了服务类型信息,但保留了窗口通告)。 比较图1 9 - 4与图1 9 - 3,我们首先注意到从s l i p到v a n g o g h不存在经受时延的A C K。这是 因为在时延定时器溢出之前总是有数据等待发送。 其次,注意到从左到右待发数据的长度是不同的,分别为: 1、1、2、1、2、2、3、1和3 个字节。这是因为客户只有收到前一个数据的确认后才发送已经收集的数据。通过使用 N a g l e 算法,为发送1 6个字节的数据客户只需要使用 9个报文段,而不再是1 6个。 报文段1 4和1 5看起来似乎是与N a g l e算法相违背的,但我们需要通过检查序号来观察其中 的真相。因为确认序号是 5 4,因此报文段1 4是报文段1 2中确认的应答。但客户在发送该报文 段之前,接收到了来自服务器的报文段 1 3,报文段1 5中包含了对序号为5 6的报文段1 3的确认。 因此即使我们看到从客户到服务器有两个连续返回的报文段,客户也是遵守了 N a g l e算法的。 在图1 9 - 4中可以看到存在一个经受时延的 A C K,但该A C K是从服务器到客户的(报文段 1 2),因为它不包含任何数据,因此我们可以假定这是经受时延的 A C K。服务器当时一定非常 忙,因此无法在服务器的定时器溢出前及时处理所收到的字符。 最后看一下最后两个报文段中数据的数量以及相应的序号。客户发送 3个字节的数据(1 8 , 1 9和2 0),然后服务器确认这 3个字节(最后的报文段中的 ACK 21),但是只返回了一个字节 (标号为5 9)。这是因为当服务器的T C P一旦正确收到这3个字节的数据,就会返回对该数据的确204使用TCP/IP详解,卷1:协议 认,但只有当R l o g i n服务器发送回显数据时,它才能够发送这些数据的回显。这表明 T C P可以 在应用读取并处理数据前发送所接收数据的确认。 T C P确认仅仅表明T C P已经正确接收了数据。 最后一个报文段的窗口大小为8 1 8 9而非8 1 9 2,表明服务器进程尚未读取这三个收到的数据。 图19-4 在s l i p 和v a n g o g h . c s . b e r k e l e y . e d u 之间使用r l o g i n 时的数据流 19.4.1 关闭Nagle算法 有时我们也需要关闭 N a g l e算法。一个典型的例子是 X窗口系统服务器(见 3 0 . 5节):小消 息(鼠标移动)必须无时延地发送,以便为进行某种操作的交互用户提供实时的反馈。 这里将举另外一个更容易说明的例子— 在一个交互注册过程中键入终端的一个特殊功 能键。这个功能键通常可以产生多个字符序列,经常从 A S C I I码的转义( e s c a p e )字符开始。如 果T C P每次得到一个字符,它很可能会发送序列中的第一个字符( A S C I I码的E S C),然后缓 存其他字符并等待对该字符的确认。但当服务器接收到该字符后,它并不发送确认,而是继 续等待接收序列中的其他字符。这就会经常触发服务器的经受时延的确认算法,表示剩下的 字符没有在200 ms内发送。对交互用户而言,这将产生明显的时延。 插口API用户可以使用T C P _ N O D E L A Y选项来关闭Nagle算法。 Host Requirements RFC声明T C P必须实现N a g l e算法,但必须为应用提供一种方法 来关闭该算法在某个连接上执行。19.4.2 一个例子 可以在N a g l e算法和产生多个字符的按键之间看到这种交互的情况。在主机 s l i p和主机 v a n g o g h . c s . b e r k e l e y . e d u之间建立一个R l o g i n连接,然后按下F 1功能键,这将产生3个 字节:一个e s c a p e、一个左括号和一个 M。然后再按下F 2功能键,这将产生另外 3个字节。图 1 9 - 5表示的是t c p d u m p的输出结果(我们去掉了其中的服务类型和窗口通告)。 图19-5 当键入能够产生多个字节数据的字符时Nagle算法的观察情况 图1 9 - 6表示了这个交互过程的时间系列。在该图的下面部分我们给出了从客户发送到服 务器的6个字节和它们的序号以及将要返回的 8个字节的回显。 图19-6 图19-5的时间系列(Nagle算法的观察结果) 第19章 TCP的交互数据流使用205 按F1 按F2 F2键 F1键 F1的回显 F2的回显 按F1键 按F2键206使用TCP/IP详解,卷1:协议 当r l o g i n客户读取到输入的第1个字节并向T C P写入时,该字节作为报文段 1被发送。这 是F 1键所产生的3个字节中的第1个。它的回显在报文段 2中被返回,此时剩余的 2个字节才被 发送(报文段3)。这两个字节的回显在报文段 4被接收,而报文段5则是对它们的确认。 第1个字节的回显为2个字节(报文段2)的原因是因为在A S C I I码中转义符的回显是2个字 节:插入记号和一个左括号。剩下的两个输入字节:一个左括号和一个 M,分别以自身作为 回显内容。 当按下下一个特殊功能键(报文段 6 ~ 1 0)时,也会发生同样的过程。正如我们希望的那 样,在报文段 5和1 0(s l i p发送回显的确认)之间的时间差是 200 ms的整数倍,因为这两个 A C K被进行时延。 现在我们使用一个修改后关闭了 N a g l e算法的r l o g i n版本重复同样的实验。图 1 9 - 7显示 了t c p d u m p的输出结果(同样去掉了其中的服务类型和窗口通告)。 图19-7 在一个Rlogin会话中关闭Nagle算法 在已知某些报文段在网络上形成交叉的情况下,以该结果构造时间系列则更具有启发性 和指导意义。这个例子同样也需要随着数据流对序号进行仔细的检查。在图 1 9 - 8中显示这个 结果。用图1 9 - 7中t c p d u m p输出的号码对报文段进行了相应的编号。 我们注意到的第 1个变化是当3个字节准备好时它们全部被发送(报文段 1、2和3)。没有 时延发生— N a g l e算法被禁止。 在t c p d u m p输出中的下一个分组(报文段 4)中带有来自服务器的第 5个字节及一个确认 序号为4的A C K。这是不正确的,因为客户并不希望接收到第 5个字节,因此它立即发送一个 确认序号为2而不是6的响应(没有被延迟)。看起来一个报文段丢失了,在图 1 9 - 8中我们用虚 线表示。 如何知道这个丢失的报文段中包含第 2、3和4个字节,且其确认序号为 3呢?这是因为正 如在报文段5中声明的那样,我们希望的下一个字节是第 2个字节(每当 T C P接收到一个超出 期望序号的失序数据时,它总是发送一个确认序号为其期望序号的确认)。也正是因为丢失的 分组中包含第 2、3和4个字节,表明服务器必定已经接收到报文段 2,因此丢失的报文段中的 确认序号一定为3(服务器期望接收的下一个字节号)。最后,注意到重传的报文段 6中包含有 丢失的报文段中的数据和报文段 4,这被称为重新分组化。我们将在 2 2 . 11节对其进行更多的 介绍。 按F1键 按F2键现在回到禁止 N a g l e算法的讨论中来。可以观察到键入的下一个特殊功能键所产生的 3个 字节分别作为单独的报文段(报文段 8、9和1 0)被发送。这一次服务器首先回显了报文段 8中 的字节(报文段11),然后回显了报文段9和1 0中的字节(报文段1 2)。 在这个例子中,我们能够观察到的是在跨广域网运行一个交互应用的环境下,当进行多 字节的按键输入时,默认使用 N a g l e算法会引起额外的时延。 在第2 1章我们将进行有关时延和重传方面的讨论。 图19-8 图19-7的时间系列(关闭Nagle算法) 19.5 窗口大小通告 在图1 9 - 4中,我们可以观察到 s l i p通告窗口大小为4 0 9 6字节,而v a n g o g h通告其窗口大 小为8 1 9 2个字节。该图中的大多数报文段都包含这两个值中的一个。 第19章 TCP的交互数据流使用207 按F1 按F2 F2键 F1键 F1的回显 F2的回显 超时并重传然而,报文段5通告的窗口大小为 4 0 9 5个字节,这意味着在 T C P的缓冲区中仍然有一个字 节等待应用程序( R l o g i n客户)读取。同样,来自客户的下一个报文段声明其窗口大小为 4 0 9 4个字节,这说明仍有两个字节等待读取。 服务器通常通告窗口大小为 8 1 9 2个字节,这是因为服务器在读取并回显接收到的数据之 前,其T C P没有数据发送。当服务器已经读取了来自客户的输入后,来自服务器的数据将被 发送。 然而,在A C K到来时,客户的 T C P总是有数据需要发送。这是因为它在等待 A C K的过程 中缓存接收到的字符。当客户 T C P发送缓存的数据时,R l o g i n客户没有机会读取来自服务器的 数据,因此,客户通告的窗口大小总是小于 4 0 9 6。 19.6 小结 交互数据总是以小于最大报文段长度的分组发送。在 R l o g i n中通常只有一个字节从客户发 送到服务器。Te l n e t允许一次发送一行输入数据,但是目前大多数实现仍然发送一个字节。 对于这些小的报文段,接收方使用经受时延的确认方法来判断确认是否可被推迟发送, 以便与回送数据一起发送。这样通常会减少报文段的数目,尤其是对于需要回显用户输入字 符的R l o g i n会话。 在较慢的广域网环境中,通常使用 N a g l e算法来减少这些小报文段的数目。这个算法限制 发送者任何时候只能有一个发送的小报文段未被确认。但我们给出的一个例子也表明有时需 要禁止N a g l e算法的功能。 习题 19.1 考虑一个 T C P客户应用程序,它发送一个小应用程序首部( 8个字节)和一个小请求 (1 2个字节),然后等待来自服务器的一个应答。比较以下两种方式发送请求时的处理情 况:先发送8个字节再发送1 2个字节和一次发送2 0个字节。 19.2 图1 9 - 4中我们在路由器s u n上运行t c p d u m p。这意味着从右至左的箭头中的数据也需要 经过b s d i,同时从左至右的箭头中的数据已经流经 b s d i。当观察一个送往 s l i p的报文 段及下一个来自 s l i p的报文段时,我们发现它们之间的时间差分别为: 3 4 . 8、2 6 . 7、 3 0 . 1、2 8 . 1、2 9 . 9和35.3 ms。现给定在s u n和s l i p之间存在两条链路(一个以太链路和 一个9600 b/s的C S L I P链路),试问这些时间差的含义(提示:重新阅读 2 . 1 0节)。 19.3 比较在使用N a g l e算法(图1 9 - 6)和禁止N a g l e算法(图1 9 - 8)的情况下发送一个特殊功 能键并等待其应答所需要的时间。 208使用TCP/IP详解,卷1:协议第20章 TCP的成块数据流 20.1 引言 在第1 5章我们看到T F T P使用了停止等待协议。数据发送方在发送下一个数据块之前需要 等待接收对已发送数据的确认。本章我们将介绍 T C P所使用的被称为滑动窗口协议的另一种 形式的流量控制方法。该协议允许发送方在停止并等待确认前可以连续发送多个分组。由于 发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输。 我们还将介绍T C P的P U S H标志,该标志在前面的许多例子中都出现过。此外,我们还要 介绍慢启动,T C P使用该技术在一个连接上建立数据流,最后介绍成块数据流的吞吐量。 20.2 正常数据流 我们以从主机s v r 4单向传输8 1 9 2个字节到主机 b s d i开始。在b s d i上运行s o c k程序作 为服务器: bsdi % sock -i -s 7777 其中,标志- i和- s指示程序作为一个“吸收( s i n k)”服务器运行(从网络上读取并丢弃 数据),服务器端口指明为7 7 7 7。相应的客户程序运行为: svr4 % sock -i -n8 bsdi 7777 该命令指示客户向网络发送 8个1 0 2 4字节的数据。图2 0 - 1显示了这个过程的时间系列。我 们在输出的前3个报文段中显示了每一端M S S的值。 发送方首先传送3个数据报文段(4 ~ 6)。下一个报文段(7)仅确认了前两个数据报文段, 这可以从其确认序号为2 0 4 8而不是3 0 7 3看出来。 报文段7的A C K的序号之所以是2 0 4 8而不是3 0 7 3是由以下原因造成的:当一个分组到达时, 它首先被设备中断例程进行处理,然后放置到 I P的输入队列中。三个报文段 4、5和6依次到达 并按接收顺序放到 I P的输入队列。 I P将按同样顺序将它们交给 T C P。当T C P处理报文段4时, 该连接被标记为产生一个经受时延的确认。 T C P处理下一报文段(5),由于T C P现在有两个未 完成的报文段需要确认,因此产生一个序号为 2 0 4 8的A C K(报文段7),并清除该连接产生经 受时延的确认标志。 T C P处理下一个报文段( 6),而连接又被标志为产生一个经受时延的确 认。在报文段9到来之前,由于时延定时器溢出,因此产生一个序号为 3 0 7 3的A C K(报文段8)。 报文段8中的窗口大小为3 0 7 2,表明在T C P的接收缓存中还有1 0 2 4个字节的数据等待被应用程 序读取。 报文段11 ~ 1 6说明了通常使用的“隔一个报文段确认”的策略。报文段 11、1 2和1 3到达并 被放入I P的接收队列。当报文段 11被处理时,连接被标记为产生一个经受时延的确认。当报 文段1 2被处理时,它们的 A C K(报文段1 4)被产生且连接的经受时延的确认标志被清除。报 文段1 3使得连接再次被标记为产生经受时延。但在时延定时器溢出之前,报文段 1 5处理完毕, 因此该确认立刻被发送。图20-1 从s v r 4 传输8192个字节到b s d i 注意到报文段7、1 4和1 6中的A C K确认了两个收到的报文段是很重要的。使用 T C P的滑动 窗口协议时,接收方不必确认每一个收到的分组。在 T C P中,A C K是累积的— 它们表示接 收方已经正确收到了一直到确认序号减 1的所有字节。在本例中,三个确认的数据为 2 0 4 8字节 而两个确认的数据为1 0 2 4字节(忽略了连接建立和终止中的确认)。 用t c p d u m p看到的是T C P的动态活动情况。我们在线路上看到的分组顺序依赖于许多无 法控制的因素:发送方T C P的实现、接收方T C P的实现、接收进程读取数据(依赖于操作系统 的调度)和网络的动态性(如以太网的冲突和退避等)。对这两个T C P而言,没有一种单一的、 正确的方法来交换给定数量的数据。 为显示情况可能怎样变化,图 2 0 - 2显示了在同样两个主机之间交换同样数据时的另一个 时间系列,它们是在图2 0 - 1所示的几分钟之后截获的。 一些情况发生了变化。这一次接收方没有发送一个序号为 3 0 7 3的A C K,而是等待并发送 序号为4 0 9 7的A C K。接收方仅发送了 4个A C K(报文段7、1 0、1 2和1 5):三个确认了2 0 4 8字 210使用TCP/IP详解,卷1:协议节,另一个确认了 1 0 2 4字节。最后1 0 2 4字节数据的A C K出现在报文段1 7中,它与F I N的A C K 一道发送(比较该图中的报文段 1 7与图2 0 - 1中的报文段1 6和1 8)。 图20-2 从s v r 4 到b s d i 的另外8192字节数据的传输过程 快的发送方和慢的接收方 图2 0 - 3显示了另外一个时间系列。这次是从一个快的发送方(一个 S p a r c工作站)到一个 慢的接收方(配有慢速以太网卡的 8 0 3 8 6机器)。它的动态活动情况又有所不同。 发送方发送4个背靠背(b a c k - t o - b a c k)的数据报文段去填充接收方的窗口,然后停下来 等待一个A C K。接收方发送 A C K(报文段8),但通告其窗口大小为 0,这说明接收方已收到 所有数据,但这些数据都在接收方的 T C P缓冲区,因为应用程序还没有机会读取这些数据。 另一个A C K(称为窗口更新)在17.4 ms后发送,表明接收方现在可以接收另外的 4 0 9 6个字节 的数据。虽然这看起来像一个 A C K,但由于它并不确认任何新数据,只是用来增加窗口的右 边沿,因此被称为窗口更新。 发送方发送最后4个报文段(1 0 ~ 1 3),再次填充了接收方的窗口。注意到报文段 1 3中包括 两个比特标志:P U S H和F I N。随后从接收方传来另外两个 A C K,它们确认了最后的 4 0 9 6字节 的数据(从4 0 9 7到8 1 9 2字节)和F I N(标号为8 1 9 2)。 第20章 TCP的成块数据流使用211图20-3 从一个快发送方发送8192字节的数据到一个慢接收方 20.3 滑动窗口 图2 0 - 4用可视化的方法显示了我们在前一节观察到的滑动窗口协议。 图20-4 TCP滑动窗口的可视化表示 在这个图中,我们将字节从 1至11进行标号。接收方通告的窗口称为提出的窗口( o ff e r e d w i n d o w),它覆盖了从第4字节到第9字节的区域,表明接收方已经确认了包括第 3字节在内的 数据,且通告窗口大小为 6。回顾第1 7章,我们知道窗口大小是与确认序号相对应的。发送方 计算它的可用窗口,该窗口表明多少数据可以立即被发送。 当接收方确认数据后,这个滑动窗口不时地向右移动。窗口两个边沿的相对运动增加或 减少了窗口的大小。我们使用三个术语来描述窗口左右边沿的运动: 212使用TCP/IP详解,卷1:协议 提供的窗口 由接收方通告 可用的窗口 发送并被确认 发送,但未被确认 直至窗口移动 不能够发送, 能够发送ASAP1) 称窗口左边沿向右边沿靠近为窗口合拢。这种现象发生在数据被发送和确认时。 2) 当窗口右边沿向右移动时将允许发送更多的数据,我们称之为窗口张开。这种现象发 生在另一端的接收进程读取已经确认的数据并释放了 T C P的接收缓存时。 3) 当右边沿向左移动时,我们称之为窗口收缩。 Host Requirements RFC强烈建议不要使 用这种方式。但T C P必须能够在某一端产生这种情况时进行处理。第 2 2 . 3节给出了这样的一个 例子,一端希望向左移动右边沿来收缩窗口,但没能够这样做。 图2 0 - 5表示了这三种情况。因为窗口的左边 沿受另一端发送的确认序号的控制,因此不可能 向左边移动。如果接收到一个指示窗口左边沿向 左移动的 A C K,则它被认为是一个重复 A C K, 并被丢弃。 如果左边沿到达右边沿,则称其为一个零窗口,此时发送方不能够发送任何数据。 一个例子 图2 0 - 6显示了在图2 0 - 1所示的数据传输过程中滑动窗口协议的动态性。 图20-6 图20-1的滑动窗口协议 以该图为例可以总结如下几点: 1) 发送方不必发送一个全窗口大小的数据。 2) 来自接收方的一个报文段确认数据并把窗口向右边滑动。这是因为窗口的大小是相对 于确认序号的。 第20章 TCP的成块数据流使用213 图20-5 窗口边沿的移动 窗 口 合拢 收缩 张开 由第2个报文段通告的窗口 由第7个报文段通告的窗口 由第8个报文段通告的窗口 由第10个报文段通告的窗口 由第14个报文段 通告的窗口 在第4,5,6报文段中发送的数据 在第9报文段 在第11,12,13报文段 在第15报文段 中发送的数据 中发送的数据 中发送的数据 被第8报 被第1 0报 被第1 4报 被第1 6报 文段确认 文段确认 文段确认 文段确认 被第7报文段确认3) 正如从报文段7到报文段8中变化的那样,窗口的大小可以减小,但是窗口的右边沿却 不能够向左移动。 4) 接收方在发送一个 A C K前不必等待窗口被填满。在前面我们看到许多实现每收到两个 报文段就会发送一个A C K。 下面我们可以看到更多的滑动窗口协议动态变化的例子。 20.4 窗口大小 由接收方提供的窗口的大小通常可以由接收进程控制,这将影响 T C P的性能。 4 . 2 B S D默认设置发送和接受缓冲区的大小为2 0 4 8个字节。在4 . 3 B S D中双方被增加 为4 0 9 6个字节。正如我们在本书中迄今为止所看到的例子一样, SunOS 4.1.3、 B S D / 3 8 6和S V R 4仍然使用4 0 9 6字节的默认大小。其他的系统,如Solaris 2.2、4 . 4 B S D和 AIX3.2则使用更大的默认缓存大小,如8192或16384等。 插口A P I允许进程设置发送和接收缓存的大小。接收缓存的大小是该连接上所能 够通告的最大窗口大小。有一些应用程序通过修改插口缓存大小来增加性能。 [Mogul 1993]显示了在改变发送和接收缓存大小(在单向数据流的应用中,如文件传输, 只需改变发送方的发送缓存和接收方的接收缓存大小)的情况下,位于以太网上的两个工作 站之间进行文件传输时的一些结果。它表明对以太网而言,默认的 4 0 9 6字节并不是最理想的 大小,将两个缓存增加到 1 6 3 8 4个字节可以增加约 4 0 %左右的吞吐量。在 [ P a p a d o p o u l o s和 Parulkar 1993]中也有相似的结果。 在2 0 . 7节中,我们将看到在给定通信媒体带宽和两端往返时间的情况下,如何计算最小的 缓存大小。 一个例子 可以使用s o c k程序来控制这些缓存的大小。我们以如下方式调用服务器程序: bsdi % sock -i -s -R6144 5555 该命令设置接收缓存为 6 1 4 4个字节(- R选项)。接着我们在主机s u n上启动客户程序并使 之发送8 1 9 2个字节的数据: sun % sock -i -n1 -w8192 bsdi 5555 图2 0 - 7显示了结果。 首先注意到的是在报文段 2中提供的窗口大小为6 1 4 4字节。由于这是一个较大的窗口,因 此客户立即连续发送了 6个报文段(4 ~ 9),然后停止。报文段 1 0确认了所有的数据(从第 1到 6 1 4 4字节),但提供的窗口大小却为 2 0 4 8,这很可能是接收程序没有机会读取多于 2 0 4 8字节的 数据。报文段11和1 2完成了客户的数据传输,且最后一个报文段带有 F I N标志。 报文段1 3包含与报文段1 0相同的确认序号,但通告了一个更大的窗口大小。报文段 1 4确 认了最后的2 0 4 8字节的数据和 F I N,报文段1 5和1 6仅用于通告一个更大的窗口大小。报文段 1 7和1 8完成通常的关闭过程。 214使用TCP/IP详解,卷1:协议图20-7 接收方提供一个6144字节的接收窗口的情况下的数据传输 20.5 PUSH标志 在每一个T C P例子中,我们都看到了 P U S H标志,但一直没有介绍它的用途。发送方使用 该标志通知接收方将所收到的数据全部提交给接收进程。这里的数据包括与 P U S H一起传送的 数据以及接收方T C P已经为接收进程收到的其他数据。 在最初的T C P规范中,一般假定编程接口允许发送进程告诉它的 T C P何时设置P U S H标志。 例如,在一个交互程序中,当客户发送一个命令给服务器时,它设置 P U S H标志并停下来等待 服务器的响应(在习题 1 9 . 1中我们假定当发送 1 2字节的请求时客户设置 P U S H标志)。通过允 许客户应用程序通知其 T C P设置P U S H标志,客户进程通知 T C P在向服务器发送一个报文段时 不要因等待额外数据而使已提交数据在缓存中滞留。类似地,当服务器的 T C P接收到一个设 置了P U S H标志的报文段时,它需要立即将这些数据递交给服务器进程而不能等待判断是否还 会有额外的数据到达。 然而,目前大多数的 A P I没有向应用程序提供通知其 T C P设置P U S H标志的方法。的确, 许多实现程序认为P U S H标志已经过时,一个好的T C P实现能够自行决定何时设置这个标志。 如果待发送数据将清空发送缓存,则大多数的源于伯克利的实现能够自动设置 P U S H标志。 这意味着我们能够观察到每个应用程序写的数据均被设置了 P U S H标志,因为数据在写的时候 第20章 TCP的成块数据流使用215就立即被发送。 代码中的注释表明该算法对那些只有在缓存被填满或收到一个P U S H标志时才向应 用程序提交数据的TCP实现有效。 使用插口A P I通知T C P设置正在接收数据的 P U S H标志或得到该数据是否被设置 PUSH标志的信息是不可能的。 由于源于伯克利的实现一般从不将接收到的数据推迟交付给应用程序,因此它们忽略所 接收的P U S H标志。 举例 在图2 0 - 1中我们观察到所有8个数据报文段(4 ~ 6、9、11 ~ 1 3和1 5)的P U S H标志均被置1, 这是因为客户进行了8次1 0 2 4字节数据的写操作,并且每次写操作均清空了发送缓存。 再次观察图 2 0 - 7,我们预计报文段 1 2中的P U S H标志被置1,因为它是最后一个报文段。 为什么发送方知道有更多的数据需要发送还设置报文段 7中的P U S H标志呢?这是因为虽然我 们指定写的是8 1 9 2个字节的数据,但发送方的发送缓存却是 4 0 9 6个字节。 值得注意的另外一点是在图 2 0 - 7中的第1 4、1 5和1 6这三个连续的确认报文段。在图 2 0 - 3 中我们也观察到了两个连续的 A C K,但那是因为接收方已经通告其窗口为 0(使发送方停止)。 当窗口张开时,需要发送另一个窗口非 0的A C K来使发送方重新启动。可是,在图 2 0 - 7中,窗 口的大小从来没有达到过 0。然而,当窗口大小增加了 2 0 4 8个字节的时候,另一个 A C K (报文 段1 5和1 6 )被发送以通知对方窗口被更新(在报文段 1 5和1 6中,这两个窗口更新是不需要的, 因为已经收到了对方的 F I N,表明它不会再发送任何数据)。许多T C P实现在窗口大小增加了 两个最大报文段长度(本例中为 2 0 4 8字节,因为M S S为1 0 2 4字节)或者最大可能窗口的 5 0 % (本例中为2 0 4 8字节,因为最大窗口大小为 4 0 9 6字节)时发送这个窗口更新。在第 2 2 . 3节详细 考察糊涂窗口综合症的时候,我们还会看到这种现象。 作为P U S H标志的另一个例子,再次回到图 2 0 - 3。我们之所以看到前4个报文段(4 ~ 7)的 标志被设置,是因为它们每一个均使 T C P产生了一个报文段并提交给 I P层。但是随后,T C P停 下来等待一个确认来移动 4 0 9 6字节的窗口。在此期间, T C P又得到了应用程序的最后 4 0 9 6个 字节的数据。当窗口张开时(报文段 9),发送方T C P知道它有4个可立即发送的报文段,因此 它只设置了最后一个报文段( 1 3)的P U S H标志。 20.6 慢启动 迄今为止,在本章所有的例子中,发送方一开始便向网络发送多个报文段,直至达到接 收方通告的窗口大小为止。当发送方和接收方处于同一个局域网时,这种方式是可以的。但 是如果在发送方和接收方之间存在多个路由器和速率较慢的链路时,就有可能出现一些问题。 一些中间路由器必须缓存分组,并有可能耗尽存储器的空间。 [Jacobson 1988]证明了这种连 接方式是如何严重降低了T C P连接的吞吐量的。 现在,T C P需要支持一种被称为“慢启动 (slow start)”的算法。该算法通过观察到新分组 进入网络的速率应该与另一端返回确认的速率相同而进行工作。 慢启动为发送方的T C P增加了另一个窗口:拥塞窗口 (congestion window),记为c w n d。当 216使用TCP/IP详解,卷1:协议与另一个网络的主机建立 T C P连接时,拥塞窗口被初始化为 1个报文段(即另一端通告的报文 段大小)。每收到一个 A C K,拥塞窗口就增加一个报文段( c w n d以字节为单位,但是慢启动 以报文段大小为单位进行增加)。发送方取拥塞窗口与通告窗口中的最小值作为发送上限。拥 塞窗口是发送方使用的流量控制,而通告窗口则是接收方使用的流量控制。 发送方开始时发送一个报文段,然后等待 A C K。当收到该A C K时,拥塞窗口从1增加为2, 即可以发送两个报文段。当收到这两个报文段的 A C K时,拥塞窗口就增加为 4。这是一种指数 增加的关系。 在某些点上可能达到了互联网的容量,于是中间路由器开始丢弃分组。这就通知发送方 它的拥塞窗口开得过大。当我们在下一章讨论 T C P的超时和重传机制时,将会看到它们是怎 样对拥塞窗口起作用的。现在,我们来观察一个实际中的慢启动。 一个例子 图2 0 - 8表示的是将从主机s u n发送到主机v a n g o g h . c s . b e r k e l e y . e d u的数据。这些数据 将通过一个慢的S L I P链路,该链路是T C P连接上的瓶颈(我们已经在时间系列上去掉了连接建立 的过程)。 图20-8 慢启动的例子 我们观察到发送方发送一个长度为 5 1 2字节的报文段,然后等待A C K。该A C K在716 ms后 收到。这个时间是一个往返时间的指示。于是拥塞窗口增加了 2个报文段,且又发送了两个报 文段。当收到报文段5的A C K后,拥塞窗口增加为3。此时尽管可发送多达3个报文段,可是在 下一个A C K收到之前,只发送了2个报文段。 在2 1 . 6节中我们将再次讨论慢启动,并介绍怎样采用另一种被称为“拥塞避免”的技术来 第20章 TCP的成块数据流使用217作为通常的实现。 20.7 成块数据的吞吐量 让我们看一看窗口大小、窗口流量控制以及慢启动对传输成块数据的 T C P连接的吞吐量 的相互作用。 图2 0 - 9显示了左边的发送方和右边的接收方之间的一个 T C P连接上的时间系列,共显示了 1 6个时间单元。为简单起见,本图只显示离散的时间单元。每个粗箭头线的上半部分显示的 是从左到右的携带数据的报文段,标记为 1, 2, 3, 等等。在粗线箭头下面表示的是反向传输的 A C K。我们把A C K用细箭头线表示,并标注了被确认的报文段号。 图20-9 时间0~15的成块数据吞吐量举例 在时间0,发送方发送了一个报文段。由于发送方处于慢启动中(其拥塞窗口为 1个报文 段),因此在继续发送以前它必须等待该数据段的确认。 在时间1, 2和3,报文段从左向右移动一个时间单元。在时间 4接收方读取这个报文段并产 生确认。经过时间 5、6和7,A C K移动到左边的发送方。我们有了一个 8个时间单元的往返时 间RT T(R o u n d - Trip Ti m e)。 我们有意把 A C K报文段画得比数据报文段小,这是因为它通常只有一个 I P首部和一个 T C P首部。这里显示仅仅是一个单向的数据流动,并且假定 A C K的移动速率与数据报文段的 移动速率相等。实际上并不总是这样。 218使用TCP/IP详解,卷1:协议 发送方 发送方 发送方 发送方 接收方 接收方 发送方 接收方 接收方 接收方 接收方通常发送一个分组的时间取决于两个因素:传播时延(由光的有限速率、传输设 备的等待时间等引起)和一个取决于媒体速率(即媒体每秒可传输的比特数)的发送 时延。对于一个给定的两个接点之间的通路,传播时延一般是固定的,而发送时延则 取决于分组的大小。在速率较慢的情况下发送时延起主要作用(例如,在习题 7 . 2中我 们甚至没有考虑传播时延),而在千兆比特速率下传播时延则占主要地位(见图24-6)。 当发送方收到A C K后,在时间8和9发送两个报文段(我们标记为2和3)。此时它的拥塞窗口 为2个报文段。这两个报文段向右传送到接收方,在时间1 2和1 3接收方产生两个A C K。这两个返 回到发送方的A C K之间的间隔与报文段之间的间隔一致,被称为 T C P的自计时( s e l f - c l o c k i n g )行 为。由于接收方只有在数据到达时才产生A C K,因此发送方接收到的A C K之间的间隔与数据到 达接收方的间隔是一致的(然而在实际中,返回路径上的排队会改变ACK的到达率)。 图2 0 - 1 0表示的是后面1 6个时间单位。2个A C K的到达使得拥塞窗口从 2个报文段增加为 4 个,而这4个报文段在时间1 6 ~ 1 9时被发送。第1个A C K在时间2 3到达。4个A C K的到达使得拥 塞窗口从4个报文段增加为8个,并在时间2 4 ~ 3 1发送8个报文段。 图20-10 时间16~31的成块数据吞吐量举例 第20章 TCP的成块数据流使用219 发送方 发送方 发送方 发送方 发送方 发送方 接收方 接收方 接收方 接收方 接收方 接收方 接收方 接收方 发送方 发送方 发送方 发送方 发送方 发送方 发送方 发送方 发送方 发送方 发送方 发送方 接收方 接收方 接收方 接收方 接收方 接收方 接收方 接收方 接收方在时间3 1及其后续时间,发送方和接收方之间的管道 ( p i p e )被填满。此时不论拥塞窗口和 通告窗口是多少,它都不能再容纳更多的数据。每当接收方在某一个时间单位从网络上移去 一个报文段,发送方就再发送一个报文段到网络上。但是不管有多少报文段填充了这个管道, 返回路径上总是具有相同数目的 A C K。这就是连接的理想稳定状态。 20.7.1 带宽时延乘积 现在来回答窗口应该设置为多大的问题。在我们的例子中,作为最大的吞吐量,发送方 在任何时候有8个已发送的报文段未被确认。接收方的通告窗口必须不小于这个数目,因为通 告窗口限制了发送方能够发送的段的数目。 可以计算通道的容量为: c a p a c i t y (bit) = b a n d w i d t h (b/s) × ro u n d-trip time ( s ) 一般称之为带宽时延乘积。这个值依赖于网络速度和两端的 RT T,可以有很大的变动。例如, 一条穿越美国(RT T约为60 ms)的T 1的电话线路(1 544 000 b/s)的带宽时延乘积为11 580字 节。对于2 0 . 4节中讨论的缓存大小而言,这个结果是合理的。但是一条穿越美国的 T 3电话线路 (45 000 000 b/s)的带宽时延乘积则为337 500字节,这个数值超过了最大所允许的T C P通告窗 口的大小(6 5 5 3 5字节)。在2 4 . 4节我们将讨论能够避免当前T C P限制的新的T C P窗口大小选项。 T1电话线的1 544 000 b/s是原始比特率。由于每193个bit使用1个作为帧同步,因此 实际数据率为1 536 000 b/s。一个T3电话线的原始比特率实际上是44 736 000 b/s,其数 据率可达到44 210 000 b/s。在讨论中我们使用1.544 Mb/s和45 Mb/s。 不论是带宽还是时延均会影响发送方和接收方之间通路的容量。在图 2 0 - 11中我们显示了 一个增加了一倍的RT T会使通路容量也增加一倍。 在图2 0 - 11底下的说明部分,通过使用一个较长的 RT T,这个管道能够容纳8个报文段而不 是4个。 类似地,图2 0 - 1 2表示了增加一倍的带宽也可使该管道的容量增加一倍。 在图2 0 - 1 2的下部,假定网络速率已经加倍,使得我们能够只使用上面一半的时间来发送 4个报文段。这样,该管道的容量再次加倍(假定该图的上半部分与下半部分中的报文段具有 同样大小,即具有相同的比特数)。 20.7.2 拥塞 当数据到达一个大的管道(如一个快速局域网)并向一个较小的管道(如一个较慢的广 220使用TCP/IP详解,卷1:协议 倍增的RTT 图20-11 RTT加倍可使管道容量增加一倍 图20-12 带宽加倍可使管道容量增加一倍域网)发送时便会发生拥塞。当多个输入流到达一个路由器,而路由器的输出流小于这些输 入流的总和时也会发生拥塞。 图2 0 - 1 3显示了一个典型的大管道向小管道发送报文的情况。之所以说它典型,是因为大 多数的主机都连接在局域网上,并通过一个路由器与速率相对较低的广域网相连(我们再次 假定图中上半部分的报文段( 9 ~ 2 0)都是相同的,而图中下半部分的 A C K也都是相同的)。 图20-13 从较大管道向较小管道发送分组引起的拥塞 在该图中,我们已经标记路由器 R 1为“瓶颈”,因为它是拥塞发生的地方。它从左侧速 率较高的局域网接收数据并向右侧速率较低的广域网发送(通常 R 1与R 3是同样的路由器, 如同R 2与R 4一样。但这并不是必需的,有时也会使用不对称的路径)。当路由器R 2将所接收 到的分组发送到右侧的局域网时,这些分组之间维持与其左侧广域网上同样的间隔,尽管局 域网具有更高的带宽。类似地,返回的确认之间的间隔也与其在路径中最慢的链路上的间隔 一致。 在图2 0 - 1 3中已经假定发送方不使用慢启动,它按照局域网的带宽尽可能快地发送编号 为1 ~ 2 0的报文段(假定接收方的通告窗口至少为 2 0个报文段)。正如我们看到的那样, A C K 之间的间隔与在最慢链路上的一致。假定瓶颈路由器具有足够的容纳这 2 0个分组的缓存。 如果这个不能保证,就会引起路由器丢弃分组。在 2 1 . 6节讨论避免拥塞时会看到怎样避免这 种情况。 20.8 紧急方式 T C P提供了“紧急方式 ( u rgent mode)”,它使一端可以告诉另一端有些具有某种方式的 “紧急数据”已经放置在普通的数据流中。另一端被通知这个紧急数据已被放置在普通数据流 中,由接收方决定如何处理。 可以通过设置 T C P首部(图1 7 - 2)中的两个字段来发出这种从一端到另一端的紧急数据 已经被放置在数据流中的通知。 U R G比特被置1,并且一个1 6 b i t的紧急指针被置为一个正的 偏移量,该偏移量必须与 T C P首部中的序号字段相加,以便得出紧急数据的最后一个字节的 序号。 仍有许多关于紧急指针是指向紧急数据的最后一个字节还是指向紧急数据最后一 个字节的下一个字节的争论。最初的 T C P规范给出了两种解释,但Host Requirements RFC确定指向最后一个字节是正确的。 然而,问题在于大多数的实现(包括源自伯克利的实现)继续使用错误的解释。 第20章 TCP的成块数据流使用221 发送方 发送方 瓶颈 路由器 R 1 路由器 R 3 路由器 R 4 接收方路由 器R2 接收方所有符合Host Requirements RFC的实现都是可兼容的,但很有可能无法与其他大多数 主机正确通信。 T C P必须通知接收进程,何时已接收到一个紧急数据指针以及何时某个紧急数据指针还不 在此连接上,或者紧急指针是否在数据流中向前移动。接着接收进程可以读取数据流,并必 须能够被告知何时碰到了紧急数据指针。只要从接收方当前读取位置到紧急数据指针之间有 数据存在,就认为应用程序处于“紧急方式”。在紧急指针通过之后,应用程序便转回到正常 方式。 T C P本身对紧急数据知之甚少。没有办法指明紧急数据从数据流的何处开始。 T C P通过连 接传送的唯一信息就是紧急方式已经开始( T C P首部中的U R G比特)和指向紧急数据最后一 个字节的指针。其他的事情留给应用程序去处理。 不幸的是,许多实现不正确地称 T C P的紧急方式为带外数据 (out-of-band data)。如果一个 应用程序确实需要一个独立的带外信道,第二个 T C P连接是达到这个目的的最简单的方法 (许多运输层确实提供许多人认为的那种真正的带外数据:使用同一个连接的独立的逻辑数据 通道作为正常的数据通道。这是 T C P所没有提供的)。 T C P的紧急方式与带外数据之间的混淆,也是因为主要的编程接口(插口A P I)将 TCP的紧急方式映射为称为带外数据的插口。 紧急方式有什么作用呢?两个最常见的例子是 Te l n e t和R l o g i n。当交互用户键入中断键时, 我们在第2 6章将看到使用紧急方式来完成这个功能的例子。另一个例子是 F T P,当交互用户 放弃一个文件的传输时,我们将在第 2 7章看到这样的一个例子。 Te l n e t和R l o g i n从服务器到客户使用紧急方式是因为在这个方向上的数据流很可能要被客户 的T C P停止(也即,它通告了一个大小为 0的窗口)。但是如果服务器进程进入了紧急方式,尽 管它不能够发送任何数据,服务器 T C P也会立即发送紧急指针和U R G标志。当客户T C P接收到 这个通知时就会通知客户进程,于是客户可以从服务器读取其输入、打开窗口并使数据流动。 如果在接收方处理第一个紧急指针之前,发送方多次进入紧急方式会发生什么情况呢? 在数据流中的紧急指针会向前移动,而其在接收方的前一个位置将丢失。接收方只有一个紧 急指针,每当对方有新的值到达时它将被覆盖。这意味着如果发送方进入紧急方式时所写的 内容对接收方非常重要,那么这些字节数据必须被发送方用某种方式特别标记。我们将看到 Te l n e t通过在数据流中加入一个值为 2 5 5的字节作为前缀来标记它所有的命令。 一个例子 让我们观察一下即使是在接收方窗口关闭的情况下, T C P是如何发送紧急数据的。在主 机b s d i上启动s o c k程序,并使之在连接建立后和从网络读取前暂停 1 0秒种(通过使用 - P选 项),这将使另一端填满发送窗口: bsdi % sock -i -s -P10 5555 接着我们在主机 s u n上启动客户,使之使用一个 8 1 9 2字节的发送缓存(使用 - S选项) 并进行6个向网络写 1 0 2 4字节数据的操作(使用 - n选项)。还指明 - U 5选项,告知它向网络 写第5个缓存之前要写 1个字节的数据,并进入紧急数据方式。我们指明详细标志来观察写 的顺序: 222使用TCP/IP详解,卷1:协议我们设置发送缓存为 8 1 9 2个字节,以便让发送应用程序能够立即写所有的数据。图 2 0 - 1 4 显示了t c p d u m p输出的这个交换过程的结果(删去了连接建立的过程)。第1 ~ 5行表示发送方 用4个1 0 2 4字节的报文段去填充接收方的窗口。然后由于接收方的窗口被填满(第 4行的A C K 确认了数据,但并没有移动窗口的右边沿),所以发送方停止发送。 在写了第4个正常数据之后,应用进程写了1个字节并进入紧急方式。第6行是该应用进程写的结 果,紧急指针被设置为4 0 9 8。尽管发送方不能发送任何数据,但紧急指针和U R G标志一起被发送。 5个这样的A C K在13 ms内被发送(第6 ~ 1 0行)。第1个A C K在应用进程写 1个字节并进入 紧急方式时被发送,后面两个在应用进程写最后两个 1 0 2 4字节的数据时被发送(尽管 T C P不 能发送这2 0 4 8个字节的数据,可每次当应用程序执行写操作的时候, T C P的输出功能被调用。 当T C P看到正处于紧急方式时,它会发送其他的紧急通知)。第4个A C K在应用进程关闭其 T C P连接时被发送( T C P的输出功能再次被调用)。发送应用程序在启动几毫秒后终止— 在 接收方应用进程已经发出其第一个写操作之前。 T C P将所有的数据进行排队,并在可能时发 送出去(这就是为何指明发送缓存为 8 1 9 2字节的原因,因此只有这样才能够把所有的数据都 放置在缓存中)。第5个A C K很可能是在接收第 4行的A C K时产生的。发送 T C P很可能在这个 A C K到达前便已将其第 4个报文段放入队列以便输出(第 5行)。另一端接收到这个 A C K也会 引起T C P输出例程被调用。 图20-14 t c p d u m p 对TCP紧急方式的输出结果 第20章 TCP的成块数据流使用223接着,接收方确认最后的 1 0 2 4字节的数据(第 11行),但同时通告窗口为 0。发送方用一 个包含紧急通知的报文段进行了响应。 在第1 3行,当应用进程被唤醒、并从接收缓存读取一些数据时,接收方通告窗口为 2 0 4 8 字节。于是后面又发送了两个 1 0 2 4字节的报文段(第 1 4和1 5行)。其中,由于紧急指针在第 1 个报文段的范围内,因此这个报文段被设置了紧急通知标志,而第 2个报文段则关闭了该标 志。 当接收方再次打开窗口(第 1 6行)时,发送方传输最后的数据(序号为 6 1 4 5)并发起正 常的连接关闭。 图2 0 - 1 5显示了发送的6 1 4 5个字节数据的序号。可以看到当进入紧急方式时所发送的字节 的序号是4 0 9 7,但在图2 0 - 1 4中紧急指针指向4 0 9 8,这证明了该实现(SunOS 4.1.3)将紧急指 针设置为紧急数据最后字节的下一个字节。 图20-15 紧急方式例子中,应用进程的写操作和TCP的一些报文段 该图还可以让我们观察 T C P是如何对应用进程写的数据进行重新分组化的。当进入紧急 方式时待输出的 1个字节是与在缓存中的后面 1 0 2 3个字节一同发送的。下一个报文段也包含 1 0 2 4字节的数据,而最后一个报文段则只包含一个字节。 20.9 小结 正如我们在本章一开始时讲的那样,没有一种单一的方法可以使用 T C P进行成块数据的 交换。这是一个依赖于许多因素的动态处理过程,有些因素我们可以控制(如发送和接收缓 存的大小),而另一些我们则没有办法控制(如网络拥塞、与实现有关的特性等)。在本章, 我们已经考察了许多T C P的传输过程,介绍了所有我们能够看到的特点和算法。 进行成块数据有效传输的最重要的方法是 T C P的滑动窗口协议。我们考察了 T C P为使发送 方和接收方之间的管道充满来获得最可能快的传输速度而采用的方法。我们用带宽时延乘积 衡量管道的容量,并分析了该乘积与窗口大小之间的关系。在 2 4 . 8节介绍T C P性能的时候将再 次涉及这个概念。 我们还介绍了T C P的P U S H标志,因为在跟踪结果中总是观察到它,但我们无法对它的设 置与否进行控制。本章最后一个主题是 T C P的紧急数据,人们常常错误地称其为“带外数据”。 T C P的紧急方式只是一个从发送方到接收方的通知,该通知告诉接收方紧急数据已被发送, 并提供该数据最后一个字节的序号。应用程序使用的有关紧急数据部分的编程接口常常都不 是最佳的,从而导致更多的混乱。 习题 20.1 在图2 0 - 6中,我们可以看到一个序号为 0的字节和一个序号为 8 1 9 3的字节,试问这两个 224使用TCP/IP详解,卷1:协议 写 报文段 报文段 报文段 报文段 报文段 报文段 写 写 写 写紧急 写字节的含义是什么? 20.2 提前观察图2 2 - 1,并解释主机b s d i设置P U S H标志的含义。 20.3 在一个U s e n e t记录中,有人抱怨说美国和日本之间的一个128 ms时延、速率为256 000 b/s的链 路吞吐量为120 000 b/s(利用率为4 7 %),而当链路通过卫星时其吞吐量则为33 000 b/s(利用 率为1 3%)。试问在这两种情况下窗口大小各为多少(假定卫星链路的时延为500 ms)?卫星 链路的窗口大小应该如何调整? 20.4 如果A P I提供一种方法,使得发送方可以告诉其 T C P打开P U S H标志,而接收方可以查询 一个接收的报文段是否被设置了 P U S H标志,试问该标志能否被用作一个记录标记? 20.5 在图2 0 - 3中为什么没有合并报文段1 5和1 6? 20.6 在图2 0 - 1 3中,我们假定对应数据报文段之间的间隔,返回的 A C K之间的间隔被分隔得 很好。如果在链路某处进行缓存并使许多 A C K同时到达发送方,试问会发生什么情况? 第20章 TCP的成块数据流使用225第21章 TCP的超时与重传 21.1 引言 T C P提供可靠的运输层。它使用的方法之一就是确认从另一端收到的数据。但数据和确 认都有可能会丢失。 T C P通过在发送时设置一个定时器来解决这种问题。如果当定时器溢出 时还没有收到确认,它就重传该数据。对任何实现而言,关键之处就在于超时和重传的策略, 即怎样决定超时间隔和如何确定重传的频率。 我们已经看到过两个超时和重传的例子:(1)在6 . 5节的I C M P端口不能到达的例子中,看 到T F T P客户使用U D P实现了一个简单的超时和重传机制:假定 5秒是一个适当的时间间隔, 并每隔5秒进行重传;( 2)在向一个不存在的主机发送 A R P的例子中(第 4 . 5节),我们看到 当T C P试图建立连接的时候,在每个重传之间使用一个较长的时延来重传 S Y N。 对每个连接,T C P管理4个不同的定时器。 1) 重传定时器使用于当希望收到另一端的确认。在本章我们将详细讨论这个定时器以及 一些相关的问题,如拥塞避免。 2) 坚持( p e r s i s t )定时器使窗口大小信息保持不断流动,即使另一端关闭了其接收窗口。第 2 2章将讨论这个问题。 3) 保活( k e e p a l i v e )定时器可检测到一个空闲连接的另一端何时崩溃或重启。第 2 3章将描述 这个定时器。 4) 2MSL定时器测量一个连接处于 T I M E _ WA I T状态的时间。我们在 1 8 . 6节对该状态进行 了介绍。 本章以一个简单的 T C P超时和重传的例子开始,然后转向一个更复杂的例子。该例子可 以使我们观察到T C P时钟管理的所有细节。可以看到 T C P的典型实现是怎样测量 T C P报文段的 往返时间以及 T C P如何使用这些测量结果来为下一个将要传输的报文段建立重传超时时间。 接着我们将研究T C P的拥塞避免— 当分组丢失时T C P所采取的动作— 并提供一个分组丢失 的实际例子,我们还将介绍较新的快速重传和快速恢复算法,并介绍该算法如何使 T C P检测 分组丢失比等待时钟超时更快。 21.2 超时与重传的简单例子 首先观察T C P所使用的重传机制,我们将建立一个连接,发送一些分组来证明一切正常, 然后拔掉电缆,发送更多的数据,再观察 T C P的行为。 正常发送本行 在发送本行前断连 9分钟后TCP放弃时输出图2 1 - 1表示的是t c p d u m p的输出结果(已经去掉了b s d i设置的服务类型信息)。 图21-1 TCP超时和重传的简单例子 第1、2和3行表示正常的T C P连接建立的过程,第4行是“hello, world”(1 2个字符加上回 车和换行)的传输过程,第 5行是其确认。接着我们从 s v r 4拔掉了以太网电缆,第 6行表示 “and hi”将被发送。第 7 ~ 1 8行是这个报文段的 1 2次重传过程,而第 1 9行则是发送方的 T C P最 终放弃并发送一个复位信号的过程。 现在检查连续重传之间不同的时间差,它们取整后分别为 1、3、6、1 2、2 4、4 8和多个6 4 秒。在本章的后面,我们将看到当第一次发送后所设置的超时时间实际上为 1 . 5秒(它在首次 发送后的1 . 0 1 3 6秒而不是精确的1 . 5秒后,发生的原因我们已在图 1 8 - 7中进行了解释),此后该 时间在每次重传时增加1倍并直至6 4秒。 这个倍乘关系被称为“指数退避 (exponential backoff )”。可以将该例子与 6 . 5节中的T F T P 例子比较,在那里每次重传总是在前一次的 5秒后发生。 首次分组传输(第6行,2 4 . 4 8 0秒)与复位信号传输(第 1 9行,5 6 6 . 4 8 8秒)之间的时间差 约为9分钟,该时间在目前的T C P实现中是不可变的。 对于大多数实现而言,这个总时间是不可调整的。Solaris 2.2允许管理者改变这个时 间(E . 4节中的t c p _ i p _ a b o r t _ i n t e r v a l变量),且其默认值为2分钟,而不是最常用的 9分钟。 21.3 往返时间测量 T C P超时与重传中最重要的部分就是对一个给定连接的往返时间( RT T)的测量。由于路 由器和网络流量均会变化,因此我们认为这个时间可能经常会发生变化, T C P应该跟踪这些 变化并相应地改变其超时时间。 首先T C P必须测量在发送一个带有特别序号的字节和接收到包含该字节的确认之间的 RT T。在上一章中,我们曾提到在数据报文段和 A C K之间通常并没有一一对应的关系。在图 第21章 TCP的超时与重传使用2272 0 . 1中,这意味着发送方可以测量到的一个 RT T,是在发送报文段 4(第1 ~ 1 0 2 4字节)和接收 报文段7(对1 ~ 1 0 2 4字节的A C K)之间的时间,用M表示所测量到的RT T。 最初的T C P规范使T C P使用低通过滤器来更新一个被平滑的 RT T估计器(记为O)。 R← R+ ( 1-)M 这里的 是一个推荐值为 0 . 9的平滑因子。每次进行新测量的时候,这个被平滑的 RT T将得到 更新。每个新估计的9 0%来自前一个估计,而1 0 %则取自新的测量。 该算法在给定这个随RT T的变化而变化的平滑因子的条件下, RFC 793推荐的重传超时时 间RTO(Retransmission Ti m e O u t)的值应该设置为 RTO = R 这里的 是一个推荐值为2的时延离散因子。 [Jacobson 1988] 详细分析了在 RT T变化范围很大时,使用这个方法无法跟上这种变化, 从而引起不必要的重传。正如 J a c o b s o n记述的那样,当网络已经处于饱和状态时,不必要的 重传会增加网络的负载,对网络而言这就像在火上浇油一样。 除了被平滑的RT T估计器,所需要做的还有跟踪RT T的方差。在往返时间变化起伏很大时, 基于均值和方差来计算 RTO,将比作为均值的常数倍数来计算 RTO能提供更好的响应。在 [Jacobson 1988]中的图5和图6中显示了根据RFC 793计算的某些实际往返时间的 RTO和下面考 虑了往返时间的方差所计算的 RTO的比较结果。 正如J a c o b s o n所描述的,均值偏差是对标准偏差的一种好的逼近,但却更容易进行计算 (计算标准偏差需要一个平方根)。这就引出了下面用于每个 RT T测量M的公式。 E rr = M-A A←A + g E rr D←D + h( | E rr |-D) RTO = A + 4D 这里的A是被平滑的RT T(均值的估计器)而D则是被平滑的均值偏差。 E rr是刚得到的测量结 果与当前的RT T估计器之差。A和D均被用于计算下一个重传时间( RTO)。增量g起平均作用, 取为1 / 8(0 . 1 2 5)。偏差的增益是h,取值为0 . 2 5。当RT T变化时,较大的偏差增益将使 RTO快 速上升。 [Jacobson 1988]指明在计算 RTO时使用 2 D,但经过后来更深入的研究, [Jacobson1990c]将该值改为4D,也就是在BSD Net/1的实现中使用的那样。 J a c o b s o n指明了一种使用整数运算来计算这些公式的方法,并被许多实现所采用(这也就 是g, h和倍数4均是2的乘方的一个原因,这样一来计算均可只通过移位操作而不需要乘、除运 算来完成)。 将J a c o b s o n与最初的方法比较,我们发现被平滑的均值计算公式是类似的( 是1减去增 益g),而增益可使用不同的值。而且 J a c o b s o n计算RTO的公式依赖于被平滑的 RT T和被平滑的 均值偏差,而最初的方法则使用了被平滑的 RT T的一个倍数。 在看完下一节中的例子时,我们将看到这些估计器是如何被初始化的。 Karn算法 在一个分组重传时会产生这样一个问题:假定一个分组被发送。当超时发生时, RTO正 228使用TCP/IP详解,卷1:协议如2 1 . 2节中显示的那样进行退避,分组以更长的 RTO进行重传,然后收到一个确认。那么这个 A C K是针对第一个分组的还是针对第二个分组呢?这就是所谓的重传多义性问题。 [Karn and Partridge 1987]规定,当一个超时和重传发生时,在重传数据的确认最后到达 之前,不能更新 RT T估计器,因为我们并不知道 A C K对应哪次传输(也许第一次传输被延迟 而并没有被丢弃,也有可能第一次传输的 A C K被延迟)。 并且,由于数据被重传, RTO已经得到了一个指数退避,我们在下一次传输时使用这 个退避后的 RTO。对一个没有被重传的报文段而言,除非收到了一个确认,否则不要计算 新的RTO。 21.4 往返时间RTT的例子 在本章中,我们将使用以下这些例子来检查 T C P的超时和重传、慢启动以及拥塞避免等 方方面面的实现细节。 使用s o c k程序和如下的命令来将 3 2 7 6 8字节的数据从主机 s l i p发送到主机v a n g o g h . c s . b e r k e l e y . e d u上的丢弃服务。 slip % sock -D -i -n32 vangogh.cs.berkeley.edu discard 在扉页前图中,可以看到 s l i p通过两个 S L I P链路与1 4 0 . 2 5 2 . 1以太网相连,并从这里通过 I n t e r n e t到达目的地。通过使用两个 9600 b/s的S L I P链路,我们期望能够得到一些可测量的 时延。 该命令执行3 2个写1 0 2 4字节的操作。由于s l i p和b s d i之间的M T U为2 9 6字节,因此这些 操作会产生1 2 8个报文段,每个报文段包含 2 5 6字节的用户数据。整个传输过程的时间约为 4 5 秒,我们观察到了一个超时和三次重传。 当该传输过程进行时,我们在 s l i p上使用t c p d u m p来截获所有的发送和接收的报文段, 并通过使用 - D选项来打开插口排错功能(见 A . 6节),这样便可以通过运行一个修改后的 t r p t( 8 )程序来打印出连接控制块中与 RT T、慢启动及拥塞避免等有关的多个变量。 对于给出的跟踪结果,我们不能够完全进行显示,相反,我们将在介绍本章时看到它的 各个部分。图2 1 - 2显示的是前5秒中的数据和确认的传输过程。与前面 t c p d u m p的输出相比, 我们已对其显示稍微进行了修改。虽然我们仅能够在运行 t c p d u m p的主机上测量分组发送 和接收的时间,但在本图中我们希望显示出分组正在网络中传输(它们确实存在,因为这 个局域网连接与共享式的以太网并不一样)以及接收主机何时可能产生 A C K(在本图中去 掉了所有的窗口大小通告。主机 s l i p总是通告窗口大小为 4 0 9 6,而v a n g o g h则总是通告窗 口大小为8 1 9 2)。 还需要注意的是在本图中我们已经将报文段按照在主机 s l i p上发送和接收的序号记为 1 ~ 1 3和1 5。这与在这个主机上所收集的 t c p d u m p的输出结果有关。 21.4.1 往返时间RTT的测量 在图2 1 - 2左边的时间轴上有三个括号,它们表明为进行RT T计算对哪些报文段进行了计时, 并不是所有的报文段都被计时。 大多数源于伯克利的 T C P实现在任何时候对每个连接仅测量一次 RT T值。在发送一个报文 段时,如果给定连接的定时器已经被使用,则该报文段不被计时。 第21章 TCP的超时与重传使用229图21-2 分组交换和RTT测量 在每次调用 500 ms的T C P的定时器例程时,就增加一个计数器来完成计时。这意味着, 如果一个报文段的确认在它发送 550 ms后到达,则该报文段的往返时间 RT T将是1个滴答(即 500 ms)或是2个滴答(即1000 ms)。 对每个连接而言,除了这个滴答计数器,报文段中数据的起始序号也被记录下来。当收 到一个包含这个序号的确认后,该定时器就被关闭。如果 A C K到达时数据没有被重传,则被 平滑的RT T和被平滑的均值偏差将基于这个新测量进行更新。 图2 1 - 2中连接上的定时器在发送报文段 1时启动,并在确认(报文段 2)到达时终止。尽 管它的RT T是1 . 0 6 1秒(t c p d u m p的输出),但插口排错的信息显示该过程经历了 3个T C P时钟 滴答,即RT T为1500 ms。 下一个被计时的是报文段 3。当2.4 ms后传输报文段4时,由于连接的定时器已经被启动, 因此该报文段不能被计时。当报文段 5到达时,确认了正在被计时的数据。虽然我们从 t c p d u m p的输出结果可以看到其RT T是0 . 8 0 8秒,但它的RT T被计算为1个滴答(500 ms)。 定时器在发送报文段 6时再次被启动,并在 1 . 0 1 5秒后接收到它的确认(报文段 1 0)时终 止。测量到的RT T是2个滴答。报文段7和9不能被计时,因为定时器已经被使用。而且,当收 230使用TCP/IP详解,卷1:协议第21章 TCP的超时与重传使用231 到报文段8(第7 6 9字节的确认)时,由于该报文段不是正在计时的数据的确认,因此什么也 没有进行更新。 图2 1 - 3显示了本例中通过t c p d u m p的输出所得到的实际RT T与时钟滴答计数之间的关系。 图21-3 RTT测量和时钟滴答 在图的上端表示间隔为 500 ms的时钟滴答,图的下端表示 t c p d u m p的输出时间及定时器 何时被启动和关闭。在发送报文段 1和接收到报文段 2之间经历了 3个滴答,时间为 1 . 0 6 1秒, 因此假定第1个滴答发生在0 . 0 3秒处(第1个滴答一定在0 ~ 0 . 0 6 1秒之间)。接着该图表示了第 2 个被测量的RT T为什么被记为1个滴答,而第3个被记为2个滴答。 在这个完整的例子中, 1 2 8个报文段被传送,并收集了 1 8个RT T采样。图2 1 - 4表示了测量 的RT T(取自t c p d u m p的输出)和T C P为超时所使用的 RTO(取自插口排错的输出)。在图 2 1 - 2中,x轴从时间0开始,表示的是传输报文段 1的时刻,而不是传输第1个S Y N的时刻。 图21-4 测量出的RTT和TCP计算的RTO的例子 测量出RT T的前3个数据点对应图2 1 - 2所示的3个RT T。在时间10, 14和2 1处的间隔是由在 这些时刻附近发生的重传(将在本章后面给出)引起的。 K a r n算法在另一个报文段被发送和 确认之前阻止我们更新估计器。同样注意到在这个实现中, T C P计算的RTO总是500 ms的倍 数。 21.4.2 RTT估计器的计算 让我们来看一下RT T估计器(平滑的RT T和平滑的均值偏差)是如何被初始化和更新,以 及每个重传超时是怎样计算的。 变量A和D分别被初始化为0和3秒。初始的重传超时使用下面的公式进行计算 1.061秒,3滴答 0.808秒,1滴答 1.015秒,2滴答 (秒) 测量出的RTT 时间(秒) TCP计算出的RTO232使用TCP/IP详解,卷1:协议 RTO = A + 2D = 0 + 2×3 = 6 s (因子2D只在这个初始化计算中使用。正如前面提到的,以后使用4D和A相加来计算RTO)。 这就是传输初始S Y N所使用的RTO。 结果是这个初始S Y N丢失了,然后超时并引起了重传。图 2 1 - 5给出了t c p d u m p输出文件中 的前4行。 图21-5 初始SYN的超时和重传 当超时在5 . 8 0 2秒后发生时,计算当前的RTO值为 RTO = A + 4D = 0 + 4×3 = 12 s 因此,应用于 RTO的指数退避取为 1 2。由于这是第 1次超时,我们使用倍数 2,因此下一个超 时时间取值为2 4秒。再下一个超时时间的倍数为 4,得出值为4 8秒(这些初始RTO,对于一个 连接上的最初的S Y N,取值为6秒,接下来为2 4秒,正是我们在图4 - 5中看到的)。 A C K在重传后4 6 7 m s到达。A和D的值没有被更新,这是因为 K a r n算法对重传的处理比较 模糊。下一个发送的报文段是第 4行的A C K,但它只是一个 A C K,所以没有被计时(只有数 据报文段才会被计时)。 当发送第1个数据报文段时(图 2 1 - 2中的报文段1),RTO没有改变,这同样是由于 K a r n算 法。当前的2 4秒一直被使用,直到进行一个 RT T测量。这意味着图 2 1 - 4中时间0的RTO并不真 的是2 4,但我们没有画出那个点。 当第1个数据报文段的A C K(图2 1 - 2中的报文段2)到达时,经历了3个时钟滴答,估计器 被初始化为 A = M + 0.5 = 1.5 + 0.5 = 2 D = A/2 = 1 (因为经历3个时钟滴答,因此, M取值为1 . 5)。在前面,A和D初始化为0,RTO的初始计算值 为3。这是使用第1个RT T的测量结果M对估计器进行首次计算的初始值。计算的 RTO值为 RTO = A + 4D = 2 + 4×1 = 6 s 当第2个数据报文段的A C K(图2 1 - 2中的报文段5)到达时,经历了1个时钟滴答(0 . 5秒), 估计器按如下更新: E rr = M-A = 0.5 - 2 =-1 . 5 A = A + g E rr = 2-0 . 1 2 5×1.5 = 1.8125 D = D + h(| E rr | -D) = 1 + 0.25×( 1 . 5-1) = 1.125 RTO = A + 4D = 1.8125 + 4×1.125 = 6.3125 E rr、A和D的定点表示与实际使用的定点计算(在简化浮点计算中表示过)有一些微小的差 别。这些不同使 RTO取值为6秒(而非6 . 3 1 2 5秒),正如我们在图2 1 - 4中的时间1 . 8 7 1处所画的 那样。21.4.3 慢启动 我们在第2 0 . 6节介绍了慢启动算法,在图 2 1 - 2中可再次看到它的工作过程。 连接上最初只允许传输一个报文段,然后在发送下一个报文段之前必须等待接收它的确 认。当报文段2被接收后,就可以再发送两个报文段。 21.5 拥塞举例 现在观察一下数据报文段的传输过程。图 2 1 - 6显示了报文段中数据的起始序号与该报文 段发送时间的对比图。它提供了一种较好的数据传输的可视化方法。通常代表数据的点将向 上和向右移动,这些点的斜率就表示传输速率。当这些点向下和向右移动则表示发生了重传。 在2 1 . 4节开始时,我们曾提到整个传输的时间约为 4 5秒,但在本图中只显示了 3 5秒钟。 这3 5秒只是数据报文段发送的时间。因为第 1个S Y N看来是丢失了并被重传(见图 2 1 - 5),因 此第1个数据报文段是在第 1个S Y N发送6 . 3秒后才发送的。而且,在发送最后一个数据报文段 和F I N(图2 1 - 6中的3 4 . 1秒)之后,在接收方的 F I N到达之前,又花费了另外的 4 . 0秒接收来自 接收方的最后1 4个A C K。 图21-6 从s l i p 发送32768个字节的数据到v a n g o g h 可以立即看到图 2 1 - 6中发生在时刻 1 0,1 4和2 1附近的3个重传。我们还可以看到在这 3个 点中只进行了一次报文段的重传,因为只有一个点下垂低于向上的斜率。 仔细检查一下这几个下垂点中的第 1个点(在1 0秒标记处的附近)。整理t c p d u m p的输出 结果可以得到图2 1 - 7。 在这个图中,除了下面将要讨论的报文段 7 2,已经去掉了其他所有的窗口通告。主机 s l i p总是通告窗口大小为 4 0 9 6,而主机v a n g o g h则通告窗口为 8 1 9 2。该图中报文段的编号 可以看作是图 2 1 - 2的延续,在那里报文段的编号从 1开始。与图2 1 - 2一样,报文段根据在 s l i p 上发送和接收的顺序进行编号, t c p d u m p在主机 s l i p上运行。我们还去掉了一些与讨论无 第21章 TCP的超时与重传使用233 发送时间(秒) 序号 (千字节)关的段(第44, 47和4 9以及所有来自v a n g o g h的A C K)。 图21-7 10秒标记处附近重传的分组交换 看来报文段4 5丢失或损坏了,这一点无法从该输出上进行辨认。能够在主机 s l i p上看到 的是对第6 6 5 7字节(报文段5 8)以前数据的确认(不包括字节 6 6 5 7在内)。紧接着的是带有相 同序号的8个A C K。正是接收到报文段 6 2,也就是第3个重复A C K,才引起自序号6 6 5 7开始的 数据报文段(报文段 6 3)进行重传。的确,源于伯克利的 T C P实现对收到的重复 A C K进行计 数,当收到第3个时,就假定一个报文段已经丢失并重传自那个序号起的一个报文段。这就是 J a c o b s o n的快速重传算法,该算法通常与他的快速恢复算法一起配合使用。我们在第 2 1 . 7节中 介绍这两个算法。 注意到在重传后(报文段 6 3),发送方继续正常的数据传输(报文段 6 7、6 9和7 1)。T C P 不需要等待对方确认重传。 现在检查一下在接收端发生了什么。当按序收到正常数据(报文段 4 3)后,接收T C P将 2 5 5个字节的数据交给用户进程。但下一个收到的报文段(报文段 4 6)是失序的:数据的开始 234使用TCP/IP详解,卷1:协议 2340字节 (保存256字节) (保存256字节) (保存256字节) (保存256字节) (保存256字节) (保存256字节) (保存256字节) (保存256字节) 256字节 到应用程序 到应用程序 (HOLE)序号(6 9 1 3)并不是下一个期望的序号( 6 6 5 7)。T C P保存2 5 6字节的数据,并返回一个已成 功接收数据的最大序号加 1(6 6 5 7)的A C K。被v a n g o g h接收到的后面 7个报文段(48, 50, 52, 54, 55, 57和5 9)也是失序的,接收方T C P保存这些数据并产生重复A C K。 目前T C P尚无办法告诉对方缺少一个报文段,也无法确认失序数据。此时主机 v a n g o g h 所能够做的就是继续发送确认序号为 6 6 5 7的A C K。 当缺少的报文段(报文段 6 3)到达时,接收方T C P在其缓存中保存第 6 6 5 7 ~ 8 9 6 0字节的数 据,并将这2 3 0 4字节的数据交给用户进程。所有这些数据在报文段 7 2中进行确认。请注意此 时该A C K通告窗口大小为5 8 8 8(8 1 9 2-2 3 0 4),这是因为用户进程没有机会读取这些已准备好 的2 3 0 4字节的数据。 如果仔细检查图21-6 中t c p d u m p的输出中第1 4和2 1秒附近的下垂点,我们会看到它们也 是由于收到了3个重复A C K引起的,这表明一个分组已经丢失。在这些例子中只有一个分组被 重传。 在介绍完拥塞避免算法后,将在第 2 1 . 8节中继续讨论这个例子。 21.6 拥塞避免算法 在第2 0 . 6节介绍的慢启动算法是在一个连接上发起数据流的方法,但有时我们会达到中间 路由器的极限,此时分组将被丢弃。拥塞避免算法是一种处理丢失分组的方法。该方法的具 体描述见 [Jacobson 1988]。 该算法假定由于分组受到损坏引起的丢失是非常少的(远小于 1 %),因此分组丢失就意 味着在源主机和目的主机之间的某处网络上发生了拥塞。有两种分组丢失的指示:发生超时 和接收到重复的确认(我们在 2 1 . 5节看到这种现象。如果使用超时作为拥塞指示,则需要使 用一个好的RT T算法,正如在2 1 . 3节中描述的那样)。 拥塞避免算法和慢启动算法是两个目的不同、独立的算法。但是当拥塞发生时,我们希 望降低分组进入网络的传输速率,于是可以调用慢启动来作到这一点。在实际中这两个算法 通常在一起实现。 拥塞避免算法和慢启动算法需要对每个连接维持两个变量:一个拥塞窗口 c w n d和一个慢 启动门限s s t h re s h。这样得到的算法的工作过程如下: 1) 对一个给定的连接,初始化 c w n d为1个报文段,s s t h re s h为6 5 5 3 5个字节。 2) TCP输出例程的输出不能超过 c w n d和接收方通告窗口的大小。拥塞避免是发送方使用 的流量控制,而通告窗口则是接收方进行的流量控制。前者是发送方感受到的网络拥塞的估 计,而后者则与接收方在该连接上的可用缓存大小有关。 3) 当拥塞发生时(超时或收到重复确认),s s t h re s h被设置为当前窗口大小的一半( c w n d 和接收方通告窗口大小的最小值,但最少为 2个报文段)。此外,如果是超时引起了拥塞,则 c w n d被设置为1个报文段(这就是慢启动)。 4) 当新的数据被对方确认时,就增加 c w n d,但增加的方法依赖于我们是否正在进行慢启 动或拥塞避免。如果 c w n d小于或等于s s t h re s h,则正在进行慢启动,否则正在进行拥塞避免。 慢启动一直持续到我们回到当拥塞发生时所处位置的半时候才停止(因为我们记录了在步骤 2 中给我们制造麻烦的窗口大小的一半),然后转为执行拥塞避免。 慢启动算法初始设置 c w n d为1个报文段,此后每收到一个确认就加 1。正如2 0 . 6节描述的 第21章 TCP的超时与重传使用235那样,这会使窗口按指数方式增长:发送 1个报文段,然后是2个,接着是4个⋯⋯。 拥塞避免算法要求每次收到一个确认时将 c w n d增加1 /c w n d。与慢启动的指数增加比起来, 这是一种加性增长(additive increase)。我们希望在一个往返时间内最多为 c w n d增加1个报文段 (不管在这个 RT T中收到了多少个 A C K),然而慢启动将根据这个往返时间中所收到的确认的 个数增加c w n d。 所有的4 . 3 B S D版本和4 . 4 B S D都在拥塞避免中将增加值不正确地设置为 1个报文段 的一小部分(即一个报文段的大小除以 8),这是错误的,并在以后的版本中不再使用 [Floyd 1994]。但是,为了和(不正确的)实现的结果对应,我们在将来的计算中给出 了这个细节。 在[Leffler et al. 1989]中介绍的4.3BSD Tahoe版本仅在对方处于一个不同的网络上时 才进行慢启动。而4.3BSD Reno版本改变了这种做法,因此,慢启动总是被执行。 图2 1 - 8是慢启动和拥塞避免的一个可视化描述。我们以段为单位来显示 c w n d和s s t h re s h, 但它们实际上都是以字节为单位进行维护的。 图21-8 慢启动和拥塞避免的可视化描述 在该图中,假定当 c w n d为3 2个报文段时就会发生拥塞。于是设置 s s t h re s h为1 6个报文段, 而c w n d为1个报文段。在时刻 0发送了一个报文段,并假定在时刻 1接收到它的 A C K,此时 c w n d增加为2。接着发送了2个报文段,并假定在时刻 2接收到它们的A C K,于是c w n d增加为4 (对每个A C K增加1次)。这种指数增加算法一直进行到在时刻 3和4之间收到8个A C K后c w n d等 于s s t h re s h时才停止,从该时刻起, c w n d以线性方式增加,在每个往返时间内最多增加 1个报 文段。 正如我们在这个图中看到的那样,术语“慢启动”并不完全正确。它只是采用了比引起 拥塞更慢些的分组传输速率,但在慢启动期间进入网络的分组数增加的速率仍然是在增加的。 只有在达到s s t h re s h拥塞避免算法起作用时,这种增加的速率才会慢下来。 21.7 快速重传与快速恢复算法 拥塞避免算法的修改建议 1 9 9 0年提出 [Jacobson 1990b]。在我们的例子(见 2 1 . 5节)中已 236使用TCP/IP详解,卷1:协议 cwud (报文段) ssthresh 往返时间经可以看到这些实施中的修改。 在介绍修改之前,我们认识到在收到一个失序的报文段时, T C P立即需要产生一个 A C K (一个重复的A C K)。这个重复的A C K不应该被迟延。该重复的 A C K的目的在于让对方知道收 到一个失序的报文段,并告诉对方自己希望收到的序号。 由于我们不知道一个重复的 A C K是由一个丢失的报文段引起的,还是由于仅仅出现了几 个报文段的重新排序,因此我们等待少量重复的 A C K到来。假如这只是一些报文段的重新排 序,则在重新排序的报文段被处理并产生一个新的 A C K之前,只可能产生 1 ~ 2个重复的A C K。 如果一连串收到 3个或3个以上的重复A C K,就非常可能是一个报文段丢失了(我们在 2 1 . 5节 中见到过这种现象)。于是我们就重传丢失的数据报文段,而无需等待超时定时器溢出。这就 是快速重传算法。接下来执行的不是慢启动算法而是拥塞避免算法。这就是快速恢复算法。 在图2 1 - 7中可以看到在收到3个重复的A C K之后没有执行慢启动。相反,发送方进行重传, 接着在收到重传的A C K以前,发送了3个新的数据的报文段(报文段 67, 69和7 1)。 在这种情况下没有执行慢启动的原因是由于收到重复的 A C K不仅仅告诉我们一个分组丢 失了。由于接收方只有在收到另一个报文段时才会产生重复的 A C K,而该报文段已经离开了 网络并进入了接收方的缓存。也就是说,在收发两端之间仍然有流动的数据,而我们不想执 行慢启动来突然减少数据流。 这个算法通常按如下过程进行实现: 1) 当收到第3个重复的A C K时,将s s t h re s h设置为当前拥塞窗口 c w n d的一半。重传丢失的 报文段。设置c w n d为s s t h re s h加上3倍的报文段大小。 2) 每次收到另一个重复的 A C K时,c w n d增加1个报文段大小并发送 1个分组(如果新的 c w n d允许发送)。 3) 当下一个确认新数据的A C K到达时,设置c w n d为s s t h re s h(在第1步中设置的值)。这个 A C K应该是在进行重传后的一个往返时间内对步骤 1中重传的确认。另外,这个 A C K也应该 是对丢失的分组和收到的第 1个重复的A C K之间的所有中间报文段的确认。这一步采用的是拥 塞避免,因为当分组丢失时我们将当前的速率减半。 在下一节中我们将看到变量 c w n d和s s t h re s h的计算过程。 快速重传算法最早出现在 4.3BSD Ta h o e版本中,但它随后错误地使用了慢启动。 快速恢复算法出现在4.3BSD Reno版本中。 21.8 拥塞举例(续) 通过使用t c m d u m p和插口排错选项(在第 2 1 . 4节进行了介绍)来观察一个连接,就会在 发送每一个报文段时看到 c w n d和s s t h re s h的值。如果M S S为2 5 6字节,则c w n d和s s t h re s h的初始 值分别为2 5 6和6 5 5 3 5字节。每当收到一个 A C K时,我们可以看到 c w n d增加了一个M S S,取值 分别为512, 768, 1024, 1280等。假定不会发生拥塞,则最终拥塞窗口将超过接收方的通告窗 口,意味着通告窗口将对数据流进行限制。 一个更有趣的例子是观察在拥塞发生时的情况。使用与 2 1 . 4节同样的例子。当这个例子运 行时发生了4次拥塞。为建立连接而发送的初始 S Y N有一个因超时而引起的重传(见图 2 1 - 5), 接着在数据传输过程中有3个分组丢失(见图2 1 - 6)。 第21章 TCP的超时与重传使用237238使用TCP/IP详解,卷1:协议 图2 1 - 9显示了当初始 S Y N重传并接着发送了前 7个数据报文段时变量 c w n d和s s t h re s h的值 (在图2 1 - 2中显示了最初的数据报文段及其 A C K之间的交换过程)。使用t c p d u m p的记号来表 示数据字节:1 : 2 5 7 ( 2 5 6 )表示第1 ~ 2 5 6字节。 当S Y N的超时发生时,s s t h re s h被置为其最小取值( 5 1 2字节,在本例中表示 2个报文段)。 为进入慢启动阶段,c w n d被置为1个报文段(2 5 6字节,与当前值一致)。 当收到S Y N和A C K时,没有对这两个变量做任何修改,因为新的数据还没有被确认。 当ACK 257到达时,因为c w n d小于等于s s t h re s h,因此仍然处于慢启动阶段,于是将 c w n d 增加2 5 6字节。当收到ACK 513时,进行同样的处理。 当ACK 769到达时,我们不再处于慢启动状态,而是进入了拥塞避免状态。新的 c w n d值 按以下方法计算: 考虑到c w n d实际上以字节而非以报文段来维护,因此这就是我们前面提到的增加 1 /c w n d。 在这个例子中我们计算 为8 8 5字节(使用整数算法)。当下一个ACK 1025到达时,我们计算 为9 9 1字节(在这些表达式中包括了不正确的 2 5 6 / 8项来匹配实现计算的数值,正如我们在前 面标注的那样)。 图21-9 拥塞避免的例子 这个c w n d持续增加一直到在图 2 1 - 6所示的发生在 1 0秒左右的第1次重传。图2 1 - 1 0是使用 与图2 1 - 6相同数据得到的图表,并给出了 c w n d增加的数值。 本图中c w n d的前6个值就是我们为图2 1 - 9所计算的数值。在这个图中,要想直观分辨出在 慢启动过程中的指数增加和在拥塞避免过程中的线性增加之间的区别是不可能的,因为慢启 动的过程太快。 报文段号 (图21-2) 发送 接收 行 为 变 量 注释 初始化 超时重传 慢启动 慢启动我们需要解释在重传的 3个点上所发生的情况。回想起每个重传都是因为收到 3个重复的 A C K,表明1个分组丢失了。这就是 2 1 . 7节的快速重传算法。 s s t h re s h立即设置为当重传发生 时正在起作用的窗口大小的一半,但是在接收到重复 A C K的过程中c w n d允许保持增加,这是 因为每个重复的A C K表示1个报文段已离开了网络(接收 T C P已缓存了这个报文段,等待所缺 数据的到达)。这就是快速恢复算法。 与图2 0 - 9类似,图2 1 - 1 0表示了c w n d和s s t h re s h的数值。第一列上的报文段编号与图 2 1 - 7对 应。 图21-10 当数据被发送时的发送序号和cwnd的取值 图21-11 拥塞避免的例子 c w n d的值一直持续增加,从图 2 1 - 9中对应于报文段1 2的最终取值(1 0 8 9)到图2 1 - 11中对 应于报文段5 8的第一个取值(2 4 2 6),而s s t h re s h的值则保持不变( 5 1 2),这是因为在此过程 中没有出现过重传。 当最初的2个重复的A C K(报文段6 0和6 1)到达时它们被计数,而 c w n d保持不变(也就 是图2 1 - 1 0中处理重传之前的平坦的一段)。然而,当第3个重复的A C K到达时,s s t h re s h被置 第21章 TCP的超时与重传使用239 序号 发送时间(秒) 序号(千字节)和 cwnd(100字节) 接收发送 报文段号 (图21-7) 行 为 变 量 注释 新数据的确认 重复 重复 重复 重复 重复 重复 重复 重复 新数据的确认 重传为c w n d的一半(四舍五入到报文段大小的下一个倍数),而c w n d被置为s s t h re s h加上所收到的 重复的A C K数乘以报文段大小(也即1 0 2 4加上3倍的2 5 6),然后发送重传数据。 又有5个重复的A C K到达(报文段64~66, 68和7 0),每次c w n d增加1个报文段长度。最后 一个新的A C K(报文段7 2段)到达时,c w n d被置为s s t h re s h(1 0 2 4)并进入正常的拥塞避免过 程。由于c w n d小于等于s s t h re s h(现在相等),因此报文段的大小增加到 c w n d,取值为1 2 8 0。 当下一个新的A C K到达(没有在图2 1 - 11中表示出来)时,c w n d大于s s t h re s h,取值为1 3 6 3。 在快速重传和快速恢复阶段,我们收到报文段 6 6、6 8和7 0中的重复的A C K后才发送新的 数据,而不是在接收到报文段 6 4和6 5中重复的A C K之后就发送。这是 c w n d的取值与未被确认 的数据大小比较的结果。当报文段 6 5到达时, c w n d为2 0 4 8,但未被确认的数据有 2 3 0 4字节 (9个报文段:46, 48, 50, 52, 54, 55, 57, 59和6 3),因此不能发送任何数据。当报文段6 5到达后, c w n d被置为2 3 0 4,此时我们仍不能进行发送。但是当报文段 6 6到达时,c w n d为2 5 6 0,所以我 们可以发送1个新的数据报文段。类似地,当报文段 6 8到达时,c w n d等于2 8 1 6,该数值大于未 被确认的2 5 6 0字节的数据大小,因此我们可以发送另 1个新的数据报文段。报文段 7 0到达时也 进行了类似的处理。 在图2 1 - 1 0中的时刻1 4 . 3发生下一个重传,也是因为收到了 3个重复的A C K。因此当另一 个A C K到达时,可以看到c w n d以同样的方式增长,之后降低到 1 0 2 4。 图2 1 - 1 0中的时刻2 1 . 1也是因为收到了重复的 A C K而引起了重传。在重传后收到了 3个重 复的A C K,因此观察到c w n d增加3个,之后降低到 1 2 8 0。在传输的后面部分, c w n d以线性方 式增加到最终值3 6 1 5。 21.9 按每条路由进行度量 较新的T C P实现在路由表项中维持许多我们在本章已经介绍过的指标。当一个 T C P连接关 闭时,如果已经发送了足够多的数据来获得有意义统计资料,且目的结点的路由表项不是一 个默认的表项,那么下列信息就保存在路由表项中以备下次使用:被平滑的 RT T、被平滑的 均值偏差以及慢启动门限。所谓“足够多的数据”是指 1 6个窗口的数据,这样就可得到 1 6个 RT T采样,从而使被平滑的RT T过滤器能够集中在正确结果的 5 %以内。 而且,管理员可以使用 r o u t e ( 8 )命令来设置给定路由的度量:前一段中给出的三个指标以 及M T、输出的带宽时延乘积(见第 2 0 . 7节)和输入的带宽时延乘积。 当建立一个新的连接时,不论是主动还是被动,如果该连接将要使用的路由表项已经有 这些度量的值,则用这些度量来对相应的变量进行初始化。 21.10 ICMP的差错 让我们来看一下 T C P是怎样处理一个给定的连接返回的 I C M P的差错。T C P能够遇到的最 常见的I C M P差错就是源站抑制、主机不可达和网络不可达。 当前基于伯克利的实现对这些错误的处理是: • 一个接收到的源站抑制引起拥塞窗口 c w n d被置为1个报文段大小来发起慢启动,但是慢 启动门限s s t h re s h没有变化,所以窗口将打开直至它或者开放了所有的通路(受窗口大 小和往返时间的限制)或者发生了拥塞。 • 一个接收到的主机不可达或网络不可达实际上都被忽略,因为这两个差错都被认为是 240使用TCP/IP详解,卷1:协议短暂现象。这有可能是由于中间路由器被关闭而导致选路协议要花费数分钟才能稳定 到另一个替换路由。在这个过程中就可能发生这两个 I C M P差错中的一个,但是连接 并不必被关闭。相反, T C P试图发送引起该差错的数据,尽管最终有可能会超时(回 想图 2 1 - 1中T C P在9分钟内没有放弃的情况)。当前基于伯克利的实现记录发生的 I C M P差错,如果连接超时, I C M P差错被转换为一个更合适的的差错码而不是“连接 超时”。 早期的B S D实现在任何时候收到一个主机不可达或网络不可达的 I C M P差错时会不 正确的放弃连接。 一个例子 可以通过在连接中拨号 S L I P链路的断开来观察一个 I C M P主机不可达的差错是如何被处理 的。建立一个从主机 s l i p到主机a i x的连接(从扉页前的图中可以看到这个连接经过了我们 的拨号S L I P链路)。在建立连接并发送一些数据之后,在路由器 s u n和n e t b之间的S L I P链路 被断开,这引起s u n上的默认路由表项(见 9 . 2节)被移去。我们希望 s u n对目的为1 4 0 . 2 5 2 . 1 以太网的I P数据报响应I C M P主机不可达。希望观察T C P如何处理这些I C M P差错。 下面是主机s l i p的交互会话: 图2 1 - 1 2显示了在路由器 b s d i上截获的t c p d u m p的相应输出(去掉了连接建立和所有的 窗口通告)。我们连接到在主机 a i x上的回显服务器并键入“ test line”(第1行),它被回显 (第2行)且回显被确认(第3行),接着我们断开了S L I P链路。 我们键入“another line”(第3行之后)并希望看到T C P超时和重传报文。的确,这一行在 收到应答前被发送了6次。第4 ~ 1 3行显示了第1次传输和接着的4次重传,每个都产生了一个来 自路由器s u n的I C M P主机不可达。这正是我们所希望的:从 s l i p来的I P数据报发往路由器 b s d i(这是一个指向s u n的默认路由器),并到达检测到链路中断的 s u n。 在发生这些重传时, S L I P链路又被连通,在第 1 4行的重传被交付。第 1 5行是来自a i x的 回显,而第1 6行是对这个回显的确认。 这表明T C P忽略I C M P主机不可达的差错并坚持重传。我们也可以观察到所预期的在每一 次重传超时中的指数退避:第 1次约为2 . 5秒,接着乘2(约5秒),乘4(约1 0秒),乘8(约2 0 秒),乘1 4(约4 0秒)。 接着我们键入输入的第3行(“line number 3”)并看到它在第1 7行被发送,在第1 8行回显, 并在第1 9行对回显进行确认。 第21章 TCP的超时与重传使用241 运行sock程序 键入本行 和它的回显 此时挂断SLIP链路 然后键入本行并观察其行为 该行及其回显被交换 SLIP链路此时重新建立, 此时挂断SLIP链路,且没有重新建立 TCP最终放弃图21-12 TCP对接收到的ICMP主机不可达差错的处理 现在我们希望观察在接收到 I C M P主机不可达后, T C P重传并放弃的情况。于是再次断开 S L I P链路,之后键入“the last line”,并观察到在T C P放弃之前该行被发送了1 3次(我们已经 从结果中删除了第3 0 ~ 4 3行,它们是额外的重传)。 然而,我们所观察到的现象是 s o c k程序在最终放弃时打印出来的差错信息:“没有到达 主机的路由”。这与U n i x的I C M P主机不可达的差错类似(图 6 - 1 2)。这表明T C P保存了它在连 接上收到的I C M P差错,并在最终放弃时打印出该差错,而不是“连接超时”。 最后,注意到第2 2 ~ 4 6行与第6 ~ 1 4行不同的重传间隔。看起来我们键入的第 3行在第1 7 ~ 1 9 行被发送和确认时(无任何重传),T C P更新了它的估计器。最初的重传超时时间现在是 3秒, 后续取值为6, 12, 24, 48,直至上限6 4。 242使用TCP/IP详解,卷1:协议 SLIP链路此时被挂断 SLIP链路此时被建立 SLIP链路此时被挂断 在这里14行输出结果被删除21.11 重新分组 当T C P超时并重传时,它不一定要重传同样的报文段。相反, T C P允许进行重新分组而发 送一个较大的报文段,这将有助于提高性能(当然,这个较大的报文段不能够超过接收方声 明的M S S)。在协议中这是允许的,因为 T C P是使用字节序号而不是报文段序号来进行识别它 所要发送的数据和进行确认。 在实际中,可以很容易地看到这一点。我们使用 s o c k程序连接到丢弃服务器并键入一行。 接着拔掉以太网电缆并再键入一行。当这一行被重传时,键入第 3行。我们预期下一个重传包 含第2次和第3次键入的数据。 bsdi % sock svr4 discard hello there 第一行发送成功 接着我们断开以太网电缆 line number 2 本行被重传 and 3 在第2行发送成功之前键入本行 接着重新连接以太网电缆 图2 1 - 1 3显示了t c p d u m p的输出(去掉了连接建立、连接终止以及所有的窗口通告)。 图21-13 TCP对数据的重新分组 第1行和第2行显示了头一行(“hello there”)被发送及其A C K。接着我们拔掉以太网电缆 并键入“line number 2”(1 4字节,包括换行)。这些数据在第3行被发送,并在第4和第5行被 重传。 在第6行重传前,我们键入“ and 3”(6个字节,包括换行),并观察到这个重传包括 2 0个 字节:键入的两行。当A C K在第9行到达时,它确认了这2 0字节的数据。 21.12 小结 本章提供了对T C P超时和重传机制的详细研究。使用的第 1个例子是一个丢失的建立连接 的S Y N,并观察了在随后的重传和超时中怎样使用指数退避方式。 T C P计算往返时间并使用这些测量结果来维护一个被平滑的 RT T估计器和被平滑的均值偏 差估计器。这两个估计器用来计算下一个重传时间。许多实现对每个窗口仅测量一次 RT T。 K a r n算法在分组丢失时可以不测量 RT T就能解决重传的二义性问题。 第21章 TCP的超时与重传使用243 此时断开以太网电缆 此时键入第3行 此时重新连接以太网电缆详细例子包括3个丢失的分组,使我们看到 T C P的许多实际算法:慢启动、拥塞避免、快 速重传和快速恢复。我们也能够使用拥塞窗口和慢启动门限来手工计算 TCP RT T估计器,并 将这些值与跟踪输出的实际数据进行比较。 以多种I C M P差错对 T C P连接的影响以及 T C P怎样允许对数据进行重新分组来结束本章。 我们观察到“软”的 I C M P差错没有引起T C P连接终止,但这些差错被保存以便在连接非正常 中止时能够报告这些软差错。 习题 21.1 在图2 1 - 5中第1个超时时间计算为 6秒而第2个为1 2秒。如果初始S Y N的确认在1 2秒超时 溢出时还没有到达,则下一次超时在什么时候发生? 21.2 在图2 1 - 5后面的讨论中,我们提到计算的超时间隔分别为图 4 - 5中表示的6、2 4和4 8秒。 但是如果观察一个从S V R 4系统到一个不存在的主机的连接,则超时间隔分别为 6, 12, 24 和4 8秒。请问发生了什么情况? 21.3 按下面的描述比较 T C P滑动窗口协议与 T F T P的停止等待协议的性能。在本章中,我们 在3 5秒(图2 1 - 6)内传输3 2 7 6 8字节的数据,其中链路的平均 RT T是1 . 5秒(图2 1 - 4)。计 算在同样条件下T F T P需要多长时间? 21.4 在第2 1 . 7节,我们提到过收到一个重复的 A C K是因为一个报文段丢失或重新进行排序。 在2 1 . 5节我们看到1个丢失的报文段产生一些重复的 A C K。请画图表示重新排序也会产 生一些重复的A C K。 21.5 在图2 1 - 6中的时刻2 8 . 8和2 9 . 8之间有一个显而易见的点,请问这是不是一个重传? 21.6 在2 1 . 6节我们提到过,如果目的地址位于一个不同的网络上, 4.3BSD Ta h o e版本只执行 慢启动。你认为在这里“不同的网络”是由什么决定的?(提示:参看附录 E)。 21.7 在2 0 . 2节我们提到过,在正常情况下, T C P每隔一个报文段进行一次确认,但是在图 2 1 - 2中,我们看到接收方对每个报文段都进行了确认,请解释其中的原因? 21.8 如果默认路由占优势,那么每路由( p e r- r o u t e)的度量是否真的有用? 244使用TCP/IP详解,卷1:协议第22章 TCP的坚持定时器 22.1 引言 我们已经看到 T C P通过让接收方指明希望从发送方接收的数据字节数(即窗口大小)来 进行流量控制。如果窗口大小为 0会发生什么情况呢?这将有效地阻止发送方传送数据,直到 窗口变为非0为止。 可以在图2 0 - 3中看到这种情况。当发送方接收到报文段 9时,它打开被报文段 8关闭的窗 口并立即开始发送数据。 T C P必须能够处理打开此窗口的 A C K(报文段9)丢失的情况。A C K 的传输并不可靠,也就是说, T C P不对A C K报文段进行确认, T C P只确认那些包含有数据的 A C K报文段。 如果一个确认丢失了,则双方就有可能因为等待对方而使连接终止:接收方等待接收数 据(因为它已经向发送方通告了一个非 0的窗口),而发送方在等待允许它继续发送数据的窗 口更新。为防止这种死锁情况的发生,发送方使用一个坚持定时器 (persist timer)来周期性地 向接收方查询,以便发现窗口是否已增大。这些从发送方发出的报文段称为窗口探查 ( w i n d o w p r o b e )。在本章中,我们将讨论窗口探查和坚持定时器,还将讨论与坚持定时器有关的糊涂窗 口综合症。 22.2 一个例子 为了观察到实际中的坚持定时器,我们启动一个接收进程。它监听来自客户的连接请求, 接受该连接请求,然后在从网上读取数据前休眠很长一段时间。 s o c k程序可以通过指定一个暂停选项 - P使服务器在接受连接和进行第一次读动作之间进 入休眠。我们以这种方式调用服务器: svr4 % sock -i -s -P100000 5555 该命令在从网络上读数据之前休眠 100 000秒(2 7 . 8小时)。客户运行在主机 b s d i上,并 向服务器的5 5 5 5端口执行1 0 2 4字节的写操作。图 2 2 - 1给出了t c p d u m p的输出结果(我们已经 在结果中去掉了连接的建立过程)。 报文段1 ~ 1 3显示的是从客户到服务器的正常的数据传输过程,有 9 2 1 6个字节的数据填充 了窗口。服务器通告窗口大小为 4 0 9 6字节,且默认的插口缓存大小为 4 0 9 6字节。但实际上它 一共接收了9 2 1 6字节的数据,这是在S V R 4中T C P代码和流子系统(stream subsystem)之间某种 形式交互的结果。 在报文段1 3中,服务器确认了前面 4个数据报文段,然后通告窗口为 0,从而使客户停止 发送任何其他的数据。这就引起客户设置其坚持定时器。如果在该定时器时间到时客户还没 有接收到一个窗口更新,它就探查这个空的窗口以决定窗口更新是否丢失。由于服务器进程 处于休眠状态,所以T C P缓存9 2 1 6字节的数据并等待应用进程读取。 请注意客户发出的窗口探查之间的时间间隔。在收到一个大小为 0的窗口通告后的第 1个(报文段1 4)间隔为4 . 9 4 9秒,下一个(报文段1 6)间隔是4 . 9 9 6秒,随后的间隔分别约为 6, 12, 24, 48和6 0秒。 图22-1 坚持定时器探查一个0大小窗口的例子 为什么这些间隔总是比5、6、1 2、2 4、4 8和6 0小一个零点几秒呢?因为这些探查被T C P的500 ms 定时器超时例程所触发。当定时器时间到时,就发送窗口探查,并大约在4 ms之后收到一个应答。 接收到应答使得定时器被重新启动,但到下一个时钟滴答之间的时间则约为5 0 0减4 ms。 计算坚持定时器时使用了普通的 T C P指数退避。对一个典型的局域网连接,首次超时时 间算出来是1 . 5秒,第2次的超时值增加一倍,为 3秒,再下次乘以 4为6秒,之后再乘以 8为1 2 秒等。但是坚持定时器总是在 5 ~ 6 0秒之间,这与我们在图2 2 - 1中观察到的现象一致。 窗口探查包含一个字节的数据(序号为 9 2 1 7)。T C P总是允许在关闭连接前发送一个字节 的数据。请注意,尽管如此,所返回的窗口为 0的A C K并不是确认该字节(它们确认了包括 9 2 1 6在内的所有数据),因此这个字节被持续重传。 坚持状态与第 2 1章中介绍的重传超时之间一个不同的特点就是 T C P从不放弃发送窗口探 查。这些探查每隔 6 0秒发送一次,这个过程将持续到或者窗口被打开,或者应用进程使用的 连接被终止。 22.3 糊涂窗口综合症 基于窗口的流量控制方案,如 T C P所使用的,会导致一种被称为“糊涂窗口综合症 S W S 246使用TCP/IP详解,卷1:协议(Silly Window Syndrome)”的状况。如果发生这种情况,则少量的数据将通过连接进行交换, 而不是满长度的报文段[Clark 1982]。 该现象可发生在两端中的任何一端:接收方可以通告一个小的窗口(而不是一直等到有 大的窗口时才通告),而发送方也可以发送少量的数据(而不是等待其他的数据以便发送一个 大的报文段)。可以在任何一端采取措施避免出现糊涂窗口综合症的现象。 1) 接收方不通告小窗口。通常的算法是接收方不通告一个比当前窗口大的窗口(可以为0), 除非窗口可以增加一个报文段大小(也就是将要接收的 M S S)或者可以增加接收方缓存空间 的一半,不论实际有多少。 2) 发送方避免出现糊涂窗口综合症的措施是只有以下条件之一满足时才发送数据: ( a )可 以发送一个满长度的报文段; ( b )可以发送至少是接收方通告窗口大小一半的报文段; ( c )可以 发送任何数据并且不希望接收 A C K(也就是说,我们没有还未被确认的数据)或者该连接上 不能使用N a g l e算法(见第1 9 . 4节)。 条件( b )主要对付那些总是通告小窗口(也许比 1个报文段还小)的主机,条件 ( c )使我们 在有尚未被确认的数据(正在等待被确认)以及在不能使用 N a g l e算法的情况下,避免发送小 的报文段。如果应用进程在进行小数据的写操作(例如比该报文段还小),条件( c )可以避免出 现糊涂窗口综合症。 这三个条件也可以让我们回答这样一个问题:在有尚未被确认数据的情况下,如果 N a g l e 算法阻止我们发送小的报文段,那么多小才算是小呢?从条件 ( a )中可以看出所谓“小”就是 指字节数小于报文段的大小。条件 ( b )仅用来对付较老的、原始的主机。 步骤2中的条件( b )要求发送方始终监视另一方通告的最大窗口大小,这是一种发送方猜测 对方接收缓存大小的企图。虽然在连接建立时接收缓存的大小可能会减小,但在实际中这种 情况很少见。 一个例子 现在我们通过仔细查看一个详细的例子来观察实际避免出现糊涂窗口综合症的情况,该 例子也包括了坚持定时器。我们将在发送主机 s u n上运行s o c k程序,并向网络写 6个1 0 2 4字 节的数据。 sun % sock -i -n6 bsdi 7777 但是在主机b s d i的接收过程中我们加入一些暂停。在第 1次读数据前暂停4秒,之后每次读 之前暂停2秒。而且,接收方进行的是 2 5 6字节的读操作: bsdi % sock -i -s -P4 -p2 -r256 7777 最初的暂停是为了让接收缓存被填满,迫使发送方停止发送。随后由于接收方从网络上 进行了一些小数目的读取,我们预期能看到接收方采取的避免糊涂窗口综合症的措施。 图2 2 - 2是传输6 1 4 4字节数据的时间系列(我们去掉了连接建立过程)。 我们还需要跟踪在每个时间点上读取数据时应用程序的运行情况、当前正在接收缓存中 的数据的序号以及接收缓存中可用空间的大小。图 2 2 - 3显示了所发生的每件事情。 图2 2 - 3中的第1列是每个行为的相对时间点。那些带有3位小数点的时间是从t c p d u m p的输 出结果(图2 2 - 2)中得到的,而小数点部分为 9 9的则是在接收服务器上产生行为的估计时间 (使这些在接收方的估计时间包含一秒的9 9 %仅与图2 2 - 2中的报文段2 0和2 2有关,它们是我们能 第22章 TCP的坚持定时器使用247够从t c p d u m p的输出结果中看到的由接收主机超时引起的仅有的两个事件。而在主机 b s d i上 观察到的其他分组,则是由接收到来自发送方的一个报文段所引起的。这同样是有意义的,因 为这就使我们可以将最初的 4秒暂停刚好放置在发送方发送第 1个数据报文段的时间 0前面。这 是接收方在连接建立过程中收到它的S Y N的A C K之后将要获得控制权的大致时间)。 图22-2 显示接收方避免出现糊涂窗口综合症的时间系列 当接收到来自发送方的数据时,接收方缓存中的数据增加,而当应用进程从缓存中读取 数据时,数据就减少。接下来我们关注的是接收方发给发送方的窗口通告以及这些窗口通告 是什么。这样就可以使我们看到接收方是如何避免糊涂窗口综合症的。 前4个数据报文段及其A C K(报文段1 ~ 5)表示发送方正在填充接收方的缓存。在那个时刻 发送方停止了发送,但仍然有更多的数据需要发送。它将自己的坚持定时器置为最小值 5分钟。 当坚持定时器时间到时,就发送出 1个字节的数据(报文段 6)。接收的应用进程已经从接 收缓存中读取了2 5 6字节的数据(在时刻 3 . 9 9),因此这个字节被接受并被确认(报文段 7段)。 但是通告窗口仍为0,由于接收方仍然没有足够的空间来接收一个满长度的报文,或者不能腾 248使用TCP/IP详解,卷1:协议出缓存空间的一半。这就是接收方的糊涂窗口避免措施。 图22-3 接收方避免出现糊涂窗口综合症的事件序列 发送方的坚持定时器被复位,并在 5秒后再次到时(在时刻1 0 . 1 5 1)。然后又发送一个字节 并被确认(报文段8和9),而接收方的缓存空间还不够用(1 0 2 2字节),使得通告窗口为0。 发送方的坚持定时器在时刻 1 5 . 1 5 1再次时间到,又发送了另一个字节并被确认(报文段 1 0和11)。这一次由于接收方有 1 5 3 3字节的有效缓存空间,因此通告了一个非 0窗口。发送方 立即利用这个窗口发送了1 0 2 4字节的数据(报文段1 2)。对这1 0 2 4字节数据的确认(报文段1 3) 通告其窗口为5 0 9字节。这看起来与我们在前面看到的小窗口通告相抵触。 在这里之所以发生这种情况,是因为报文段 11段通告了一个大小为 1 5 3 3字节的窗口,而 发送方只使用了其中的1 0 2 4字节。如果在报文段1 3中的A C K通告其窗口为0,就会违反窗口的 右边沿不能向左边沿移动而导致窗口收缩的 T C P原则(见第2 0 . 3节)。这就是为什么必须通告 第22章 TCP的坚持定时器使用249 时间 发送TCP 接收TCP 行 为 应用 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取256 读取2 5 6 ( E O F ) 数据 可用的 接收缓冲区报文段号 (图22-2)一个5 0 9字节的窗口的原因。 接下来我们看到发送方没有立即向这个小窗口发送数据。这就是发送方采取的糊涂窗口 避免策略。相反,它等待另一个坚持定时器在时刻 2 0 . 1 5 1到时间,并在该时刻发送 5 0 9字节的 数据。尽管它最终还是发送了一个长度为 5 0 9字节的小数据段,但在发送前它等待了 5秒钟, 看是否会有一个A C K到达,以便可以将窗口开得更大。这 5 0 9字节的数据使得接收缓存仅剩下 7 6 8字节的有效空间,因此接收方通告窗口为 0(报文段1 5)。 坚持定时器在时刻 2 5 . 1 5 1再次到时间,发送方发送 1个字节,于是接收缓存中有 1 2 7 9字节 的可用空间,这就是在报文段 1 7所通告的窗口大小。 发送方只有另外的5 11个字节的数据需要发送,因此在收到 1 2 7 9的窗口通告后立刻发送了 这些数据(报文段 1 8)。这个报文段也带有 F I N标志。接收方确认数据和 F I N,并通告窗口大 小为7 6 7(见习题2 2 . 2)。 由于发送应用进程在执行完 6个1 0 2 4字节的写操作后发出关闭命令,发送方的连接从 E S TA B L I S H E D状态转变到F I N _ WA I T _ 1状态,再到F I N _ WA I T _ 2状态(见图1 8 - 1 2)。它一直 处于这个状态,直到收到对方的 F I N。在这个状态上没有设置定时器(回忆我们在 1 8 . 6节结束 时的讨论),因为它在报文段 1 8中发送的F I N被报文段1 9确认。这就是为什么我们看到发送方 直到接收到F I N(报文段2 1)为止没有发送其他任何数据的原因。 接收应用进程继续每隔 2秒从接收缓存区中读取 2 5 6个字节的数据。为什么在时刻 3 9 . 9 9发 送A C K(报文段2 0)呢?这是因为应用进程在时刻 3 9 . 9 9读取数据时,接收缓存中的可用空间 已经从原来通告的7 6 7(报文段1 9)变为2 8 1 6,这相当于接收缓存中增加了额外的 2 0 4 9字节的 空间。回忆本节开始讲的第 1个规则,因为现在接收缓存已经增加了其空间的一半,因此接收 方现在发送窗口更新。这意味着每次当应用进程从 T C P的接收缓存中读取数据时,接收的 T C P 将检查是否需要更新发送窗口。 应用进程在时间5 1 . 9 9发出最后一个读操作,然后收到一个文件结束标志,因为缓存已经 变空。这就导致了最后两个完成连接终止的报文段(报文段 2 1和2 2)的发送。 22.4 小结 在连接的一方需要发送数据但对方已通告窗口大小为0时,就需要设置T C P的坚持定时器。发送 方使用与第2 1章类似的重传间隔时间,不断地探查已关闭的窗口。这个探查过程将一直持续下去。 当运行一个例子来观察坚持定时器时,我们还观察到了 T C P的避免出现糊涂窗口综合症 的现象。这就是使 T C P避免通告小的窗口大小或发送小的报文段。在我们的例子中,可以观 察到发送方和接收方为避免糊涂窗口综合症所使用的策略。 习题 22.1 在图2 2 - 3中注意到所有确认(报文段5、7、9、11、1 3、1 5和1 7)的发送时刻为:0.170, 5.170、 1 0 . 1 7 0、1 5 . 1 7 0、2 0 . 1 7 0和2 5 . 1 7 0,还注意到在接收数据和发送A C K之间的时间差分别为: 1 6 4 . 5、1 8 . 5、1 8 . 7、1 8 . 8、1 9 8 . 3、1 8 . 5和19.1 ms。试解释可能会发生的情况。 22.2 在图2 2 - 3中的时刻2 5 . 1 7 4,发送出一个7 6 7字节的通告窗口,而在接收缓存中有 7 6 8字节 的可用空间。为什么相差1个字节? 250使用TCP/IP详解,卷1:协议第23章 TCP的保活定时器 23.1 引言 许多T C P / I P的初学者会很惊奇地发现可以没有任何数据流通过一个空闲的 T C P连接。也 就是说,如果T C P连接的双方都没有向对方发送数据,则在两个T C P模块之间不交换任何信息。 例如,没有可以在其他网络协议中发现的轮询。这意味着我们可以启动一个客户与服务器建 立一个连接,然后离去数小时、数天、数个星期或者数月,而连接依然保持。中间路由器可 以崩溃和重启,电话线可以被挂断再连通,但是只要两端的主机没有被重启,则连接依然保 持建立。 这意味着两个应用进程— 客户进程或服务器进程— 都没有使用应用级的定时器来检 测非活动状态,而这种非活动状态可以导致应用进程中的任何一个终止其活动。回想在第 1 0 . 7节末尾曾提到过的B G P每隔3 0秒就向对端发送一个应用的探查,就是独立于 T C P的保活定 时器之外的应用定时器。 然而,许多时候一个服务器希望知道客户主机是否崩溃并关机或者崩溃又重新启动。许 多实现提供的保活定时器可以提供这种能力。 保活并不是T C P规范中的一部分。Host Requirements RFC提供了3个不使用保活定 时器的理由:(1) 在出现短暂差错的情况下,这可能会使一个非常好的连接释放掉; (2)它们耗费不必要的带宽;(3)在按分组计费的情况下会在互联网上花掉更多的钱。 然而,许多实现提供了保活定时器。 保活定时器是一个有争论的功能。许多人认为如果需要,这个功能不应该在 T C P中提供, 而应该由应用程序来完成。这是应当认真对待的一些问题之一,因为在这个论题上有些人表 达出了很大的热情。 在连接两个端系统的网络出现临时故障的时候,保活选项会引起一个实际上很好的连接 终止。例如,如果在一个中间路由器崩溃并重新启动时发送保活探查,那么 T C P会认为客户 的主机已经崩溃,而实际上所发生的并非如此。 保活功能主要是为服务器应用程序提供的。服务器应用程序希望知道客户主机是否崩溃, 从而可以代表客户使用资源。许多版本的 R l o g i n和Te l n e t服务器默认使用这个选项。 一个说明现在需要使用保活功能的常见例子是当个人计算机用户使用 T C P / I P向一个使用 Te l n e t的主机注册时。如果在一天结束时,他们仅仅关闭了电源而没有注销,那么便会留下一 个半开放的连接。在图1 8 - 1 6中,我们看到通过一个半开放连接发送数据会导致返回一个复位, 但那是在来自正在发送数据的客户端。如果客户已经消失了,使得在服务器上留下一个半开 放连接,而服务器又在等待来自客户的数据,则服务器将永远等待下去。保活功能就是试图 在服务器端检测到这种半开放的连接。23.2 描述 在这个描述中,我们称使用保活选项的一端为服务器,而另一端则为客户。并没有什么 使客户不能使用这个选项,但通常都是服务器设置这个功能。如果双方都特别需要了解对方 是否已经消失,则双方都可以使用这个选项(在 2 9章我们将看到N F S使用T C P时,客户和服务 器都设置了这个选项。但在第 2 6章讲到Te l n e t和R l o g i n时,只有服务器设置了这个选项,而客 户则没有)。 如果一个给定的连接在两个小时之内没有任何动作,则服务器就向客户发送一个探查报 文段(我们将在随后的例子中看到这个探查报文段看起来像什么)。客户主机必须处于以下 4 个状态之一。 1) 客户主机依然正常运行,并从服务器可达。客户的 T C P响应正常,而服务器也知道对 方是正常工作的。服务器在两小时以后将保活定时器复位。如果在两个小时定时器到时间之 前有应用程序的通信量通过此连接,则定时器在交换数据后的未来 2小时再复位。 2) 客户主机已经崩溃,并且关闭或者正在重新启动。在任何一种情况下,客户的 T C P都 没有响应。服务器将不能够收到对探查的响应,并在 7 5秒后超时。服务器总共发送 1 0个这样 的探查,每个间隔 7 5秒。如果服务器没有收到一个响应,它就认为客户主机已经关闭并终止 连接。 3) 客户主机崩溃并已经重新启动。这时服务器将收到一个对其保活探查的响应,但是这 个响应是一个复位,使得服务器终止这个连接。 4) 客户主机正常运行,但是从服务器不可达。这与状态 2相同,因为T C P不能够区分状态 4与状态2之间的区别,它所能发现的就是没有收到探查的响应。 服务器不用关注客户主机被关闭和重新启动的情况(这指的是一个操作员的关闭,而不 是主机崩溃)。当系统被操作员关闭时,所有的应用进程也被终止(也就是客户进程),这会 使客户的T C P在连接上发出一个 F I N。接收到F I N将使服务器的T C P向服务器进程报告文件结 束,使服务器可以检测到这个情况。 在第1种情况下,服务器的应用程序没有感觉到保活探查的发生。 T C P层负责一切。这个 过程对应用程序都是透明的,直至第 2、3或4种情况发生。在这三种情况下,服务器应用程序 将收到来自它的 T C P的差错报告(通常服务器已经向网络发出了读操作请求,然后等待来自 客户的数据。如果保活功能返回一个差错,则该差错将作为读操作的返回值返回给服务器)。 在第2种情况下,差错是诸如“连接超时”之类的信息,而在第 3种情况则为“连接被对方复 位”。第4种情况看起来像是连接超时,也可根据是否收到与连接有关的 I C M P差错来返回其他 的差错。在下一节中我们将观察这 4种情况。 一个被人们不断讨论的关于保活选项的问题就是两个小时的空闲时间是否可以改 变。通常他们希望该数值可以小得多,处在分钟的数量级。正如我们在附录 E看到的, 这个值通常可以改变,但是在该附录所描述的所有系统中,保活间隔时间是系统级的 变量,因此改变它会影响到所有使用该功能的用户。 Host Requirements RFC提到一个实现可提供保活的功能,但是除非应用程序指明 要这样,否则就不能使用该功能。而且,保活间隔必须是可配置的,但是其默认值必 须不小于两个小时。 252使用TCP/IP详解,卷1:协议23.3 保活举例 现在详细讨论前一节提到的第 2、3和4种情况。我们将在使用这个选项的情况下检查所交 换的分组。 23.3.1 另一端崩溃 首先观察另一端崩溃且没有重新启动的情况下所发生的现象。为模拟这种情况,我们采 用如下步骤: • 在客户(主机b s d i上运行的s o c k程序)和主机s v r 4上的标准回显服务器之间建立一 个连接。客户使用- K选项使能保活功能。 • 验证数据可以通过该连接。 • 观察客户T C P每隔2小时发送保活分组,并观察被服务器的 T C P确认。 • 将以太网电缆从服务器上拔掉直到这个例子完成,这会使客户认为服务器主机已经崩 溃。 • 我们预期服务器在断定连接已中断前发送 1 0个间隔为7 5秒的保活探查。 这里是客户端的交互输出结果: bsdi % sock -K svr4 echo -K是保活选项 hello, world 开始时键入本行以验证连接有效 hello, world 和看到回显 4小时后断开以太网电缆 read error: Connection timed out 这发生在启动后约6小时1 0分钟 图2 3 - 1显示的是t c p d u m p的输出结果(已经去掉了连接建立和窗口通告)。 图23-1 决定一个主机已经崩溃的保活分组 客户在第1、2和3行向服务器发送“Hello, world”并得到回显。第4行是第一个保活探查, 发生在两个小时以后( 7 2 0 0秒)。在第6行的T C P报文段能够发送之前,首先观察到的是一个 A R P请求和一个A R P应答。第6行的保活探查引出来自另一端的响应(第 7行)。两个小时以后, 在第7和8行发生了同样的分组交换过程。 第23章 TCP的保活定时器使用253如果能够观察到第6和第1 0行的保活探查中的所有字段,我们就会发现序号字段比下一个 将要发送的序号字段小 1(在本例中,当下一个为 1 4时,它就是1 3)。但是因为报文段中没有 数据, t c p d u m p不能打印出序号字段(它仅能够打印出设置了 S Y N、F I N或R S T标志的空数 据的序号)。正是接收到这个不正确的序号,才导致服务器的 T C P对保活探查进行响应。这个 响应告诉客户,服务器下一个期望的序号是 1 4。 一些基于4 . 2 B S D的旧的实现不能够对这些保活探查进行响应,除非报文段中包含 数据。某些系统可以配置成发送一个字节的无用数据来引出响应。这个无用数据是无 害的,因为它不是所期望的数据(这是接收方前一次接收并确认的数据),因此它会被 接收方丢弃。其他一些系统在探查的前半部分发送4.3BSD格式的报文段(不包含数据), 如果没有收到响应,在后半部分则切换为4.2BSD格式的报文段。 接着我们拔掉电缆,并期望两个小时的再一次探查失败。当这下一个探查发生时,注意 到从来没有看到电缆上出现 T C P报文段,这是因为主机没有响应 A R P请求。在放弃之前,我 们仍可以观察到客户每隔 7 5秒发送一个探查,一共发送了 1 0次。从交互式脚本可以看到返回 给客户进程的差错码被T C P转换为“连接超时”,这正是实际所发生的。 23.3.2 另一端崩溃并重新启动 在这个例子中,我们可以观察到当客户崩溃并重新启动时发生的情况。最初的环境与前 一个例子相似,但是在我们验证连接有效之后,我们将服务器从以太网上断开,重新启动, 然后再连接到网络上。我们希望看到下一个保活探查产生一个来自服务器的复位,因为现在 服务器不知道关于这个连接的任何信息。这是交互会话的过程: bsdi % sock -K svr4 echo -K使保活选项有效 hi, there 键入这行以验证连接有效 hi, there 这是来自另一端的回显 从以太网断连后,服务器这时重新启动 read error: Connection reset by peer 图2 3 - 2显示的是t c p d u m p的输出结果(已经去掉了连接建立和窗口通告)。 图23-2 另一端崩溃并重启时保活的例子 我们建立了连接,并从客户发送 9个字节的数据到服务器(第 1 ~ 3行)。两个小时之后,客 户发送第1个保活探查,其响应是一个来自服务器的复位。客户应用进程打印出“连接被对端 复位”的差错,这是有意义的。 23.3.3 另一端不可达 在这个例子中,客户没有崩溃,但是在保活探查发送后的 1 0分钟内无法到达,可能是一 个中间路由器已经崩溃,或一条电话线临时出现故障,或发生了其他一些类似的情况。 254使用TCP/IP详解,卷1:协议为了仿真这个例子,我们从主机 s l i p经过一个拨号 S L I P链路与主机 v a n g o g h . c s . b e r k e l e y . e d u建立一个连接,然后断掉链路。这里是交互输出的结果: bsdi % sock -K vangogh.cs.berkeley.edu echo t e s t i n g 我们键入这行 testing 看到这行的回显 在某个时刻这条S L I P链路被断开 read error: No route to host 图2 3 - 3显示了在路由器b s d i上收集到的t c p d u m p输出结果(已经去掉了连接建立和窗口通告)。 图23-3 当另一端不可达时的保活例子 我们与以前一样开始讨论这个例子:第 1 ~ 3行证实连接是有效的。两个小时之后的第 1个 保活探查是正常的(第 4、5行),但是在两个小时后发生下一个探查之前,我们断开在路由器 s u n和n e t b之间的S L I P连接(拓扑结构参见封)。 第6行的保活探查引发一个来自路由器 s u n的I C M P网络不可达的差错。正如我们在第 2 1 . 1 0节描述的那样,对于主机 s l i p上接收的T C P而言,这只是一个软差错。它报告收到了一 个I C M P差错,但是差错的接收者并没有终止这个连接。在发送主机最终放弃之前,一共发送 了9个保活探查,间隔为 7 5秒。这时返回给应用进程的差错产生了一个不同的报文:“没有到 达主机的路由”。我们在图6 - 1 2看到这对应于I C M P网络不可达的差错。 23.4 小结 正如我们在前面提到的,对保活功能是有争议的。协议专家继续在争论该功能是否应该 归入运输层,或者应当完全由应用层来处理。 在连接空闲两个小时后,在一个连接上发送一个探查分组来完成保活功能。可能会发生 4 种不同的情况:对端仍然运行正常、对端已经崩溃、对端已经崩溃并重新启动以及对端当前无 法到达。我们使用一个例子来观察每一种情况,并观察到在最后三个条件下返回的不同差错。 在前两个例子中,如果没有提供这种功能,并且也没有应用层的定时器,则客户将永远 无法知道对端已经崩溃或崩溃并重新启动。可是在最后一个例子中,两端都没有发生差错, 只是它们之间的连接临时中断。我们在使用保活时必须关注这个限制。 习题 23.1 列出保活功能的一些优点。 23.2 列出保活功能的一些缺点。 第23章 TCP的保活定时器使用255 删除14行第24章 TCP的未来和性能 24.1 引言 T C P已经在从1200 b/s的拨号S L I P链路到以太数据链路上运行了许多年。在 8 0年代和9 0年 代初期,以太网是运行 T C P / I P最主要的数据链路方式。虽然 T C P在比以太网速率高的环境 (如T 2电话线、F D D I及千兆比网络)中也能够正确运行,但在这些高速率环境下, T C P的某 些限制就会暴露出来。 本章讨论T C P的一些修改建议,这些建议可以使 T C P在高速率环境中获得最大的吞吐量。 首先要讨论前面已经碰到过的路径 M T U发现机制,本章主要关注它如何与 T C P协同工作。这 个机制通常可以使T C P为非本地的连接使用大于5 3 6字节的M T U,从而增加吞吐量。 接着介绍长肥管道(long fat pipe),也就是那些具有很大的带宽时延乘积的网络,以及 T C P 在这些网络上所具有的局限性。为处理长肥管道,我们描述两个新的 T C P选项:窗口扩大选 项(用来增加 T C P的最大窗口,使之超过 6 5 5 3 5字节)和时间戳选项。后面这个选项可以使 T C P对报文段进行更加精确的 RT T测量,还可以在高速率下对可能发生的序号回绕提供保护。 这两个选项在RFC 1323 [Jacobson, Braden, and Borman 1992]中进行定义。 我们还将介绍建议的T / T C P,这是为增加事务功能而对 T C P进行的修改。通信的事务模式 以客户的请求将被服务器应答的响应为主要特征。这是客户服务器计算的常见模型。 T / T C P 的目的就是减少两端交换的报文段数量,避免三次握手和使用 4个报文段进行连接的关闭,从 而使客户可以在一个RT T和处理请求所必需的时间内收到服务器的应答。 这些新选项(路径 M T U发现、窗口扩大选项、时间戳选项和 T / T C P)中令人印象最深刻 的就是它们与现有的 T C P实现能够向后兼容,即包括这些新选项的系统仍然可以与原有的旧 系统进行交互。除了在一个 I C M P报文中为路径M T U发现增加了一个额外字段之外,这些新的 选项只需要在那些需要使用它们的端系统中进行实现。 我们以介绍近来发表的有关 T C P性能的图例作为本章的结束。 24.2 路径MTU发现 在2 . 9节我们描述了路径M T U的概念。这是当前在两个主机之间的路径上任何网络上的最 小M T U。路径M T U发现在I P首部中继承并设置“不要分片( D F)”比特,来发现当前路径上 的路由器是否需要对正在发送的 I P数据报进行分片。在 11 . 6节我们观察到如果一个待转发的 I P 数据报被设置 D F比特,而其长度又超过了 M T U,那么路由器将返回 I C M P不可达的差错。在 11 . 7节我们显示了某版本的 t r a c e r o u t e程序使用该机制来决定目的地的路径 M T U。在11 . 8 节我们看到 U D P是怎样处理路径 M T U发现的。在本节我们将讨论这个机制是如何按照 R F C 1191 [Mogul and Deering 1990]中规定的那样在T C P中进行使用的。 在本书的多种系统(参看序言)中只有Solaris 2.x支持路径MTU发现。T C P的路径M T U发现按如下方式进行:在连接建立时, T C P使用输出接口或对端声明的 M S S中的最小M T U作为起始的报文段大小。路径 M T U发现不允许T C P超过对端声明的 M S S。 如果对端没有指定一个 M S S,则默认为5 3 6。一个实现也可以按 2 1 . 9节中讲的那样为每个路由 单独保存路径M T U信息。 一旦选定了起始的报文段大小,在该连接上的所有被 T C P发送的I P数据报都将被设置 D F 比特。如果某个中间路由器需要对一个设置了 D F标志的数据报进行分片,它就丢弃这个数据 报,并产生一个我们在11 . 6节介绍的I C M P的“不能分片”差错。 如果收到这个I C M P差错,T C P就减少段大小并进行重传。如果路由器产生的是一个较新 的该类I C M P差错,则报文段大小被设置为下一跳的 M T U减去I P和T C P的首部长度。如果是一 个较旧的该类I C M P差错,则必须尝试下一个可能的最小 M T U(见图2 - 5)。当由这个I C M P差 错引起的重传发生时,拥塞窗口不需要变化,但要启动慢启动。 由于路由可以动态变化,因此在最后一次减少路径 M T U的一段时间以后,可以尝试使用 一个较大的值(直到等于对端声明的 M S S或输出接口M T U的最小值)。RFC 11 9 1推荐这个时 间间隔为1 0分钟(我们在11 . 8节看到Solaris 2.2使用一个3 0分钟的时间间隔)。 在对非本地目的地,默认的 M S S通常为5 3 6字节,路径M T U发现可以避免在通过 M T U小 于5 7 6(这非常罕见)的中间链路时进行分片。对于本地目的主机,也可以避免在中间链路 (如以太网)的 M T U小于端点网络(如令牌环网)的情况下进行分片。但为了能使路径 M T U 更加有用和充分利用 M T U大于5 7 6的广域网,一个实现必须停止使用为非本地目的制定的 5 3 6 的M T U默认值。M S S的一个较好的选择是输出接口的 M T U(当然要减去I P和T C P的首部大小) (在附录E中,我们将看到大多数的实现都允许系统管理员改变这个默认的 M S S值)。 24.2.1 一个例子 在某个中间路由器的 M T U比任一个端点接口M T U小的情况下,我们能够观察路径 M T U发 现是如何工作的。图2 4 - 1显示了这个例子的拓扑结构。 图24-1 路径MTU例子的拓扑结构 我们从主机s o l a r i s(支持路径M T U发现机制)到主机 s l i p建立一个连接。这个建立 过程与U D P的路径M T U发现(图11 - 1 3)中的一个例子相同,但在这里我们已经把 s l i p接口 的M T U设置为5 5 2,而不是通常的 2 9 6。这使得s l i p通告一个5 1 2的M S S。但是在b s d i上的 S L I P链路上的 M T U为2 9 6,这就引起超过 2 5 6的T C P报文段被分片。于是就可以观察在 s o l a r i s上的路径M T U发现是如何进行处理的。 我们在s o l a r i s上运行s o c k程序并向s l i p上的丢弃服务器进行一个5 1 2字节的写操作: 第24章 TCP的未来和性能使用257 512字节的报文 段在此处分片 此处运行 tcpdump TCP连接solaris % sock -i -n1 -w512 slip discard 图2 4 - 2是在主机s u n的S L I P接口上收集的t c p d u m p的输出结果。 图24-2 路径MTU发现的t c p d u m p 输出结果 在第1和第2行的M S S值是我们所期望的。接着我们观察到 s o l a r i s发送一个包含5 1 2字节的 数据和对S Y N的确认报文段(第 3行)(在习题1 8 . 9中可以看到这种把 S Y N的确认与第一个包 含数据的报文段合并的情况)。这就在第4行产生了一个 I C M P差错,我们看到路由器 b s d i产 生较新的、包含输出接口M T U的I C M P差错。 看来在这个差错回到s o l a r i s之前,就发送了F I N(第5行)。由于s l i p从没有收到被路由 器b s d i丢弃的5 1 2字节的数据,因此并不期望接收这个序号( 5 1 3),所以在第6行用它期望的 序号(1)进行了响应。 在这个时候,I C M P差错返回到了s o l a r i s,s o l a r i s用两个2 5 6字节的报文段(第 7和 第9行)重传了5 1 2字节的数据。因为在b s d i后面可能还有具有更小的 M T U的路由器,因此这 两个报文段都设置了D F比特。 接着是一个较长的传输过程(持续了大约 1 5分钟),在最初的5 1 2字节变为2 5 6字节以后, s o l a r i s没有再尝试使用更大的报文段。 24.2.2 大分组还是小分组 常规知识告诉我们较大的分组比较好 [Mogul 1993, 15.2.8节],因为发送较少的大分组比 发送较多的小分组“花费”要少(假定分组的大小不足以引起分片,否则会引起其他方面的 问题)。这些减少的花费与网络(分组首部负荷)、路由器(选路的决定)和主机(协议处理 和设备中断)等有关。但并非所有的人都同意这种观点 [Bellovin 1993]。 考虑下面的例子。我们通过 4个路由器发送8 1 9 2个字节,每个路由器与一个 T 1电话线(1 544 000b/s)相连。首先我们使用两个 4 0 9 6字节的分组,如图2 4 - 3所示。 基本问题在于路由器是存储转发设备。它们通常接收整个输入分组,检验包含 I P检验和 的I P首部,进行选路判决,然后开始发送输出分组。在这个图中,我们可以假定在理想情况 下这些在路由器内部进行的操作不花费时间(水平点状线)。然而,从R 1到R 4它需要花费4个 258使用TCP/IP详解,卷1:协议单位时间来发送所有的8 1 9 2字节。每一跳的时间为 图24-3 通过4个路由器发送两个4096字节的分组 (将T C P和I P的首部算为4 0字节)。发送数据的整个时间为分组个数加上跳数减 1,从图中 可以看到是4个单位时间,或8 5 . 6秒。每个链路空闲2个单位时间,或4 2 . 8秒。 图2 4 - 4显示了当我们发送1 6个5 1 2字节的分组时所发生的情况。 图24-4 通过4个路由器发送16个512字节的分组 这将花费更多的单位时间,但是由于发送的分组较短,因此每个单位时间较小。 现在总时间为(1 8×2 . 9)=52.2 ms。每个链路也空闲2个单位的时间,即5.8 ms。 在这个例子中,我们忽略了确认返回所需要的时间、连接建立和终止以及链路可能被其 他流量共享等的影响。然而,在 [Bellovin 1993]中的测量表明,分组并不一定是越大越好。我 们需要在更多的网络上对该领域进行更多的研究。 24.3 长肥管道 在2 0 . 7节,我们把一个连接的容量表示为 c a p a c i t y (b) = b a n d w i d t h (b/s) × ro u n d-t r i p t i m e ( s ) 并称之为带宽时延乘积。也可称它为两端的管道大小。 当这个乘积变得越来越大时, T C P的某些局限性就会暴露出来。图 2 4 - 5显示了多种类型的 网络的某些数值。 第24章 TCP的未来和性能使用259 (4096字节+40字节)×8 b/字节 1 544 000 b/s =21.4 ms/跳 ( 5 1 2字节+ 4 0字节)×8 b/字节 1 544 000 b/s =2.9 ms/跳图24-5 多种网络的带宽时延乘积 可以看到带宽时延乘积的单位是字节,这是因为我们用这个单位来测量每一端的缓存大小和 窗口大小。 具有大的带宽时延乘积的网络被称为长肥网络( Long Fat Network,即L F N,发音为 “e l e f a n ( t ) s”),而一个运行在 L F N上的T C P连接被称为长肥管道。回顾图 2 0 - 11和图2 0 - 1 2,管 道可以被水平拉长(一个长的 RT T),或被垂直拉高(较高的带宽),或向两个方向拉伸。使 用长肥管道会遇到多种问题。 1) T C P首部中窗口大小为 16 bit,从而将窗口限制在 6 5 5 3 5个字节内。但是从图 2 4 - 5的最 后一列可以看到,现有的网络需要一个更大的窗口来提供最大的吞吐量。在 2 4 . 4节介 绍的窗口扩大选项可以解决这个问题。 2) 在一个长肥网络 L F N内的分组丢失会使吞吐量急剧减少。如果只有一个报文段丢失, 我们需要利用 2 1 . 7节介绍的快速重传和快速恢复算法来使管道避免耗尽。但是即使使 用这些算法,在一个窗口内发生的多个分组丢失也会典型地使管道耗尽(如果管道耗 尽了,慢启动会使它渐渐填满,但这个过程将需要经过多个 RT T)。 在RFC 1072 [Jacobson and Braden 1988]中建议使用有选择的确认( S A C K)来处理在 一个窗口发生的多个分组丢失。但是这个功能在 RFC 1323中被忽略了,因为作者觉得 在把它们纳入T C P之前需要先解决一些技术上的问题。 3) 我们在第2 1 . 4节看到许多T C P实现对每个窗口的RT T仅进行一次测量。它们并不对每个 报文段进行RT T测量。在一个长肥网络 L F N上需要更好的RT T测量机制。我们将在 2 4 . 5 节介绍时间戳选项,它允许更多的报文段被计时,包括重传。 4) T C P对每个字节数据使用一个32 bit无符号的序号来进行标识。如果在网络中有一个被延迟 一段时间的报文段,它所在的连接已被释放,而一个新的连接在这两个主机之间又建立了, 怎样才能防止这样的报文段再次出现呢?首先回想起I P首部中的T T L为每个I P段规定了一 个生存时间的上限— 2 5 5跳或2 5 5秒,看哪一个上限先达到。在1 8 . 6节我们定义了最大的 报文段生存时间(M S L)作为一个实现的参数来阻止这种情况的发生。推荐的M S L的值为 2分钟(给出一个2 4 0秒的2 M S L),但是我们在1 8 . 6节看到许多实现使用的M S L为3 0秒。 在长肥网络L F N上,T C P的序号会碰到一个不同的问题。由于序号空间是有限的,在 已经传输了4 294 967 296个字节以后序号会被重用。如果一个包含序号 N字节数据的报 文段在网络上被迟延并在连接仍然有效时又出现,会发生什么情况呢?这仅仅是一个 相同序号N在M S L期间是否被重用的问题,也就是说,网络是否足够快以至于在不到 一个M S L的时候序号就发生了回绕。在一个以太网上要发送如此多的数据通常需要 6 0 分钟左右,因此不会发生这种情况。但是在带宽增加时,这个时间将会减少:一个 T 3 的电话线(45 Mb/s)在1 2分钟内会发生回绕,F D D I(100 Mb/s)为5分钟,而一个千 兆比网络(1000 Mb/s)则为3 4秒。这时问题不再是带宽时延乘积,而在于带宽本身。 260使用TCP/IP详解,卷1:协议 网 络 带宽(b/s) RTT(ms) 带宽时延乘积 (字节) 以太局域网 横跨大陆的T1电话线 卫星T1电话线 横跨大陆的T3电话线 横跨大陆的gigabit线路在2 4 . 6节,我们将介绍一种对付这种情况的办法:使用 T C P的时间戳选项的 PAW S (Protection Against Wrapped Sequence numbers)算法(保护回绕的序号)。 4 . 4 B S D包含了我们将要在下面介绍的所有选项和算法:窗口扩大选项、时间戳选 项和保护回绕的序号。许多供应商也正在开始支持这些选项。 千兆比网络 当网络的速率达到千兆比的时候,情况就会发生变化。 [Partridge 1994]详细介绍了千兆比 网络。在这里我们看一下在时延和带宽之间的差别 [Kleinrock 1992]。 考虑通过美国发送一个 1 0 0万字节的文件的情况,假定时延为 30 ms。图2 4 - 6显示了两种 情况:上图显示了使用一个 T 1电话线(1 544 000 b/s)的情况,而下图则是使用一个 1 Gb/s网 络的情况。x轴显示的是时间,发送方在图的左侧,而接收方则在图的右侧, y轴为网络容量。 两幅图中的阴影区域表示发送的 1 0 0万字节。 图24-6 以30 ms的延时通过网络发送100万字节的文件 图2 4 - 6显示了30 ms后这两个网络的状态。经过 30 ms(延时)以后数据的第1个比特都已到达 对端。但对T 1网络而言,由于管道容量仅为 5 790字节,因此发送方仍然有 994 210个字节等 待发送。而千兆比网络的容量则为 3 750 000字节,因此,整个文件仅使用了 2 5%左右的带宽, 此时文件的最后一个比特已经到达第 1个字节后8 ms处。 经过T 1网络传输文件的总时间为5 . 2 11秒。如果增加更多的带宽,使用一个T 3网络(45 000 000 b/s), 则总时间减少到0 . 2 0 8秒。增加约2 9倍的带宽可以将总时间减小到约2 5分之一。 使用千兆比网络传输文件的总时间为 0 . 0 3 8秒:30 ms的时延加上8 ms的真正传输文件的时 间。假定能够将带宽增加为 2000 Mb/s,我们只能够将总时间减小为 0.304 ms:同样30 ms的时 延和4 m s的真正传输时间。现在使带宽加倍仅能够将时间减少约 1 0%。在千兆比速率下,时延 限制占据了主要地位,而带宽不再成为限制。 时延主要是由光速引起的,而且不能够被减小(除非爱因斯坦是错误的)。当我们考虑到 分组需要建立和终止一个连接时,这个固定时延起的作用就更糟糕了。千兆比网络会引起一 些需要不同看待的连网观点。 第24章 TCP的未来和性能使用261 仍然等待发送的994 210字节 文件传输的方向 线路中的5 790字节 30 ms时延 8 ms 1 000 000字节 1Gb/s 1 544 000 b/s24.4 窗口扩大选项 窗口扩大选项使T C P的窗口定义从16 bit增加为32 bit。这并不是通过修改T C P首部来实现 的, T C P首部仍然使用 16 bit,而是通过定义一个选项实现对 16 bit的扩大操作 ( s c a l i n g o p e r a t i o n )来完成的。于是T C P在内部将实际的窗口大小维持为 32 bit的值。 在图1 8 - 2 0可以看到关于这个选项的例子。一个字节的移位记数器取值为 0(没有扩大窗 口的操作)和1 4。这个最大值1 4表示窗口大小为1 073 725 440字节(6 5 5 3 5×21 4)。 这个选项只能够出现在一个 S Y N报文段中,因此当连接建立起来后,在每个方向的扩大 因子是固定的。为了使用窗口扩大,两端必须在它们的 S Y N报文段中发送这个选项。主动建 立连接的一方在其 S Y N中发送这个选项,但是被动建立连接的一方只能够在收到带有这个选 项的S Y N之后才可以发送这个选项。每个方向上的扩大因子可以不同。 如果主动连接的一方发送一个非零的扩大因子,但是没有从另一端收到一个窗口扩大选 项,它就将发送和接收的移位记数器置为 0。这就允许较新的系统能够与较旧的、不理解新选 项的系统进行互操作。 Host Requirements RFC要求T C P接受在任何报文段中的一个选项(只有前面定义的一 个选项,即最大报文段大小,仅在S Y N报文段中出现)。它还进一步要求T C P忽略任何它 不理解的选项。这就使事情变得容易,因为所有新的选项都有一个长度字段(图1 8 - 2 0)。 假定我们正在使用窗口扩大选项,发送移位记数为 S,而接收移位记数则为 R。于是我们 从另一端收到的每一个 16 bit的通告窗口将被左移 R位以获得实际的通告窗口大小。每次当我 们向对方发送一个窗口通告的时候,我们将实际的 32 bit窗口大小右移S比特,然后用它来替 换T C P首部中的16 bit的值。 T C P根据接收缓存的大小自动选择移位计数。这个大小是由系统设置的,但是通常向应 用进程提供了修改途径(我们在 2 0 . 4节中讨论了这个缓存)。 一个例子 如果在4 . 4 B S D的主机v a n g o g h . c s . b e r k e l e y . e d u上使用 s o c k程序来初始化一个连 接,我们可以观察到它的 T C P计算窗口扩大因子的情况。下面的交互输出显示的是两个连续 运行的程序,第1个指定接收缓存为128 000字节,而第2个的缓存则为220 000字节。 图2 4 - 7显示了这两个连接的 t c p d u m p输出结果(去掉了第 2个连接的最后8行,因为没有 262使用TCP/IP详解,卷1:协议 我们键入这一行 此处是它的回显 键入文件结束字符以终止 我们键入这一行 此处是它的回显 键入文件结束字符以终止什么新内容)。 图24-7 窗口扩大选项的例子 在第1行,v a n g o g h通告一个6 5 5 3 5的窗口,并通过设置移位计数为 1来指明窗口扩大选项。 这个通告的窗口是比接收窗口( 128 000)还小的一个最大可能取值,因为在一个 S Y N报文段 中的窗口字段从不进行扩大运算。 扩大因子为1表示v a n g o g h发送窗口通告一直到131 070(6 5 5 3 5×21)。这将调节我们的接 收缓存的大小(12 8000)。因为b s d i在它的S Y N(第2行)中没有发送窗口扩大选项,因此这 个选项没有被使用。注意到v a n g o g h在随后的连接阶段继续使用最大可能的窗口(6 5 5 3 5)。 对于第2个连接v a n g o g h请求的移位计数为 2,表明它希望发送窗口通告一直为 262 140 (6 5 5 3 5×22),这比我们的接收缓存(220 000)大。 24.5 时间戳选项 时间戳选项使发送方在每个报文段中放置一个时间戳值。接收方在确认中返回这个数值, 从而允许发送方为每一个收到的 A C K计算RT T(我们必须说“每一个收到的 A C K”而不是 “每一个报文段”,是因为T C P通常用一个A C K来确认多个报文段)。我们提到过目前许多实现 为每一个窗口只计算一个 RT T,对于包含8个报文段的窗口而言这是正确的。然而,较大的窗 口大小则需要进行更好的RT T计算。 RFC 1323的3 . 1节给出了需要为较大窗口进行更好的 RT T计算的信号处理的理由。 通常RT T通过对一个数据信号(包含数据的报文段)以较低的频率(每个窗口一次) 进行采样来进行计算,这就将别名引入了被估计的RT T中。当每个窗口中有8个报文段 时,采样速率为数据率的1 / 8,这还是可以忍受的。但是如果每个窗口中有1 0 0个报文段 时,采样速率则为数据速率的1 / 1 0 0,这将导致被估计的RT T不精确,从而引起不必要 的重传。如果一个报文段被丢失,则会使情况变得更糟。 图1 8 - 2 0显示了时间戳选项的格式。发送方在第 1个字段中放置一个 32 bit的值,接收方在 应答字段中回显这个数值。包含这个选项的 T C P首部长度将从正常的2 0字节增加为3 2字节。 第24章 TCP的未来和性能使用263 该连接的其余部分被删除时间戳是一个单调递增的值。由于接收方只需要回显收到的内容,因此不需要关注时间 戳单元是什么。这个选项不需要在两个主机之间进行任何形式的时钟同步。 RFC 1323推荐在1 毫秒和1秒之间将时间戳的值加1。 4.4BSD在启动时将时间戳始终设置为0,然后每隔500 ms将时间戳时钟加1。 在图2 4 - 7中,如果观察在报文段1和报文段11的时间戳,它们之间的差(8 9个单元) 对应于每个单元500 ms的规定,因为实际时间差为44.4秒。 在连接建立阶段,对这个选项的规定与前一节讲的窗口扩大选项类似。主动发起连接的 一方在它的S Y N中指定选项。只有在它从另一方的 S Y N中收到了这个选项之后,该选项才会 在以后的报文段中进行设置。 我们已经看到接收方 T C P不需要对每个包含数据的报文段进行确认,许多实现每两个报 文段发送一个A C K。如果接收方发送一个确认了两个报文段的 A C K,那么哪一个收到的时间 戳应当放入回显应答字段中来发回去呢? 为了减少任一端所维持的状态数量,对于每个连接只保持一个时间戳的数值。选择何时 更新这个数值的算法非常简单: 1) TCP跟踪下一个A C K中将要发送的时间戳的值(一个名为 t s re c e n t的变量)以及最后发 送的A C K中的确认序号(一个名为l a s t a c k的变量)。这个序号就是接收方期望的序号。 2) 当一个包含有字节号 l a s t a c k的报文段到达时,则该报文段中的时间戳被保存在 t s re c e n t 中。 3) 无论何时发送一个时间戳选项, t s re c e n t就作为时间戳回显应答字段被发送,而序号字 段被保存在l a s t a c k中。 这个算法能够处理下面两种情况: 1) 如果A C K被接收方迟延,则作为回显值的时间戳值应该对应于最早被确认的报文段。 例如,如果两个包含 1 ~ 1 0 2 4和1 0 2 5 ~ 2 0 4 8字节的报文段到达,每一个都带有一个时间戳选项, 接收方产生一个ACK 2049来对它们进行确认。此时, A C K中的时间戳应该是包含字节 1 ~ 1 0 2 4 的第1个报文段中的时间戳。这种处理是正确的,因为发送方在进行重传超时时间的计算时, 必须将迟延的A C K也考虑在内。 2) 如果一个收到的报文段虽然在窗口范围内但同时又是失序,这就表明前面的报文段已 经丢失。当那个丢失的报文段到达时,它的时间戳(而不是失序的报文段的时间戳)将被回 显。例如,假定有3个各包含1 0 2 4字节数据的报文段,按如下顺序接收:包含字节 1 ~ 1 0 2 4的报 文段1,包含字节2 0 4 9 ~ 4 0 7 2的报文段3和包含字节1 0 2 5 ~ 2 0 4 8的报文段2。返回的A C K应该是 带有报文段1的时间戳的ACK 1025(一个正常的所期望的对数据的 A C K)、带有报文段1的时 间戳的ACK 1025(一个重复的、响应位于窗口内但却是失序的报文段的 A C K),然后是带有 报文段2的时间戳的ACK 3073(不是报文段3中的较后的时间戳)。这与当报文段丢失时的对 RT T估计过高具有同样的效果,但这比估计过低要好些。而且,如果最后的 A C K含有来自报 文段3的时间戳,它可以包括重复的 A C K返回和报文段2被重传所需要的时间,或者可以包括 发送方的报文段 2的重传超时定时器到期的时间。无论在哪一种情况下,回显报文段 3的时间 戳将引起发送方的RT T计算出现偏差。 尽管时间戳选项能够更好地计算 RT T,它还为发送方提供了一种方法,以避免接收到旧 的报文段,并认为它们是现在的数据的一部分。下一节将对此进行描述。 264使用TCP/IP详解,卷1:协议24.6 PAWS:防止回绕的序号 考虑一个使用窗口扩大选项的 T C P连接,其最大可能的窗口大小为 1千兆字节(23 0)(最 大的窗口是6 5 5 3 5×21 4,而不是21 6×21 4,但只比这个数值小一点点,并不影响这里的讨论)。 还假定使用了时间戳选项,并且由发送方指定的时间戳对每个将要发送的窗口加 1(这是保守 的方法。通常时间戳比这种方式增加得快)。图2 4 - 8显示了在传输6 千兆字节的数据时,在两 个主机之间可能的数据流。为了避免使用许多 1 0位的数字,我们使用G来表示1 073 741 824的 倍数。我们还使用了t c p d u m p的记号,即用J : K来表示通过了J字节的数据,且包括字节K- 1。 图24-8 在6个1千兆字节的窗口中传输6千兆字节的数据 32 bit的序号在时间D和时间E之间发生了回绕。假定一个报文段在时间 B丢失并被重传。还假 定这个丢失的报文段在时间 E重新出现。 这假定了在报文段丢失和重新出现之间的时间差小于 M S L,否则这个报文段在它的 T T L 到期时会被某个路由器丢弃。正如我们前面提到的,这种情况只有在高速连接上才会发生, 此时旧的报文段重新出现,并带有当前要传输的序号。 我们还可以从图 2 4 - 8中观察到使用时间戳可以避免这种情况。接收方将时间戳视为序列 号的一个32 bit的扩展。由于在时间E重新出现的报文段的时间戳为 2,这比最近有效的时间戳 小(5或6),因此PAW S算法将其丢弃。 PAW S算法不需要在发送方和接收方之间进行任何形式的时间同步。接收方所需要的就是 时间戳的值应该单调递增,并且每个窗口至少增加 1。 24.7 T/TCP:为事务用的TCP扩展 T C P提供的是一种虚电路方式的运输服务。一个连接的生存时间包括三个不同的阶段: 建立、数据传输和终止。这种虚电路服务非常适合诸如远程注册和文件传输之类的应用。 但是,还有出现其他的应用进程被设计成使用事务服务。一个事务 ( t r a n s a c t i o n )就是符合 下面这些特征的一个客户请求及其随后的服务器响应。 1) 应该避免连接建立和连接终止的开销,在可能的时候,发送一个请求分组并接收一个 应答分组。 2) 等待时间应当减少到等于RT T与S P T之和。其中RTT (Round-Trip Ti m e )为往返时间,而 SPT (Server Processing Ti m e )则是服务器处理请求的时间。 3) 服务器应当能够检测出重复的请求,并且当收到一个重复的请求时不重新处理事务 (避免重新处理意味着服务器不必再次处理请求,而是返回保存的、与该请求对应的应答)。 我们已经看到的一个使用这种类型服务的应用就是域名服务(第 1 4章),尽管D N S与服务 器重新处理重复的请求无关。 第24章 TCP的未来和性能使用265 时间 发送字节 发送序号 发送时间戳 接 收 正确,但有一个段丢失并重发 正确 正确 正确 正确 正确,但重发的段又出现了如今一个应用程序设计人员面对的一种选择是使用 T C P还是U D P。T C P提供了过多的事务 特征,而U D P提供的则不够。通常应用程序使用U D P来构造(避免T C P连接的开销),而许多需 要的特征(如动态超时和重传、拥塞避免等)被放置在应用层,一遍又一遍的重新设计和实现。 一个较好的解决方法是提供一个能够提供足够多的事务处理功能的运输层。我们在本节 所介绍的事务协议被称为 T / T C P。我们从它的定义,即 RFC 1379 [Braden 1992b]和[ B r a d e n 1 9 9 2 c ],开始介绍。 大多数的T C P需要使用7个报文段来打开和关闭一个连接(见图 1 8 - 1 3)。现在增加三个报 文段:一个对应于请求,一个对应于应答和对请求的确认,第三个对应于对应答的确认。如 果额外的控制比特被追加到报文段上— 也就是,第 1个报文段带有 S Y N、客户请求和一个 F I N— 客户仍然能够看到一个 2倍的RT T与S P T之和的最小开销(与数据一起发送一个 S Y N 和F I N是合法的;当前的T C P是否能够正确处理它们是另外一个问题)。 另一个与T C P有关的问题是 T I M E _ WA I T状态和它需要的 2 M S L的等待时间。正如在习题 1 8 . 1 4中看到的,这使两个主机之间的事务率降低到每秒 2 6 8个。 T C P为处理事务而需要进行的两个改动是避免三次握手和缩短 WA I T _ T I M E状态。T / T C P 通过使用加速打开来避免三次握手: 1) 它为打开的连接指定一个 32 bit的连接计数CC (Connection Count),无论主动打开还是 被动打开。一个主机的C C值从一个全局计数器中获得,该计数器每次被使用时加 1。 2) 在两个使用T / T C P的主机之间的每一个报文段都包括一个新的 T C P选项C C。这个选项 的长度为6个字节,包含发送方在该连接上的 32 bit的C C值。 3) 一个主机维持一个缓存,该缓存保留每个主机上一次的 C C值,这些值从来自这个主机 的一个可接受的S Y N报文段中获得。 4) 当在一个开始的S Y N中收到一个C C选项的时候,接收方比较收到的值与为该发送方缓 存的C C值。如果接收到的 C C比缓存的大,则该 S Y N是新的,报文段中的任何数据被 传递给接收应用进程(服务器)。这个连接被称为半同步。 如果接收的C C比缓存的小,或者接收主机上没有对应这个客户的缓存 C C,则执行正常 的T C P三次握手过程。 5) 为响应一个开始的 S Y N,带有S Y N和A C K的报文段在另一个被称为 C C E C H O的选项中 回显所接收到的C C值。 6) 在一个非S Y N报文段中的C C值检测和拒绝来自同一个连接的前一个替身的任何重复的 报文段。 这种“加速打开”避免了使用三次握手的要求,除非客户或者服务器已经崩溃并重新启 动。这样做的代价是服务器必须记住从每个客户接收的最近的 C C值。 基于在两个主机之间测量 RT T来动态计算T I M E _ WA I T的延时,可以缩短 T I M E _ WA I T状 态。T I M E _ WA I T时延被设置为8倍的重传超时值RTO(见2 1 . 3节)。 通过使用这些特征,最小的事务序列是交换三个报文段: 1) 由一个主动打开引起的客户到服务器:客户的 S Y N、客户的数据(请求)、客户的F I N 以及客户的C C。当被动的服务器T C P接收到这个报文段的时候,如果客户的 C C比为这 个客户缓存的C C要大,则客户的数据被传送给服务器应用程序进行处理。 2) 服务器到客户:服务器的 S Y N、服务器的数据(应答)、服务器的F I N、对客户的F I N 266使用TCP/IP详解,卷1:协议的A C K、服务器的C C以及客户的C C的C C E C H O。由于T C P的确认是累积的,这个对 客户的F I N的A C K也对客户的S Y N、数据及F I N进行了确认。 当客户T C P接收到这个报文段,就将其传送给客户应用进程。 3) 客户到服务器:对服务器的 F I N的A C K,它也确认了服务器的S Y N、数据和F I N。 客户对它的请求的响应时间为 RT T与S P T的和。 在参考资料中有许多关于实现这个 T C P选项的很好的地方。我们在这里将它们归纳如下: • 服务器的 S Y N和A C K(第2个报文段)必须被迟延,从而允许应答与它一起捎带发送 (通常对S Y N的A C K是不迟延的)。但它也不能迟延得太多,否则客户将超时并引起重 传。 • 请求可以需要多个报文段,但是服务器必须对它们可能失序达到的情况进行处理(通常 当数据在S Y N之前到达时,该数据被丢弃并产生一个复位。通过使用 T / T C P,这些失序 的数据将放入队列中处理)。 • A P I必须使服务器进程用一个单一的操作来发送数据和关闭连接,从而允许第二个报文 段中的F I N与应答一起捎带发送(通常应用进程先写应答,从而引起发送一个数据报文 段,然后关闭连接,引起发送 F I N)。 • 在收到来自服务器的 M S S通告之前,客户在第 1个报文段中正在发送数据。为避免限制 客户的M S S为5 3 6,一个给定主机的M S S应该与它的C C值一起缓存。 • 客户在没有接收到来自服务器的窗口通告之前也可以向服务器发送数据。 T / T C P建议默 认的窗口为4 0 9 6,并且也为服务器缓存拥塞门限。 • 使用最小3个报文段交换,在每个方向上只能计算一个 RT T。加上包括了服务器处理时 间的客户测量RT T。这意味着被平滑的 RT T及其方差的值也必须为服务器缓存起来,这 与我们在2 1 . 9节描述的类似。 T / T C P的特征中吸引人的地方在于它对现有协议进行了最小的修改,同时又兼容了现有的 实现。它还利用了 T C P中现有的工程特征(动态超时和重传、拥塞避免等),而不是迫使应用 进程来处理这些问题。 一个可作为替换的事务协议是通用报文事务协议 V M T P(Versatile Message Tr a n s a c t i o n P r o t o c o l),该协议在RFC 1045 [Cheriton 1988]中进行了描述。与 T / T C P是现有协议的一个小 的扩充不同,V M T P是使用I P的一个完整的运输层。 V M T P处理差错检测、重传和重复压缩。 它还支持多播通信。 24.8 TCP的性能 在8 0年代中期出版的数值显示出 T C P在一个以 太网上的吞吐量在每秒 100 000~200 000字节之间 ([Stevens 1990]的1 7 . 5节给出了参考文献)。从那时 起事情已经发生了许多改变。现在通常使用的硬件 (工作站和更快的个人电脑)每秒可以传输 800 000 字节或者更快。 在10 Mb/s的以太网上计算我们能够观察到的理 论上的T C P最大吞吐量是一件值得做的练习[ Wa r n o c k 第24章 TCP的未来和性能使用267 图24-9 计算以太网理论上最大 吞吐量的字段大小 字 段 ACK (字节) 数据 (字节) 以太网前导 以太网目的地址 以太网源地址 以太类型字段 IP首部 TCP首部 用户数据 填充字符 以太网CRC检验 分组间隙(9.6ms) 总计1 9 9 1 ]。我们可以在图2 4 - 9中看到这个计算的基础。这个图显示了满长度的数据报文段和一个 A C K交换的全部的字节。 我们必须计及所有的开销:前同步码、加到确认上的填充字节、循环冗余检验 C R C以及 分组之间的最小间隔(9 . 6 m s,相当在10 Mb/s速率下的1 2个字节)。 首先假定发送方传输两个背对背、满长度的数据报文段,然后接收方为这两个报文段发 送一个A C K。于是最大的吞吐量(用户数据)为: 如果T C P窗口开到它的最大值( 6 5 5 3 5,不使用窗口扩大选项),这就允许一个窗口容纳 4 4个 1 4 6 0字节的报文段。如果接收方每个报文段发送一个 A C K,则计算变为: 这就是理论上的限制,并做出某些假定:接收方发送的一个 A C K没有和发送方的报文段之一 在以太网上发生冲突;发送方可按以太网的最小间隔时间来发送两个报文段;接收方可以在 最小的以太网间隔时间内产生一个 A C K。不论在这些数字上多么乐观, [ Warnock 1991]在一 个以太网上使用标准的多用户工作站(即使是快的工作站)测量到了一个连续的 1 075 000字 节/秒的速率,这个值在理论值的 9 0%之内。 当移到更快的网络上时,如 F D D I(100 Mb/s),[Schryver 1993]指出三个商业厂家已经演 示了在F D D I上的T C P在80 Mb/s~90 Mb/s之间。即使在有更多带宽的环境下, [Borman 1992] 报告说两个Gray Y- M P计算机在一个800 Mb/s的H I P P I通道上最大值为781 Mb/s,而运行在一 个Gray Y- M P上的使用环回接口的两个进程间的速率为 907 Mb/s。 下面这些实际限制适用于任何的实际情况 [Borman 1991]。 1) 不能比最慢的链路运行得更快。 2) 不能比最慢的机器的内存运行得更快。这假定实现是只使用一遍数据。如果不是这样 (也就是说,实现使用一遍数据是将它从用户空间复制到内核中,而使用另一遍数据是计算 T C P的检验和),那么将运行得更慢。[Dalton et al. 1993]描述了将数据复制数目减少从而使一 个标准伯克利源程序的性能得到改进。 [Partridge and Pink 1993]将类似的“复制与检验和”的 改变与其他性能改进措施一道应用于 U D P,从而将U D P的性能提高了约3 0%。 3) 不能够比由接收方提供的窗口大小除以往返时间所得结果运行得更快(这就是带宽时 延乘积公式,使用窗口大小作为带宽时延乘积,并解出带宽)。如果使用2 4 . 4节的最大窗口扩 大因子1 4,则窗口大小为1.073 千兆字节,所以这除以RT T的结果就是带宽的极限。 所有这些数字的重要意义就是 T C P的最高运行速率的真正上限是由 T C P的窗口大小和光速 决定的。正如[Partridge and Pink 1993]中计算的那样,许多协议性能问题在于实现中的缺陷而 不是协议所固有的一些限制。 24.9 小结 本章已经讨论了五个新的 T C P特征:路径M T U发现、窗口扩大选项、时间戳选项、序号 回绕保护以及使用改进的 T C P事务处理。我们观察到中间的三个特征是为在长肥管道——具 有大的带宽时延乘积的网络— 上优化性能所需要的。 268使用TCP/IP详解,卷1:协议 throughput= throughput= =1 555 063 B/S =1 183 667 B/S 2×1460 B 22×1538 B+84 B 22×1460 B 22×1538 B+84 B 10 000 000 b/s 8 b/B 10 000 000 b/s 8 b/B × ×路径M T U发现在M T U较大时,对于非本地连接,允许 T C P使用比默认的 5 3 6大的窗口。 这样可以提高性能。 窗口扩大选项使最大的 T C P窗口从6 5 5 3 5增加到1千兆字节以上。时间戳选项允许多个报 文段被精确计时,并允许接收方提供序号回绕保护( PAW S)。这对于高速连接是必须的。这 些新的T C P选项在连接时进行协商,并被不理解它们的旧系统忽略,从而允许较新的系统与 旧的系统进行交互。 为事务用的T C P扩展,即T / T C P,允许一个客户/服务器的请求-应答序列在通常的情况下 只使用三个报文段来完成。它避免使用三次握手,并缩短了 T I M E _ WA I T状态,其方法是为每 个主机高速缓存少量的信息,这些信息曾用来建立过一个连接。它还在包含数据报文段中使 用S Y N和F I N标志。 由于还有许多关于T C P能够运行多快的不精确的传闻,因此我们以对 T C P性能的分析来结 束本章。对于一个使用本章介绍的较新特征、协调得非常好的实现而言, T C P的性能仅受最 大的1千兆字节窗口和光速(也就是往返时间)的限制。 习题 24.1 当一个系统发送一个开始的 S Y N报文段,其窗口扩大因子为 0,这是什么含义? 24.2 如果在图2 4 - 7中的主机b s d i支持窗口扩大选项,则来自 v a n g o g h的报文段3的16 bit窗 口大小字段中的期望值是多少?类似地,如果在该图的第 2个连接中也使用这个选项, 那么报文段1 3中的窗口通告应该是多少? 24.3 与在建立连接时的固定窗口扩大因子不同,已经定义过的窗口扩大因子能否在扩大因子 变化时也出现呢? 24.4 假定M S L为2分钟,那么在什么速率下序号回绕会成为一个问题呢 ? 24.5 PAW S被定义为只在一个单独的连接中进行。为了使 T C P将PAW S来替换2 M S L等待(即 T I M E _ WA I T状态),需要进行什么改动? 24.6 在2 4 . 4节最后的例子中,为什么 s o c k程序在紧接着(具有 I P地址和端口)后面的一行 之前,将接收缓存的大小来输出呢? 24.7 假定M S S为1 0 2 4,重新计算2 4 . 8节中的吞吐量。 24.8 时间戳选项是如何影响K a r n算法(见2 1 . 3节)的? 24.9 如果主动建立连接的 T C P发送带有S Y N标志的报文段(没有使用我们在 2 4 . 7节介绍的扩 展),那么接收T C P应该怎样处理这些数据呢? 24.10 在2 4 . 7节我们提到如果没有使用 T / T C P扩展,即使主动开启方发送带有 F I N的数据,客 户在接收服务器的响应的时延仍然是两倍的 RT T再加上S P T。给出符合这种情况的报文 段。 2 4 . 11 假定支持T / T C P,且源自伯克利系统的最小 RTO为0 . 5秒,重做习题1 8 . 1 4。 24.12 如果我们实现了 T / T C P,并测量两个主机之间的事务时间,那么可以通过比较什么指 标来确定它的有效性? 第24章 TCP的未来和性能使用269第25章 SNMP: 简单网络管理协议 25.1 引言 随着网络技术的飞速发展,网络的数量也越来越多。而网络中的设备来自各个不同的厂 家,如何管理这些设备就变得十分重要。本章的内容就是介绍管理这些设备的标准。 基于T C P / I P的网络管理包含两个部分:网络管理站(也叫管理进程, m a n a g e r)和被管的 网络单元(也叫被管设备)。被管设备种类繁多,例如:路由器、 X 终端、终端服务器和打印 机等。这些被管设备的共同点就是都运行 T C P / I P协议。被管设备端和管理相关的软件叫做代 理程序( a g e n t )或代理进程。管理站一般都是带有彩色监视器的工作站,可以显示所有被管设 备的状态(例如连接是否掉线、各种连接上的流量状况等 )。 管理进程和代理进程之间的通信可以有两种方式。一种是管理进程向代理进程发出请求, 询问一个具体的参数值(例如:你产生了多少个不可达的 I C M P端口?)。另外一种方式是代 理进程主动向管理进程报告有某些重要的事件发生(例如:一个连接口掉线了)。当然,管理 进程除了可以向代理进程询问某些参数值以外,它还可以按要求改变代理进程的参数值(例 如:把默认的IP TTL值改为6 4)。 基于T C P / I P的网络管理包含3个组成部分: 1) 一个管理信息库M I B(Management Information Base)。管理信息库包含所有代理进程 的所有可被查询和修改的参数。 RFC 1213 [McCloghrie and Rose 1991]定义了第二版的M I B, 叫做M I B - I I。 2) 关于 M I B的一套公用的结构和表示符号。叫做管理信息结构 S M I(Structure of Management Information)。这个在RFC 1155 [Rose and McCloghrie 1990] 中定义。例如:S M I 定义计数器是一个非负整数,它的计数范围是 0~4 294 967 295,当达到最大值时,又从0开始 计数。 3) 管理进程和代理进程之间的通信协议,叫做简单网络管理协议 S N M P(Simple Network Management Protocol)。在RFC 1157 [Case et al. 1990]中定义。S N M P包括数据报交换的格式 等。尽管可以在运输层采用各种各样的协议,但是在 S N M P中,用得最多的协议还是U D P。 上面提到的R F C所定义的S N M P叫做SNMP v1,或者就叫做S N M P,这也是本章的主要内 容。到1 9 9 3年为止,又有一些新的关于 S N M P的 R F C发表。在这些R F C中定义的S N M P叫做第 二版S N M P(SNMP v2),这将在2 5 . 1 2章节中讨论。 本章首先介绍管理进程和代理进程之间的协议,然后讨论参数的数据类型。在本章中将 用到前面已经出现过的名词,如: I P、U D P和T C P等。我们在叙述中将举一些例子来帮助读 者理解,这些例子和前面的某些章节相关。 25.2 协议 关于管理进程和代理进程之间的交互信息, S N M P定义了5种报文:1) g e t - r e q u e s t操作:从代理进程处提取一个或多个参数值。 2) g e t - n e x t - r e q u e s t操作:从代理进程处提取一个或多个参数的下一个参数值(关 于“下一个(n e x t)”的含义将在后面的章节中介绍)。 3) s e t - r e q u e s t操作:设置代理进程的一个或多个参数值。 4) g e t - r e s p o n s e操作:返回的一个或多个参数值。这个操作是由代理进程发出的。它 是前面3中操作的响应操作。 5) t r a p 操作:代理进程主动发出的报文,通知管理进程有某些事情发生。 前面的3个操作是由管理进程向代理进程发出的。后面两个是代理进程发给管理进程的 (为简化起见,前面3个操作今后叫做g e t、g e t - n e x t和s e t操作)。图2 5 - 1描述了这5种操作。 图25-1 SNMP的5种操作 既然这些操作中的前 4种操作是简单的请求 -应答方式(也就是管理进程发出请求,代理 进程应答响应),而且在S N M P中往往使用U D P协议,所以可能发生管理进程和代理进程之间 数据报丢失的情况。因此一定要有超时和重传机制。 管理进程发出的前面 3种操作采用U D P的1 6 1端口。代理进程发出的 Tr a p操作采用U D P的 1 6 2端口。由于收发采用了不同的端口号,所以一个系统可以同时为管理进程和代理进程(参 见习题2 5 . 1)。 图2 5 - 2是封装成U D P数据报的5种操作的S N M P报文格式。 在图中,我们仅仅对I P和U D P的首部长度进行了标注。这是由于: S N M P报文的编码采用 了A S N . 1和B E R,这就使得报文的长度取决于变量的类型和值。关于 A S N . 1和B E R的内容将在 后面介绍。在这里介绍各个字段的内容和作用。 版本字段是0。该字段的值是通过S N M P版本号减去1得到的。显然0代表SNMP v1。 图2 5 - 3显示各种P D U对应的值(P D U即协议数据单元,也就是分组)。 共同体字段是一个字符串。这是管理进程和代理进程之间的口令,是明文格式。默认的 值是p u b l i c。 对于g e t、g e t - n e x t和s e t操作,请求标识由管理进程设置,然后由代理进程在 g e t - r e s p o n s e中返回。这种类型的字段我们在其他U D P应用中曾经见过(回忆一下在图1 4 - 3中D N S 的标识字段,或者是图1 6 - 2中的事务标识字段)。这个字段的作用是使客户进程(在目前情况下是 管理进程)能够将服务器进程(即代理进程)发出的响应和客户进程发出的查询进行匹配。这个 第25章 SNMP:简单网络管理协议使用271 UDP端口162 UDP端口161 UDP端口161 UDP端口161 SNMP代理进程SNMP管理进程字段允许管理进程对一个或多个代理进程发出多个请求,并且从返回的众多 应答中进行分类。 图25-2 SNMP报文的格式 差错状态字段是一个整数,它是由代理进程标注的, 指明有差错发生。图2 5 - 4是参数值、名称和描述之间的对应 关系。 差错索引字段是一个整数偏移量,指明当有差错发生 时,差错发生在哪个参数。它是由代理进程标注的,并且 只有在发生 n o S u c h N a m e、r e a d O n l y和b a d V a l u e差错 时才进行标注。 图25-4 SNMP差错状态的值 在g e t、g e t - n e x t和s e t的请求数据报中,包含变量名称和变量值的一张表。对于 g e t 和g e t - n e x t操作,变量值部分被忽略,也就是不需要填写。 对于t r a p操作符(P D U类型是4),S N M P报文格式有所变化。我们将在 2 5 . 1 0节中当讨论 到t r a p时再详细讨论。 25.3 管理信息结构 S N M P中,数据类型并不多。在本节,我们就讨论这些数据类型,而不关心这些数据类型 在实际中是如何编码的。 • I N T E G E R。一个变量虽然定义为整型,但也有多种形式。有些整型变量没有范围限制,有些 整型变量定义为特定的数值(例如,I P的转发标志就只有允许转发时的1或者不允许转发时的 2这两种),有些整型变量定义为一个特定的范围(例如,U D P和T C P的端口号就从0到6 5 5 3 5)。 • OCTER STRING。0或多个8 bit字节,每个字节值在 0 ~ 2 5 5之间。对于这种数据类型和 272使用TCP/IP详解,卷1:协议 IP数据报 UDP数据报 SNMP报文 公共SNMP首部 IP首部 UDP 首部 版本 (0) P D U 类型 ( 0 - 3 ) 请求 标识 差错状 态( 0 - 5 ) t r a p 类型 ( 0 - 6 ) 差错 索引 名称 值 名称 值 值名称时间戳特定 代码 代理 地址企业 t r a p首部 有意义的变量 P D U类 型( 4 ) 共同体 20字节 8字节 get/set首部 get/set变量部分 图25-3 SNMP报文中的PDU类型 PDU类型 名 称 差错状态 名 称 描 述 没有错误 代理进程无法把响应放在一个SNMP消息中发送 操作一个不存在的变量 set操作的值或语义有错误 管理进程试图修改一个只读变量 其他错误下一种数据类型的 B E R编码,字符串的字节个数要超过字符串本身的长度。这些字符 串不是以N U L L结尾的字符串。 • D i s p l a y S t r i n g。0或多个8 bit字节,但是每个字节必须是 A S C I I码(2 6 . 4中有A S C I I 字符集)。在M I B - I I中,所有该类型的变量不能超过 2 5 5个字符(0个字符是可以的)。 • OBJECT IDENTIFIER。将在下一节中介绍。 • N U L L。代表相关的变量没有值。例如,在 g e t或g e t - n e x t操作中,变量的值就是 N U L L,因为这些值还有待到代理进程处去取。 • I p A d d r e s s。4字节长度的OCTER STRING,以网络序表示的 I P地址。每个字节代表 I P地址的一个字段。 • P h y s A d d r e s s。OCTER STRING类型,代表物理地址(例如以太网物理地址为 6个字 节长度)。 • C o u n t e r。非负的整数,可从0递增到 23 2-1(4 294 976 295)。达到最大值后归0。 • G a u g e。非负的整数,取值范围为从 0到4 294 976 295(或增或减)。达到最大值后锁定 , 直到复位。例如, M I B中的t c p C u r r E s t a b就是这种类型的变量的一个例子,它代表目前 在E S TA B L I S H E D或C L O S E _ WA I T状态的T C P连接数。 • T i m e T i c k s。时间计数器, 以0 . 0 1秒为单位递增,但是不同的变量可以有不同的递增幅 度。所以在定义这种类型的变量的时候,必须指定递增幅度。例如, M I B 中的 s y s U p T i m e变量就是这种类型的变量,代表代理进程从启动开始的时间长度,以多少 个百分之一秒的数目来表示。 • S E Q U E N C E。这一数据类型与 C程序设计语言中的“ s t r u c t u r e”类似。一个S E Q U E N C E 包括 0个或多个元素,每一个元素又是另一个 A S N . 1数据类型。例如, M I B中的 U d p E n t r y就是这种类型的变量。它代表在代理进程侧目前“激活”的 U D P数量(“激活” 表示目前被应用程序所用)。在这个变量中包含两个元素: 1) I p A d d r e s s类型中的u d p L o c a l A d d r e s s,表示I P地址。 2) I N T E G E R类型中的u d p L o c a l P o r t,从0到6 5 5 3 5,表示端口号。 • SEQUENDE OF。这是一个向量的定义,其所有元素具有相同的类型。如果每一个元素 都具有简单的数据类型,例如是整数类型,那么我们就得到一个简单的向量(一个一 维向量)。但是我们将看到, S N M P在使用这个数据类型时,其向量中的每一个元素是 一个S E Q U E N C E(结构)。因而可以将它看成为一个二维数组或表。 例如,名为 u d p T a b l e的U D P监听表( l i s t e n e r )就是这种类型的变量。它是一个二元的 S E Q U E N C E变量。每个二元组就是一个 U d p E n t r y。如图2 5 - 5所示。 图25-5 表格形式的u d p T a b l e 变量 第25章 SNMP:简单网络管理协议使用273 一个IpAddress类型的变量 udpLocalAddress 范围在0 ~ 6 5 5 3 5的整型变量在S N M P中,对于这种类型的表格并没有标注它的列数。但在 2 5 . 7节中,我们将看到 g e t - n e x t 操作是如何判断已经操作到最后一列的情况。同时,在 2 5 . 6节中,我们还将介绍管理进程如 何表示它对某一行数据进行 g e t或s e t操作。 25.4 对象标识符 对象标识是一种数据类型,它指明一种“授权”命名的对象。“授权”的意思就是这些标 识不是随便分配的,它是由一些权威机构进行管理和分配的。 对象标识是一个整数序列,以点(“.”)分隔。这些整数构成一个树型结构,类似于 D N S (图1 4 - 1)或U n i x的文件系统。对象标识从树的顶部开始,顶部没有标识,以 r o o t表示(这和 U n i x中文件系统的树遍历方向非常类似)。 图2 5 - 6显示了在S N M P中用到的这种树型结构。所有的 M I B变量都从1 . 3 . 6 . 1 . 2 . 1这个标识 开始。 树上的每个结点同时还有一个文字名。例如标识 1 . 3 . 6 . 1 . 2 . 1就和 i s o . o r g . d o d . i n t e r n e t . m e m t . m i b对应。这主要是为了人们阅读方便。在实际应用中,也就是说在管理进程 和代理进程进行数据报交互时,M I B变量名是以对象标识来标识的,当然都是以1 . 3 . 6 . 1 . 2 . 1开头的。 图25-6 管理信息库中的对象标识 在图2 5 - 6中,我们除了给出了 m i b对象标识外,还给出了 i s o . o r g . d o d . i n t e r n e t . p r i v a t e . e n t e r p r i s e s(1 . 3 . 6 . 1 . 4 . 1)这个标识。这是给厂家自定义而预留的。在 A s s i g n e d Number RFC中列出了在该结点下大约4 0 0个标识。 25.5 管理信息库介绍 所谓管理信息库,或者M I B,就是所有代理进程包含的、并且能够被管理进程进行查询和设 274使用TCP/IP详解,卷1:协议置的信息的集合。我们在前面已经提到了在RFC 1213 [McColghrie 和Rose 1991]中定义的M I B - I I。 如图2 5 - 6所示,M I B被划分为若干个组,如s y s t e m、i n t e r f a c e s、a t(地址转换)和 i p组等。 在本节,我们仅仅讨论 U D P组中的变量。这个组比较简单,它包含几个变量和一个表格。 在下一节,我们将以U D P组为例,详细讲解什么是实例标识( instance identification),什么是 字典式排序(lexicographic ordering)以及和这些概念有关的一些简单例子。在这些例子之后, 在2 5 . 8节我们继续回到M I B,描述M I B中的其他一些组。 在图2 5 - 6中我们画出了u d p组在m i b的下面。图2 5 - 7就显示了U D P组的结构。 图25-7 UDP组的结构 在该组中,包含4个简单变量和1个由两个简单变量组成的表格。图 2 5 - 8描述了这4个简单 变量。 图25-8 UDP组下的简单变量 在本章中,我们就以图 2 5 - 8的格式来描述所有的 M I B变量。“R / W”列如果为空,则代表 该变量是只读的;如果变量是可读可写的,则以“·”符号来表示。哪怕整个组中的变量都 是只读的,我们也将列出“ R / W”列,以提示读者管理进程只能对这些变量进行查询操作 (上图U D P组我们就是这样做的)。同样,如果变量类型是 I N T E G E T类型并且有范围约束,我 们也将标明它的下限和上限,就如我们在下图中描述 U D P端口号所做的一样。 图2 5 - 9描述了在u d p T a b l e中的两个简单变量。 图25-9 u d p T a b l e 中的变量 每次当我们以S N M P表格形式来描述 M I B变量时,表格的第 1行都表示索引的值,它是表 第25章 SNMP:简单网络管理协议使用275 名 称 描 述 UDP数据报输入数 没有发送到有效端口的UDP数据报个数 接收到的有错误的UDP数据报个数(例如检验错误) UDP数据报输出数 数据类型 名 称 数据类型 描 述 监听进程的本地I P地址。0 . 0 . 0 . 0代表接收任何接口的数据报 监听进程的本地端口号 UDP监听表,索引=.格中的每一列的参考。在下一节中读者将看到的一些例子也是这样做的。 Case图 在图2 5 - 8中,前3个计数器是有相互关系的。 C a s e图真实地描述了一个给出的 M I B组中变 量之间的相互关系。图2 5 - 1 0就是U D P组的C a s e图。 图25-10 UDP组的Case图 这张图表明,发送到应用层的 U D P数据报的数量(u d p I n D a t a g r a m s)就是从I P层送到 U D P层的U D P数据报的数量,当然 u d p I n E r r o r和u d p N o P o r t s也类似。同样,发送到 I P层 的U D P数据报的数量(u d p O u t D a t a g r a m s)就是从应用层发出的 U D P数据报的数量。这表 明u d p I n D a t a g r a m不包括u d p I n E r r o r和u d p N o P o r t s。 在深入讲解 M I B的时候,这些 C a s e图被用来验证:分组的所有数据路径都是被计数的。 [Rose 1994] 中显示了所有M I B组的C a s e图。 25.6 实例标识 当对M I B变量进行操作,如查询和设置变量的值时,必须对M I B的每个变量进行标识。首先, 只有叶子结点是可操作的。S N M P没法处理表格的一整行或一整列。回到图2 5 - 7,在图2 5 - 8和图 2 5 - 9中描述过的变量就是叶子结点,而m i b、u d p、u d p T a b l e和u d p E n t r y就不是叶子结点。 25.6.1 简单变量 对于简单变量的处理方法是通过在其对象标识后面添加“ . 0”来处理的。例如图2 5 - 8中的 计数器u d p I n D a t a g r a m s,它的对象标识是1 . 3 . 6 . 1 . 2 . 1 . 7 . 1,它的实例标识是1 . 3 . 6 . 1 . 2 . 1 . 7 . 1 . 0, 相对应的文字名称是i s o . o r g . d o d . i n t e r n e t . m g m t . m i b . u d p . u d p I n D a t a g r a m s . 0。 虽然这个变量处理后通常可以缩写为 u d p I n D a t a g r a m s . 0,但我们还是要提醒读者在 S N M P报文中(图2 5 - 2)该变量的名称是其对象的标识 1 . 3 . 6 . 1 . 2 . 1 . 7 . 1 . 0。 25.6.2 表格 表格的实例标识就要复杂得多。回顾一下图 2 5 - 8中的UDP 监听表。 每个M I B中的表格都指明一个以上的索引。对于 U D P监听表来说, M I B定义了包含两个 变量的联合索引,这两个变量是:u d p L o c a l A d d r e s s,它是一个I P地址;u d p L o c a l P o r t, 它是一个整数(在图2 5 - 9中的第1行就显示了这个索引)。 假设在U D P监听表中有3行具体成员:第1行的I P地址是0 . 0 . 0 . 0,端口号是6 7;第2行的I P 276使用TCP/IP详解,卷1:协议 应用层 IP层地址是0 . 0 . 0 . 0,端口号是1 6 1;第3行的I P地址是0 . 0 . 0 . 0, 端口号是5 2 0。如图2 5 - 11所示。 这意味着系统将从端口 6 7(B O O T P服务器)、端口 1 6 1(S N M P)和端口 5 2 0(R I P)接受来自任何接口的 U D P数据报。表格中的这 3行经过处理后的结果在图 2 5 - 1 2中显示。 25.6.3 字典式排序 M I B中按照对象标识进行排序时有一个隐含的排序规则。 M I B表格是根据其对象标识按 照字典的顺序进行排序的。这就意味着图 2 5 - 1 2中的6个变量排序后的情况如图 2 5 - 1 3所示。从 这种字典式排序中可以得出两个重要的结论。 图25-12 UDP监听表中行的实例标识 图25-13 UDP监听表的字典式排序 1) 在表格中,一个给定变量(在这里指 u d p L o c a l A d d r e s s)的所有实例都在下个变量 (这里指u d p L o c a l P o r t)的所有实例之前显示。这暗 示表格的操作顺序是“先列后行”的次序。这是由于对 对象标识进行字典式排序所得到的,而不是按照人们的 阅读习惯而排列的。 2) 表格中对行的排序和表格中索引的值有关。在图2 5 - 1 3中,6 7的字典序小于1 6 1,同样1 6 1的字典序小于5 2 0。 图2 5 - 1 4描述了例子中U D P监听表的这种“先列后行” 的次序。 在下节中,讲述到g e t - n e x t操作时,同样还会遇到这种“先列后行”的次序。 25.7 一些简单的例子 在本节中,我们将介绍如何从 S N M P代理进程处获取变量的值。对代理进程进行查询的软 件属于I S O D E系统,叫做s n m p i。两者在[Rose 1994]中有详细的介绍。 第25章 SNMP:简单网络管理协议使用277 图25-11 UDP监听表 行 对象标识 简 称 值 列 对象标识(字典序) 简 称 值 图25-14 按“先列后行”次序显示 的UDP监听表25.7.1 简单变量 对一个路由器取两个U D P组的简单变量值: 其中,- a选项代表要和之通信的代理进程名称, - c选项表示S N M P的共同体名。所谓共 同体名,就是客户进程(在这里指 s n m p i)提供、同时能被服务器进程(这里指代理进程 g a t e w a y)所识别的一个口令,共同体名称是管理进程请求的权限标志。代理进程允许客户 进程用只读共同体名对变量进行读操作,用读写共同体名对变量进行读和写操作。 S n m p i程序的输出提示符是 s n m p i >,在后面可以键入如g e t这样的命令,该软件将把它 转化为S N M P中的g e t - r e q u e s t报文。当结束时,键入 q u i t就退出(在后面的例子中,我们 将省略掉q u i t的操作)。 图2 5 - 1 5显示的是对于这个例子t c p d u m p的两行输出结果。 图25-15 简单SNMP查询操作t c p d u m p 的输出结果 对这两个变量的查询请求是封装在一个 U D P数据报中的,而响应也在一个 U D P数据报中。 显示的变量是以其对象标识的形式显示的,这是在 S N M P报文中实际传输的内容。我们必 须指定这两个变量的实例是 0。注意,变量的名称(它的对象标识)同样也在响应中返回。在 下面我们将看到对于g e t - n e x t操作这是必需的。 25.7.2 get-next操作 g e t - n e x t操作是基于 M I B的字典式排序的。在下面的例子中,首先向代理进程询问 U D P后的下一个对象标识(由于不是一个叶子对象,没有指定任何实例)。代理进程将返回 U D P组中的第1个对象,然后我们继续向代理进程取该对象的下一个对象标识,这时候第 2个 对象将被返回。重复上面的步骤直到取出所有的对象为止。 这个例子解释了为什么 g e t - n e x t操作总是返回变量的名称,这是因为我们向代理进程 询问下一个变量,代理进程就把变量值和名称一起返回了。 采用这种方式进行 g e t - n e x t操作,我们可以想象管理进程只要做一个简单的循环程序, 278使用TCP/IP详解,卷1:协议就可以从M I B树的顶点开始,对代理进程一步步地进行查询,就可以得出代理进程处所有的 变量值和标识。该方式的另外一个用处就是可以对表格进行遍历。 25.7.3 表格的访问 对于“先列后行”次序的U D P监听表,只要采用前面的简单查询程序一步一步地进行操作, 就可以遍历整个表格。只要从询问代理进程 u d p T a b l e的下一个变量开始就可以了。由于 u d p T a b l e不是叶子对象,我们不能指定一个实例,但是g e t - n e x t操作依然能够返回表格中的 下一个对象。然后就可以以返回的结果为基础进行下一步的操作,代理进程也会以“先列后行” 的次序返回下一个变量,这样就可以遍历整个表格。我们可以看到返回的次序和图25-14相同。 但是管理进程如何知道已经到达表格的最后一行呢?既然g e t - n e x t操作返回结果中包含表 格中的下一个变量的值和名称,当返回的结果是超出表格之外的下一个变量时,管理进程就可以 发现变量的名称发生了较大的变化。这样就可以判断出已经到达表格的最后一行。例如在我们的 例子中,当返回的是s n m p I n P k t s变量的时候就代表已经到了U D P监听表的最后一个变量了。 25.8 管理信息库(续) 现在继续讨论M I B。我们仅仅介绍下列 M I B组:s y s t e m(系统标识)、i f(接口)、a t (地址转换)、i p、i c m p和t c p。 25.8.1 s y s t e m组 s y s t e m组非常简单,它包含7个简单变量(例如,没有表格)。图2 5 - 1 6列出了s y s t e m组 的名称、数据类型和描述。 可以对n e t b路由器查询一些简单变量: 第25章 SNMP:简单网络管理协议使用279 我们已完成了对UDP监听表的操作图25-16 system组中的简单变量 回到图2 5 - 6中,s y s t e m的对象标识符在i n t e r n e t . p r i v a t e . e n t e r p r i s e s组(1 . 3 . 6 . 1 . 4 . 1)中, 在Assigned Numbers RFC文档中可以确定下一个对象标识符(1 2)肯定是指派给了厂家(E p i l o g u e)。 同时还可以看出, s y s S e r v i c e s变量的值是4与8的和,它支持网络层(例如选路)和运输 层的应用(例如端到端)。 25.8.2 interface组 在本组中只定义了一个简单变量,那就 是系统的接口数量,如图2 5 - 1 7所示。 在该组中,还有一个表格变量,有 2 2列。表格中的每行定义了接口的一些特征参数。如 图2 5 - 1 8所示。 可以向主机 s u n查询所有这些接口的变量。如 3 . 8节中所示,我们还是希望访问三个接口, 如果S L I P接口已经启动: 280使用TCP/IP详解,卷1:协议 名 称 数据类型 R / W 描 述 s y s D e s c r D i s p l a y S t r i n g 系统的文字描述 s y s O b j e c t I D O b j e c t I D 在子树1 . 3 . 6 . 1 . 4 . 1中的厂商标识 s y s U p Ti m e Ti m e Ti c k s 从系统的网管部分启动以来运行的时间(以百分之一 秒为计算单位) s y s C o n t a c t D i s p l a y S t r i n g • 联系人的名字及联系方式 s y s N a m e D i s p l a y S t r i n g • 结点的完全合格的域名( F Q D N ) s y s L o c a t i o n D i s p l a y S t r i n g • 结点的物理位置 s y s S e r v i c e s [ 0⋯ 1 2 7 ] • 指示结点提供的服务的值。该值是此结点所支持的 O S I模型中层次的和。根据所提供的服务,将下面的一 些值相加: 0 x 0 1 (物理层)、0 x 0 2(数据链路层)、0 x 0 4 (互联网层)、0 x 0 8(端到端的运输层)和 0 x 4 0(应用 层) 名 称 数据类型 R / W 描述 i f N u m b e r I N T E G E R 系统上的网络接 口数 图25-17 i f组中的简单变量 首先看第一个接口的接口索引接口表,索引= 名称 数据类型 R / W 描 述 i f I n d e x I N T E G E R 接口索引,介于 1和i f N u m b e r之间 i f D e s c r D i s p l a y S t r i n g 接口的文字描述 i f Ty p e I N T E G E R 类型,例如:6 = 以太网,7 = 802.3以太网,9 = 802.5令牌环,23 = PPP,28 = SLIP,还有其他一 些值 i f M t u I N T E G E R 接口的M T U i f S p e e d G a u g e 以b / s为单位的速率 i f P h y s A d d r e s s P h y s A d d r e s s 物理地址,对无物理地址的接口,以一串 0表示 (例如,串行链路) i f A d m i n S t a t u s [ 1⋯ 3 ] • 所希望的接口状态:1= 工作,2 = 不工作,3 = 测试 i f O p e r S t a t u s [ 1⋯ 3 ] • 当前接口的状态:1= 工作,2 = 不工作,3 = 测 试 i f L a s t C h a n g e Ti m e Ti c k s 当接口进入目前运行状态时 s y s U p T i m e的值 i f I n O c t e t s C o u n t e r 收到的字节总数,包括组帧字符 i f I n U c a s t P k t s C o u n t e r 交付给高层的单播分组数 i f I n N U c a s t P k t s C o u n t e r 交付给高层的非单播(例如,广播或多播)分 组数 i f I n D i s c a r d s C o u n t e r 收到的被丢弃的分组数,即使在分组中无差错 (例如,无缓存空间) i f I n E r r o r s C o u n t e r 收到的由于差错被丢弃的分组数 i f I n U n k n o w n P r o t o s C o u n t e r 收到的由于未知的协议被丢弃的分组数 i f O u t O c t e t s C o u n t e r 发送的字节总数,包括组帧字符 i f O u t U c a s t P k t s C o u n t e r 从高层接收到的单播分组数 i f O u t N U c a s t P k t s C o u n t e r 从高层接收到的非单播(如广播或多播)分组 数 i f O u t D i s c a r d s C o u n t e r 发出的被丢弃的分组数,即使在分组中无差错 (如无缓存空间) i f O u t E r r o r s C o u n t e r 发出的由于差错被丢弃的分组数 i f O u t Q L e n G a u g e 在输出队列中的分组数 i f S p e c i f i c O b j e c t I D 对这种特定媒体类型的M I B定义的引用 图25-18 在接口表中的变量:i f T a b l e 对于第1个接口,采用g e t操作提取5个变量值,然后用g e t - n e x t操作提取第2个接口的相 同的5个参数。对于第3个接口,同样采用g e t - n e x t操作。 对于S L I P链路的接口类型,所报告的是一个点到点的专用串行链路,而不是 S L I P链路。 此外,S L I P链路的速率没有报告。 这个例子对我们理解 g e t - n e x t操作和“先列后行”次序之间的关系十分重要。如果我 们键入命令“next ifDescr.1”,则系统返回的是表格中的下一行所对应的变量,而不是 同一行中的下个变量。如果表格是按照“先行后列”次序存放,我们就不能通过一个给定变 量来读取下一个变量。 25.8.3 a t组 地址转换组对于所有的系统都是必需的,但是在 M I B - I I中已经没有这个组。从 M I B - I I开 第25章 SNMP:简单网络管理协议使用281始,每个网络协议组(如 I P组)都包含它们各自的网络地址转换表。例如对于 I P组,网络地 址转换表就是i p N e t T o M e d i a T a b l e。 在该组中,仅有一个由3列组成的表格变量。如图2 5 - 1 9所示。 我们将用s n m p i程序中的一个新命令来转储 ( d u m p )整个表格。向一个叫做 k i n e t i c s的 路由器(该路由器连接了一个 T C P / I P网络和一个A p p l e Ta l k网络)查询其整个 A R P高速缓存。 命令的输出是字典式排序的整个表格内容。 图25-19 网络地址转换表:a t T a b l e 让我们来分析一下用t c p d u m p命令时的分组交互情况。当s n m p i要转储整个表格时,首先 发出一条g e t - n e x t命令以取得表格的名称(在 本例中是a t),该名称就是要获取的第一个表项。 然后在屏幕上显示的同时生成另一条g e t - n e x t 命令。直到遍历完整个表格的内容后才终止。 图25-20显示了在路由器中实际表格的内容。 注意图中,接口2的A p p l e Ta l k协议的物理地 址是32 bit的数值,而不是我们所熟悉的以太网的48 bit物理地址。同时请注意,正如我们所希望 的那样,在图中有一条记录和n e t b路由器(其I P地址是1 4 0 . 2 5 2 . 1 . 1 8 3)有关。这是因为n e t b路 由器和k i n e t i c s路由器在同一个以太网中(1 4 0 . 2 5 2 . 1),而且k i n e t i c s路由器必需采用A R P 来回送SNMP响应。 25.8.4 i p组 i p组定义了很多简单变量和3个表格变量。图2 5 - 2 1显示了所有的简单变量。 282使用TCP/IP详解,卷1:协议 地址转换表,索引= . 1 . 名 称 数据类型 R / W 描 述 a t I f I n d e x I N T E G E R • 接口数:i f I n d e x a t P h y s A d d r e s s P h y s A d d r e s s • 物理地址。若设置为长度为 0的字符 串,则表示无效表项 a t N e t A d d r e s s N e t w o r k A d d r e s s • I P地址 图25-20 a t表举例(ARP高速缓存)图25-21 i p组中的简单变量 i p组中的第一个表格变量是 I P地址表。系统的每个 I P地址都对应该表格中的一行。每行 中包含了5个变量,如图2 5 - 2 2所示。 图25-22 IP地址表:i p A d d r T a b l e 同样可以向主机s u n查询整个I P地址表: 第25章 SNMP:简单网络管理协议使用283 名称 数据类型 R / W 描 述 i p F o r w a r d i n g [ 1⋯ 2 ] • 1代表系统正在转发I P数据报,2则代表不在转 发 i p D e f a u l t T T L I N T E G E R • 当运输层不提供T T L值时的默认T T L值 i p I n R e c e i v e s C o u n t e r 从所有接口收到的I P数据报的总数 i p I n H d r E r r o r s C o u n t e r 由于首部差错被丢弃的数据报数(例如,检验 和差错,版本不匹配,T T L超过等) i p I n A d d r E r r o r s C o u n t e r 由于不正确的目的地址被丢弃的 I P数据报数 i p F o r w D a t a g r a m s C o u n t e r 曾进行过一次转发尝试的 I P数据报数 i p I n U n k n o w n P r o t o s C o u n t e r 具有无效协议字段的发往本地的 I P数据报数 i p I n D i s c a r d s C o u n t e r 由于缓存空间不足被丢弃的收到的数据报数 i p I n D e l i v e r s C o u n t e r 交付到适当的协议模块的 I P数据报数 i p O u t R e q u e s t s C o u n t e r 传递给I P层来传输的I P数据报总数。不包括已 经在i p F o r w D a t a g r a m s中计入的那些 i p O u t D i s c a r d s C o u n t e r 由于缓存空间不足被丢弃的输出数据报数 i p O u t N o R o u t e s C o u n t e r 由于找不到路由被丢弃的数据报数 i p R e a s m Ti m e o u t I N T E G E R 在等待重装时已收到的数据报片被保留的最大 秒数 i p R e a s m R e q d s C o u n t e r 收到的需要进行重装的I P数据报片的数目 i p R e a s m O K s C o u n t e r 已成功重装的 I P数据报数 i p R e a s m F a i l s C o u n t e r I P重装算法失败次数 i p F r a g O K s C o u n t e r 被成功分片的 I P数据报数 i p F r a g F a i l s C o u n t e r 需要进行分片但由于设置了“不分片”标志而 不能分片的I P数据报数 i p F r a g C r e a t e s C o u n t e r 由分片而产生的I P数据报片的数目 i p R o u t i n g D i s c a r d s C o u n t e r 所选择的选路表项即使是有效的但也要丢弃的 数目 I P地址表,索引= 名 称 数据类型 R / W 描 述 i p A d E n t A d d r I p A d d r e s s 这一行的I P地址 i p A d E n t I f I n d e x I N T E G E R 对应的接口数:i f I n d e x i p A d E n t N e t M a s k I p A d d r e s s 对这个I P地址的子网掩码 i p A d E n t B c a s t A d d r [ 0⋯ 1 ] I P广播地址中的最低位的值。通常为 1 i p A d E n t R e a s m M a x S i z e [ 0⋯ 6 5 5 3 5 ] 在这个接口上收到的、能够进行重装的、 最长的I P数据报输出的接口号码可以和图 2 5 - 1 8中的输出进行比较,同样 I P地址和子网掩码可以和 3 . 8节中 采用i f c o n f i g命令时的输出进行比较。 i p组中的第二个表是 I P路由表(请回忆一下我们在 9 . 2节中讲到的路由表),如图2 5 - 2 3所 示。访问该表中每行记录的索引是目的 I P地址。 图25-23 IP路由表:i p R o u t e T a b l e 图2 5 - 2 4显示的是用s n m p i程序采用dump ipRouteTable命令从主机s u n得到的路由 表。在这张表中,已经删除了所有 5个路由度量,那是由于这 5条记录的度量都是- 1。在列的 标题中,对每个变量名称已经删除了 i p R o u t e这样的前缀。 图25-24 路由器s u n 上的IP路由表 284使用TCP/IP详解,卷1:协议 名 称 数据类型 R / W 描 述 i p R o u t e D e s t I p A d d r e s s • 目的I P地址。值0 . 0 . 0 . 0表示一个默认的表项 i p R o u t e I f I n d e x I N T E G E R • 接口数:i f I n d e x i p R o u t e M e t r i c 1 I N T E G E R • 主要的选路度量。这个度量的意义取决于选路协 议(i p R o u t e P r o t o)。-1表示未使用 i p R o u t e M e t r i c 2 I N T E G E R • 可选的选路度量 i p R o u t e M e t r i c 3 I N T E G E R • 可选的选路度量 i p R o u t e M e t r i c 4 I N T E G E R • 可选的选路度量 i p R o u t e N e x t H o p I p A d d r e s s • 下一跳路由器的I P地址 i p R o u t e T y p e I N T E G E R • 路由类型:1 = 其他,2 = 无效路由,3 = 直接,4 = 间接 i p R o u t e P r o t o I N T E G E R 选路协议:1 = 其他,4 = ICMP重定向,8 = RIP, 13 = OSPF, 14 = BGP, 以及其他 i p R o u t e A g e I N T E G E R • 自从路由上次被更新或确定是正确的以后所经历 的秒数 i p R o u t e M a s k I p A d d r e s s • 在和i p R o u t e D e s t相比较之前,掩码要与目的 I P地 址进行逻辑“与” i p R o u t e M e t r i c 5 I N T E G E R • 其他的选路度量 i p R o u t e I n f o O b j e c t I D • 对这种特定选路协议的M I B定义的引用 间接(4) 其他(1) 其他(1) 其他(1) 其他(1) 其他(1) 直接(3) 直接(3) 直接(3) 间接(4) 环回接口 SLIP接口 以太网接口 所有这三个都使用一个比特进行广播为比较起见,下面的内容是我们用 n e t s t a t命令(在9 . 2节中曾经讨论过)格式显示的路 由表信息。图2 5 - 2 4是按字典序显示的,这和n e t s t a t命令显示格式不同: i p组的最后一个表是地址转换表,如图 2 5 - 2 5所示。正如我们前面所说的, a t组已经被删 除了,在这里已经用I P表来代替了。 图25-25 IP地址转换表:i p N e t T o M e d i a T a b l e 这里显示的是系统s u n上的A R P高速缓存信息: sun % arp -a svr4 (140.252.13.34) at 0:0:c0:c2:9b:26 bsdi (140.252.13.35) at 0:0:c0:6f:2d:40 相应的S N M P输出: 25.8.5 i c m p组 i c m p组包含4个普通计数器变量( I C M P报文的输出和输入数量以及 I C M P差错报文的输 入和输出数量)和2 2个其他I C M P报文数量的计数器: 11个是输出计数器,另外 11个是输入计 数器。如图2 5 - 2 6所示。 对于有附加代码的 I C M P报文(请回忆一下图 6 - 3中,有 1 5种报文代表目的不可达), S N M P没有为它们定义专门的计数器。 25.8.6 t c p组 图2 5 - 2 7显示的是t c p组中的简单变量。其中的很多变量和图 1 8 - 1 2描述的T C P状态有关。 第25章 SNMP:简单网络管理协议使用285 I P地址转换表,索引= . 名 称 数 据 类 型 R / W 描 述 i p N e t To M e d i a I f I n d e x I N T E G E R • 对应的接口:i f I n d e x i p N e t To M e d i a P h y s A d d r e s s P h y s A d d r e s s • 物理地址 i p N e t To M e d i a N e t A d d r e s s I p A d d r e s s • I P地址 i p N e t To M e d i a Ty p e [ 1⋯ 4 ] • 映射的类型:1 = 其他,2 = 无效的, 3 = 动态的,4 = 静态的。图25-26 i c m p 组中的简单变量 图25-27 t c p 组中的简单变量 286使用TCP/IP详解,卷1:协议 名 称 数据类型 R / W 描 述 i c m p I n M s g s C o u n t e r 收到的I C M P报文总数 i c m p I n E r r o r s C o u n t e r 收到的有差错的I C M P报文数(例如,无效 的I C M P检验和) i c m p I n D e s t U n r e a c h s C o u n t e r 收到的I C M P目的站不可达报文数 i c m p I n T i m e E x c d s C o u n t e r 收到的I C M P超时报文数 i c m p I n P a r m P r o b s C o u n t e r 收到的I C M P参数问题报文数 i c m p I n S r c Q u e n c h s C o u n t e r 收到的I C M P源站抑制报文数 i c m p I n R e d i r e c t s C o u n t e r 收到的I C M P重定向报文数 i c m p I n E c h o s C o u n t e r 收到的I C M P回显请求报文数 i c m p I n E c h o s R e p s C o u n t e r 收到的I C M P回显应答报文数 i c m p I n T i m e S t a m p s C o u n t e r 收到的I C M P时间戳请求报文数 i c m p I n T i m e S t a m p R e p s C o u n t e r 收到的I C M P时间戳应答报文数 i c m p I n A d d r M a s k s C o u n t e r 收到的I C M P地址掩码请求报文数 i c m p I n A d d r M a s k R e p s C o u n t e r 收到的I C M P地址掩码应答报文数 i c m p O u t M s g s C o u n t e r 输出的I C M P报文总数 i c m p O u t E r r o r s C o u n t e r 由于在I C M P报文中有一个问题(例如,缓 存空间不足)而未发送的 I C M P报文数 i c m p O u t D e s t U n r e a c h s C o u n t e r 发送的I C M P目的站不可达报文数 i c m p O u t T i m e E x c d s C o u n t e r 发送的I C M P超时报文数 i c m p O u t P a r m P r o b s C o u n t e r 发送的I C M P参数问题报文数 i c m p O u t S r c Q u e n c h s C o u n t e r 发送的I C M P源站抑制报文数 i c m p O u t R e d i r e c t s C o u n t e r 发送的I C M P重定向报文数 i c m p O u t E c h o s C o u n t e r 发送的I C M P回显请求报文数 i c m p O u t E c h o s R e p s C o u n t e r 发送的I C M P回显应答报文数 i c m p O u t T i m e S t a m p s C o u n t e r 发送的I C M P时间戳请求报文数 i c m p O u t T i m e S t a m p R e p s C o u n t e r 发送的I C M P时间戳应答报文数 i c m p O u t A d d r M a s k s C o u n t e r 发送的I C M P地址掩码请求报文数 i c m p O u t A d d r M a s k R e p s C o u n t e r 发送的I C M P地址掩码应答报文数 名 称 数据类型 R / W 描 述 t c p R t o A l g o r i t h m I N T E G E R 用来计算重传超时值的算法:1 =除下列值以外,2 = 固 定的RTO, 3 = MIL-S T D-1 7 7 8附件B, 4 = Van Jacobson算法 t c p R t o M i n I N T E G E R 以毫秒计的最小重传超时值 t c p R t o M a x I N T E G E R 以毫秒计的最大重传超时值 t c p M a x C o n n I N T E G E R 最大的T C P连接数。若为动态的,则值为- 1 t c p A c t i v e O p e n s C o u n t e r 从C L O S E D到S Y N _ S E N T的状态变迁数 t c p P a s s i v e O p e n s C o u n t e r 从L I S T E N到S Y N _ R C V D的状态变迁数 t c p A t t e m p F a i l s C o u n t e r 从S Y N _ S E N T或S Y N _ R C V D到C L O S E D的状态变迁 数,加上从S Y N _ R C V D到L I S T E N的状态变迁数 t c p E s t a b R e s e t s C o u n t e r 从E S TA B L I S H E D或C L O S E _ WA I T状态到C L O S E D的 状态变迁数 t c p C u r r E s t a b G a u g e 当前在E S TA B L I S H E D或C L O S E _ WA I T状态的连接数 t c p I n S e g s C o u n t e r 收到的报文段的总数 t c p O u t S e g s C o u n t e r 发送的报文段的总数,但将仅包含重传字节的除外 t c p R e t r a n s S e g s 重传的报文段的总数 t c p I n E r r s C o u n t e r 收到的具有一个差错(如无效的检验和)的报文段总数 t c p O u t R s t s C o u n t e r 具有R S T标志置位的报文段的总数现在向系统s u n查询一些t c p组变量: 本系统(指 S u n O S 4 . 1 . 3)使用的是 Van Jacobson超时重传算法,超时定时器的范围在 200 ms~12.8 s之间,并且对T C P连接数量没有特定的限制(这里的超时上限 12.8 s恐怕有错, 因为我们在2 1章中曾经介绍大多数应用的超时上限是 64 s )。 t c p组还包括一个表格变量,即 T C P连接表,如图2 5 - 2 8所示。对于每个T C P连接,都对应 表格中的一条记录。每条记录包含 5个变量:连接状态、本地 I P地址、本地端口号、远端 I P地 址以及远端端口号。 图25-28 TCP连接表:t c p C o n n T a b l e 让我们看一看在系统 s u n上的这个表。由于有许多服务器进程在监听这些连接,所以我 们只显示该表的一部分内容。在转储全部表格的变量之前,我们必需先建立两条 T C P连接: sun % rlogin gemini g e m i n i的I P地址是1 4 0 . 2 5 2 . 1 . 1 1 和 sun % rlogin localhost I P地址应该是1 2 7 . 0 . 0 . 1 在所有的监听服务器进程中,我们仅仅列出了 F T P服务器进程的情况,它使用 2 1号端口。 第25章 SNMP:简单网络管理协议使用287 索引= . . . 名 称 数据类型 R / W 描 述 t c p C o n n S t a t e [ 1⋯ 1 2 ] • 连接状态: 1 = CLOSED, 2 = LISTEN, 3 = SYN_SENT, 4 = SYN_RCVD, 5 = ESTABLISHED, 6 = FIN_WAIT, 7 = FIN_WAIT, 8 = CLOSE_WAIT, 9 = LAST_ACK, 10 = CLOSING, 11 = T I M E _ WA I T, 12 = 删除T C B。管理进程对此变量 可以设置的唯一值就是 1 2(例如,立即终止此连 接) t c p C o n n L o c a l A d d r e s s I p A d d r e s s 本地I P地址。0 . 0 . 0 . 0代表监听进程愿意在任何 接口接受连接 t c p C o n n L o c a l P o r t [ 1⋯ 6 5 5 3 5 ] 本地端口号 t c p C o n n R e m A d d r e s s I p A d d r e s s 远程I P地址 t c p C o n n R e m P o r t [ 1⋯ 6 5 5 3 5 ] 远程端口号对于r l o g i n到g e m i n i,只显示一条记录,这是因为g e m i n i是另外一个主机。而且我们 仅仅能够看到连接的客户端信息(端口号是 1 0 2 3)。但是Te l n e t连接,客户端和服务器端都显示 (客户端口号是1 4 1 5,服务器端口号是2 3),这是因为这种连接通过环回接口。同时我们还可以 看到,F T P监听服务器程序的本地I P地址是0 . 0 . 0 . 0。这表明它可以接受通过任何接口的连接。 25.9 其他一些例子 现在开始回答前面一些没有回答的问题,我们将用 S N M P的知识进行解释。 25.9.1 接口MTU 回忆一下在11 . 6节的实验中,我们试图得出一条从 n e t b到s u n的S L I P连接的M T U。现在可 以采用S N M P得到这个 M T U。首先从 I P路由表中取到 S L I P连接(1 4 0 . 2 5 2 . 1 . 2 9)的接口号 (i p R o u t e I f I n d e x),然后就可以用这个数值进入接口表并且取得想要的 S L I P连接的M T U (通过S L I P的描述和数据类型)。 可以看到,即使连接的类型是 S L I P连接,但是M T U仍设置为以太网,其值为 1 5 0 0,目的 可能是为了避免分片。 25.9.2 路由表 回忆一下在1 4 . 4节中,我们讨论了 D N S如何进行地址排序的问题。当时我们介绍了从域 名服务器返回的第 1个I P地址是和客户有相同子网掩码的情况。还介绍了用其他的 I P地址也会 正常工作,但是效率比较低。现在我们从 S N M P的角度来查阅路由表的入口,在这里将用到前 面章节中和I P路由有关的很多相关知识。 路由器g e m i n i是一个多接口主机,有两个以太网接口。首先确认一下两个接口都可以 Te l n e t登录: 288使用TCP/IP详解,卷1:协议可以看出这两个地址的连接没有什么区别。现在我们采用 t r a c e r o u t e命令来看一下对于每 个地址,是否有选路方面的不同: 可以看到:如果采用属于 1 4 0 . 2 5 2 . 3子网的地址,就多了额外的一跳。下面解释造成这个额外 一跳的原因。 图2 5 - 2 9是系统的连接关系图。从 t r a c e r o u t e命令的输出结果可以看出主机 g e m i n i和 路由器s w n r t都连接了两个网段:1 4 0 . 2 5 2 . 3子网和1 4 0 . 2 5 2 . 1子网。 回忆一下在图4 - 6中,我们解释了路由器 n e t b采用A R P代理进程,使得s u n工作站好象是 直接连接到1 4 0 . 2 5 2 . 1子网上的情况。我们忽略了 s u n和n e t b之间S L I P连接的调制解调器,因 为这和我们这里的讨论不相关。 在图2 5 - 2 9中,我们用虚线箭头画出了当 Te l n e t到1 4 0 . 2 5 2 . 3 . 5 4时的路径。返回的数据报怎 么知道直接从g e m i n i到n e t b,而不是从原路返回呢?我们采用在 8 . 5节中介绍过的,带有宽 松选路特性的t r a c e r o u t e版本来解释: 当在命令中指明是宽松源站选路时, s w n r t路由器就不再有 响应。看一下前面没有指明源站选路的 t r a c e r o u t e命令输 出,可以看出s w n r t路由器是事实上的第 2跳。超时数据必 须这样设置的原因是:当数据报指定了宽松源站选路选项时, 该路由器没有发生I C M P超时差错。所以在t r a c e r o u t e命令 的输出中可以得出,返回路径是从g e m i n i(TTL 3, 4和5)路由 器直接到达n e t b路由器,而不通过s w n r t路由器。 还剩下一个需要用S N M P来解释的问题就是:在n e t b路 由器的路由表中,哪条信息代表寻径到1 4 0 . 2 5 2 . 3?该信息表示 n e t b路由器把分组发送给s w n r t而不是直接发送给g e m i n i? 用g e t命令来取下一跳路由器的值。 第25章 SNMP:简单网络管理协议使用289 图25-29 例子中的网络拓扑结构sun % snmpi -a netb -c secret get ipRouteNextHop.140.252.3.0 i p R o u t e N e x t H o p . 1 4 0 . 2 5 2 . 3 . 0 = 1 4 0 . 2 5 2 . 1 . 6 正如我们所看到发生的那样,路由表设置使得 n e t b路由器把分组发送到s w n r t路由器。 为什么g e m i n i路由器直接把分组回送给n e t b路由器?那是因为在g e m i n i路由器端,它要回 送的分组目的地址是1 4 0 . 2 5 2 . 1 . 2 9,而子网1 4 0 . 2 5 2 . 1是直接连接到g e m i n i路由器上的。 从上面这个例子可以看出选路的策略。由于g e m i n i是打算作一个多接口主机而不是路由器, 所以默认的到1 4 0 . 2 5 3 . 3子网的路由器是s w n r t。这是多接口主机和路由器之间差异的一个典型例子。 25.10 Trap 本章我们看到的例子都是从管理进程到代理进程的。当然代理进程也可以主动发送 t r a p到 管理进程,以告诉管理进程在代理进程侧有某些管理进程所关心的事件发生,如图 2 5 - 1所示。 t r a p发送到管理进程的1 6 2号端口。 在图2 5 - 2中,我们已经描述了 trap PDU的格式。在下面关于 t c p d u m p输出内容中我们将 再一次用到这些字段。 现在已经定义了 6种特定的t r a p类型,第7种t r a p类型是由供应商自己定义的特定类型。图 2 5 - 3 0给出了t r a p报文中t r a p类型字段的内容。 图25-30 trap的类型 用t c p d u m p命令来看看t r a p的情况。我们在系统s u n上启动S N M P代理进程,然后让它产生 c o l d S t a r t类型的t r a p(我们告诉代理进程把t r a p信息发送到b s d i主机。虽然在该主机上并没有运行 处理t r a p的管理进程,但是可以用t c p d u m p来查看产生了什么样的分组。回忆一下在图2 5 - 1中, t r a p是从代理进程发送到管理进程的,而管理进程不需要给代理进程发送确认。所以我们不需 要t r a p的处理程序)。然后我们用s n m p i程序发送一个请求,但该请求的共同体名称是无效的。 这将产生一个a u t h e n t i c a t i o n F a i l u r e类型的t r a p。图2 5 - 3 1显示了命令的输出结果。 图25-31 t c p d u m p 输出的由SNMP代理进程产生的trap 首先注意一下两个 U D P数据报都是从 S N M P代理进程(端口是 1 6 1,图中显示的名称是 s n m p)发送到目的端口号是1 6 2的服务器进程上的(图中显示的名称是 s n m p - t r a p)。 再注意一下C = t r a p s是t r a p报文的共同体名称。这是ISODE SNMP代理进程的配置选项。 290使用TCP/IP详解,卷1:协议 t r a p类型 名 称 描 述 0 c o l d S t a r t 代理进程对自己初始化 1 w a r m S t a r t 代理进程对自己重新初始化 2 l i n k D o w n 一个接口已经从工作状态改变为故障状态(图 2 5 - 1 8)。 报文中的第一个变量标识此接口 3 l i n k U p 一个接口已经从故障状态改变为工作状态(图 2 5 - 1 8)。 报文中的第一个变量标识此接口 4 a u t h e n t i c a t i o n F a i l u r e 从S N M P管理进程收到无效共同体的报文 5 e g p N e i g h b o r L o s s 一个E G P邻站已变为故障状态。报文中的第一个变量包含 此邻站的I P地址 6 e n t e r p r i s e S p e c i f i c 在这个特定的代码字段中查找 t r a p信息下一个要注意的是:第1行中的Tr a p(2 8)和第2行中的Tr a p(2 9)是P D U类型和长度。 两个输出行的第一项内容都是相同的 E : u n i x . 1 . 2 . 5。这代表企业名字段和代理进程的 s y s O b j i e c t I D。它是图 2 5 - 6中1 . 3 . 6 . 1 . 4 . 1(i s o . o r g . d o d . i n t e r n e t . p r i v a t e . e n t e r p a r s e s)结点下面的某个结点,所以代理进程的对象标识是1 . 3 . 6 . 1 . 4 . 1 . 4 . 1 . 2 . 5。它的简称 是:u n i x . a g e n t s . f o u r B S D - i s o d e . 5。最后一个数字“5”代表I S O D E代理进程软件的版本号。 这些企业名的值代表了产生t r a p的代理进程软件信息。 输出的下一项是代理进程的 I P地址(1 4 0 . 2 5 2 . 1 3 . 3 3)。 在第1行中,t r a p的类型显示的是c o l d S t a r t,第2行中,显示的是a u t h e n t i c a t i o n F a i l u r e。 与之相对应的t r a p类型值是0和4(如图2 5 - 3 0所示)。由于这些都不是厂家自定义的t r a p,所以特定代 码必须是0,在图中没有显示。 输出的最后分别是2 0和1 9 0 7,这是时间戳字段。它是 T i m e T i c k s类型的值,表示从代理 进程初始化开始到 t r a p发生所经历了多少个百分之一秒。在冷启动 t r a p的情况下,在代理进程 初始化后到t r a p的产生共经历了200 ms。同样,t c p d u m p的输出表明第2个t r a p在第1个t r a p产 生的1 8 . 8 6 s后出现,这对应于打印出的 1 9 0 7个百分之一秒减去200 ms所得到的值。 图2 5 - 2表明t r a p报文还包含很多代理进程发送给管理进程的变量,但在这些在例子中没有 再讨论。 25.11 ASN.1和BER 在正式的S N M P规范中都是采用A S N . 1(Abstract Syntax Notation 1)语法,并且在S N M P 报文中比特的编码采用 B E R(Basic Encoding Rule)。和其他介绍S N M P的书不同,我们有目 的地把A S N . 1和B E R的讨论放到最后。因为如果放在前面讨论,有可能使读者产生混淆而忽 略了S N M P的真正目的是进行网络管理。在这里我们也只是对这两个概念简单地进行解释, [Rose 1990]的第8章详细讨论了A S N . 1和B E R。 A S N . 1是一种描述数据和数据特征的正式语言。它和数据的存储及编码无关。 M I B和 S N M P报文中的所有的字段都是用 A S N . 1描述的。例如:对于 S M I中的i p A d d r e s s数据类型, A S N . 1是这样描述的: IpAddress ::= [APPLICATION 0] -- in network-byte order IMPLICIT OCTET STRING (SIZE (4)) 同样,在M I B中,简单变量的定义是这样描述的: 用S E Q U E N C E和SEQUENCE OF来定义表格的描述更加复杂。 当有了这样的A S N . 1定义,可以有多种编码方法把数据编码为传输的比特流。 S N M P使用 的编码方法是B E R。例如,对于一个简单的整数如 6 4,在B E R中需要用3个字节来表示。第一 个字节说明类型是一个整数,下个字节说明用了多少个字节来存储该整数(在这里是 1),最 后一个字节才是该整数的值。 幸运的是,A S N . 1和B E R这两个繁琐的概念仅仅在实现 S N M P的时候才重要,对我们理解 第25章 SNMP:简单网络管理协议使用291网络管理的概念和流程并没有太大的关系。 25.12 SNMPv2 在1 9 9 3年,发表了定义新版本S N M P的11个R F C。RFC 1441 [Case et al. 1993]是其中的第 一个,它系统地介绍了S N M P v 2。同样,有两本书 [Stallings 1993; Rose 1994]也对S N M P v 2进 行了介绍。现在已经有两个 S N M P v 2的基本模型(参见附录 B . 3中的[Rose 1994]),但是厂家 的实现到1 9 9 4年才能广泛使用。 在本节中,我们主要介绍S N M P v 1和S N M P v 2之间的重要区别。 1) 在S N M P v 2中定义了一个新的分组类型 g e t - b u l k - r e q u e s t,它高效率地从代理进程 读取大块数据。 2) 另的一个新的分组类型是i n f o r m - r e q u e s t,它使一个管理进程可以向另一个管理进 程发送信息。 3) 定义了两个新的M I B,它们是:SNMPv2 MIB和SNMPv2-M2M MIB(管理进程到管理 进程的M I B)。 4) SNMPv2的安全性比S N M P v 1大有提高。在S N M P v 1中,从管理进程到代理进程的共同 体名称是以明文方式传送的。而 SNMP v2可以提供鉴别和加密。 厂家提供的设备支持S N M P v 2的会越来越多,管理站将对两个版本的 S N M P代理进程进行 管理。[Routhier 1993]中描述了如何将S N M P v 1的实现扩展到支持S N M P v 2。 25.13 小结 S N M P是一种简单的、S N M P管理进程和S N M P代理进程之间的请求 -应答协议。M I B定义 了所有代理进程所包含的、能够被管理进程查询和设置的变量,这些变量的数据类型并不多。 所有这些变量都以对象标识符进行标识,这些对象标识符构成了一个层次命名结构,由 一长串的数字组成,但通常缩写成人们阅读方便的简单名字。一个变量的特定实例可以用附 加在这个对象标识符后面的一个实例来标识。 很多S N M P变量是以表格形式体现的。它们有固定的栏目,但有多少条记录并不固定。对 于S N M P来讲,重要的是对表格中的每一行如何进行标识(尤其当我们不知道表格中有多少条 记录时)以及如何按字典方式进行排序(“先列后行”的次序)。最后要说明的一点是: S N M P的g e t - n e x t操作符对任何S N M P管理进程来讲都是最基本的操作。 然后我们介绍了下列的S N M P变量组:s y s t e m、i n t e r f a c e、address translation、I P、I C M P、T C P 和U D P。接着是两个例子,一个介绍如何确定一个接口的M T U,另外一个介绍如何获取路由器的 路由信息。 在本章的后面介绍了 S N M P的t r a p操作,它是当代理进程发生了某些重大事件后主动向管 理进程报告的。最后我们简单介绍了 A S N . 1和B E R,这两个概念比较繁琐,但所幸的是,它 对我们了解S N M P并不十分重要,仅仅在实现 S N M P的时候才要用到。 习题 25.1 我们说过采用两个不同的U D P端口(1 6 1和1 6 2)可以使得一个系统既可以是管理进程,也可以 是代理进程。如果对管理进程和代理进程采用一个同样的端口,会出现什么情况? 25.2 用g e t - n e x t操作,如何列出一张路由表的完整信息? 292使用TCP/IP详解,卷1:协议第26章 Telnet和Rlogin:远程登录 26.1 引言 远程登录(Remote Login)是I n t e r n e t上最广泛的应用之一。我们可以先登录(即注册) 到一台主机然后再通过网络远程登录到任何其他一台网络主机上去,而不需要为每一台主机 连接一个硬件终端(当然必须有登录帐号)。 在T C P / I P网络上,有两种应用提供远程登录功能。 1) Te l n e t是标准的提供远程登录功能的应用,几乎每个 T C P / I P的实现都提供这个功能。它 能够运行在不同操作系统的主机之间。Te l n e t通过客户进程和服务器进程之间的选项协商机制, 从而确定通信双方可以提供的功能特性。 2) Rlogin起源于伯克利U n i x,开始它只能工作在 U n i x系统之间,现在已经可以在其他操 作系统上运行。 在本章中,我们将介绍Te l n e t和R l o g i n。首先介绍R l o g i n,因为R l o g i n比较简单。 Te l n e t是一种最老的I n t e r n e t应用,起源于1 9 6 9年的A R PA N E T。它的名字是“电信 网络协议(telecommunication network protocol)”的缩写词。 远程登录采用客户-服务器模式。图 2 6 - 1显示的是一个Te l n e t客户和服务器的典型连接图 (对于R l o g i n的客户和服务器连接图,我们可以画得更加简单)。 图26-1 客户-服务器模式的Telnet简图 在这张图中,有以下要点需要注意: 1) Te l n e t客户进程同时和终端用户和 T C P / I P协议模块进行交互。通常我们所键入的任何信 息的传输是通过T C P连接,连接的任何返回信息都输出到终端上。 2) Te l n e t服务器进程经常要和一种叫做“伪终端设备”(pseudo-terminal device)打交道, 至少在U n i x系统下是这样的。这就使得对于登录外壳 ( s h e l l )进程来讲,它是被 Te l n e t服务器进 程直接调用的,而且任何运行在登录外壳进程处的程序都感觉是直接和一个终端进行交互。 对于像满屏编辑器这样的应用来讲,就像直接在和终端打交道一样。实际上,如何对服务器 进程的登录外壳进程进行处理,使得它好像在直接和终端交互,往往是编写远程登录服务器 Telnet客户 进程 终端驱动 内核 终端用户 TCP连接 内核 伪终端 驱动 登录 shell Telnet服务 器进程进程程序中最困难的方面之一。 3) 仅仅使用了一条T C P连接。由于客户进程必须多次和服务器进程进行通信(反之亦然), 这就必然需要某些方法,来描绘在连接上传输的命令和用户数据。我们在后面的内容中会介 绍Te l n e t和R l o g i n是如何处理这个问题的。 4) 注意在图 2 6 - 1中,我们用虚线框把终端驱动进程和伪终端驱动进程框了起来。在 T C P / I P实现中,虚线框的内容一般是操作系统内核的一部分。 Te l n e t客户进程和服务器进程一 般只是属于用户应用程序。 5) 把服务器进程的登录外壳进程画出来的目的是为了说明:当我们想登录到系统的时候, 必须要有一个帐号,Te l n e t和R l o g i n都是如此。 对于Te l n e t和R l o g i n,如果比较一下它们客户进程和服务器进程源代码的数量,就可以知 道这两者的复杂程度。图 2 6 - 2显示了伯克利不同版本的 Te l n e t和R l o g i n客户进程和服务器进程 源代码的数量。 图26-2 Telnet/ Rlogin/客户进程/服务器进程的源代码数量比较 现在,不断有新的Te l n e t选项被添加到Te l n e t中去,这就使得Te l n e t实现的源代码数量大大 增加,而R l o g i n依然变化不大,还是比较简单。 远程登录不是那种有大量数据报传输的应用。正如我们前面讲到的一样,客户进程和服 务器进程交互的分组大多比较小。 [Paxson 1993]发现客户进程发出的字节数(用户在终端上 键入的信息)和服务器进程端发出的字节数的数量之比是 1 : 2 0。这是因为我们在终端上键入 的一条短命令往往令服务器进程端产生很多输出。 26.2 Rlogin协议 R l o g i n的第一次发布是在 4 . 2 B S D中,当时它仅能实现 U n i x主机之间的远程登录。这就使 得R l o g i n比Te l n e t简单。由于客户进程和服务器进程的操作系统预先都知道对方的操作系统类 型,所以就不需要选项协商机制。在过去的几年中, R l o g i n协议也派生出几种非 U n i x环境的 版本。 RFC 1282 [Kantor 1991]详细说明了R l o g i n协议。类似于选路信息协议( R I P)的R F C,它 是R l o g i n用了许多年后才发布的。 [Stevens 1990]的第1 5章介绍了远程登录的客户进程及服务 器进程端的编程,并且给出了 R l o g i n的客户进程及服务器进程的完整源代码。 [ C o m e r和 Stevens 1993]的第2 5章和第2 6章给出了Te l n e t的客户进程的实现细节和源代码。 294使用TCP/IP详解,卷1:协议 源程序代 码行数 Telnet客户进程 Telnet服务器进程 Rlogin客户进程 Rlogin服务器进程26.2.1 应用进程的启动 R l o g i n的客户进程和服务器进程使用一个 T C P连接。当普通的T C P连接建立完毕之后,客 户进程和服务器进程之间将发生下面所述的动作。 1) 客户进程给服务器进程发送4个字符串:(a)一个字节的0;(b)用户登录进客户进程主机 的登录名,以一个字节的0结束;(c)登录服务器进程端主机的登录名,以一个字节的0 结束;(d)用户终端类型名,紧跟一个正斜杠“/”,然后是终端速率,以一个字节的0结 束。在这里需要两个登录名字,这是因为用户登录客户和服务器的名称有可能不一样。 由于大多满屏应用程序需要知道终端类型,所以终端类型也必须发送到服务器进程。发 送终端速率的原因是因为有些应用随着速率的改变,它的操作也有所变化。例如 v i编辑 器,当速率比较小的时候,它的工作窗口也变小。所以它不能永远保持同样大小的窗口。 2) 服务器进程返回一个字节的 0。 3) 服务器进程可以选择是否要求用户输入口令。这个步骤的数据交互没有什么特别的协 议,而被当作是普通的数据进行传输。服务器进程给客户进程发送一个字符串(显示 在客户进程的屏幕上),通常是password: 。如果在一定的限定时间内(通常是 6 0秒) 客户进程没有输入口令,服务器进程将关闭该连接。 通常可以在服务器进程的主目录 (home directory)下生成一个文件(通常叫 . r h o s t s),该 文件的某些行记录了一个主机名和用户名。如果从该文件中已经记录的主机上用已经 记录的用户名进行登录,服务器进程将不提示我们输入口令。但是很多关于安全性的 文献,如[Curry 1992],强烈建议不要采用这种方法,因为这存在安全漏洞。 如果提示输入口令,那么我们输入的口令将以明文的形式发送到服务器进程。我们所 键入的每个字符都是以明文的格式传输的。所以某人只要能够截取网络上的原始传输 的分组,他就可以截获用户口令。针对这个问题,新版本的 R l o g i n客户程序,例如 4 . 4 B S D版本的客户程序,第一次采用了 K e r b e r o s安全模型。K e r b e r o s安全模型可以避 免用户口令以明文的形式在网络上传输。当然,这要求服务器进程也支持 K e r b e r o s ([Curry 1992]详细描述了K e r b e r o s安全模型)。 4) 服务器进程通常要给客户进程发送请求,询问终端的窗口大小(将在后面解释)。 客户进程每次给服务器进程发送一个字节的内容,并且接收服务器进程的所有返回信息。 这在1 9 . 2节中已经介绍过了。同样我们也采用了 N a g l e算法(在1 9 . 4节中曾经介绍),该算法可 以保证在速率较低的网络上,若干输入字节以单个 T C P报文段传输。操作其实很简单:用户 键入的所有东西被发送到服务器,服务器发送给客户的任何信息返回到用户的屏幕上。 另外,服务器和客户之间还可以互相发送命令。在介绍这些命令之前,先介绍需要用到 这些命令的场合。 26.2.2 流量控制 默认情况下,流量控制是由 R l o g i n的客户进程完成的。客户进程能够识别用户键入的 S TO P和S TA RT的A S C I I字符(C o n t r o l_S和C o n t r o l_Q),并且终止或启动终端的输出。 如果不是这样,每次我们为终止终端输出而键入的 C o n t r o l _ S字符将沿网络传输到服务器 进程,这时服务器进程将停止往网络上写数据。但是在写操作终止之前,服务器进程可能已 经往网络上写了一窗口的输出数据。也就是说,在输出停止之前,成千上万的数据字节还将 第26章 Telnet和Rlogin:远程登录使用295在屏幕上显示。图2 6 - 3显示了这个情况。 图26-3 服务器进程执行STOP/START的情况 对于一个交互式用户来讲, C o n t r o l _ S字符的响应延时是较大的。 有时候,服务器的应用程序需要解释输入的每个字节,但又不想让客户对它的输入内容 进行处理,例如对控制字符如 C o n t r o l _ S和C o n t r o l _ Q进行特殊处理(e m a c s编辑器就是这样的 一个例子,它把C o n t r o l _ S和C o n t r o l _ C作为自己的命令)。解决这个问题的办法就是由服务器 告诉客户是否要进行流量控制。 26.2.3 客户的中断键 当我们为中断服务器正在运行的进程而键入一个中断字符时(通常是 D E L E T E或 C o n t r o l _ C),会发生和流量控制相同的问题。这个情况和图 2 6 - 3所示的类似,在一条 T C P连接 的管道上,从服务器进程向客户进程正在发送大量的数据,而客户进程同时在向服务器进程传 输中断字符。而我们的本意是要中断字符尽快终止某个进程,使屏幕上不再有任何响应输出。 在流量控制和中断键这两种情况中,流量控制机制很少终止客户进程到服务器进程的数 据流。这个方向仅仅包含我们键入的字符。所以对于从客户输出到服务器的特殊输入字符 (C o n t r o l _ S和中断字符)不需要采用T C P的紧急方式(u rgent mode)。 26.2.4 窗口大小的改变 如果是窗口风格的显示方式,当应用程序在运行的时候,我们还可以动态地改变窗口的 大小。一些应用程序(典型的如那些操作整个窗口的应用程序,如全屏编辑器)需要知道窗 口大小的变化。目前大多数 U n i x系统提供这种功能,可以告诉应用程序关于窗口大小的变化。 对于远程登录这种情况,窗口大小的变化发生在客户端,而运行在服务器端的应用程序 需要知道窗口大小变化。所以 R l o g i n的客户需要采用某些方法来通知服务器窗口大小变化的 情况以及新窗口的大小。 26.2.5 服务器到客户的命令 现在我们介绍通过 T C P连接,R l o g i n服务器进程可以发送给客户进程的 4条命令。问题是 只有一条T C P连接可供使用,所以服务器进程必须给这些命令字节做标记,使得客户进程可 以从数据流中识别出这些是命令,而不是显示在终端上。所以我们将使用 T C P的紧急方式 (在2 0 . 8节中曾经介绍)。 当服务器要给客户发送命令时,服务器就进入紧急方式,并且把命令放在紧急数据的最 后一个字节中。当客户进程收到这个紧急方式通知时,它从连接上读取数据并且保存起来, 直到读到命令字节(即紧急数据的最后一个字节)。这时候客户进程根据读到的命令,再决定 对于所读到并保存起来的数据是显示在终端上还是丢弃它。图 2 6 - 4介绍了这4个命令。 采用T C P紧急方式发送这些命令的一个原因是第一个命令(“清仓输出(flush output)”)需 要立即发送给客户,即使服务器到客户的数据流被窗口流量控制所终止。这种情况下,即服 296使用TCP/IP详解,卷1:协议 终端用户 Rlogin 客户进程 Rlogin服 务器进程 要在终端显示的全屏数据 Control_S→务器到客户的输出被流量控制所终止的情况是经常发生的,这是因为运行在服务器的进程的 输出速率通常大于客户终端的显示速率。另一方面,客户到服务器的数据流很少被流量控制 所终止,因为这个方向的数据流仅仅包含用户所键入的字符。 图26-4 服务器到客户的Rlogin命令 回忆一下图2 0 - 1 4中的例子,在那里我们介绍了即使窗口大小是 0时,紧急通知通过网络 进行传输的情况(在下节中,我们还将介绍一个类似的例子)。其他的3个命令实时性并不特 别强,但为了简单起见,也采用了和第一个命令相同的技术。 26.2.6 客户到服务器的命令 对于客户到服务器的命令,只定义了一条命令,那就是:将当前窗口大小发送给服务器。 当客户的窗口大小发生变化时,客户并不立即向服务器报告,除非收到了服务器发来的 0 x 8 0 命令(图2 6 - 4中有介绍)。 同样,由于只存在一条 T C P连接,客户必须对在连接上传输的该命令字节进行标注,使 得服务器可以从数据流中识别出命令,而不是把它发送到上层的应用程序中去。处理的方法 就是在两个字节的0 x ff后面紧跟着发送两个特殊的标志字节。 对于窗口大小命令,两个标志字节是 A S C I I码的字符‘s’。之后是4个16 bit长的数据(按 网络字节顺序),分别是:行数(例如,2 5),每列的字符数(例如,8 0),X方向的像素数量, Y方向的像素数量。通常情况下,后两个 1 6 b i t是0,因为在R l o g i n服务器进程调用的应用程序 中,通常是以字符为单位来度量屏幕的,而不是像素点。 上面我们介绍的从客户进程到服务器进程的命令采用带内信令( in-band signaling),这是 因为命令字节和其他的普通数据一起传输。选择 0 x ff字节来表示这个带内信令的原因是:一般 用户的操作不会产生0 x ff这个字节。所以说R l o g i n是不完备的,如果我们采用某种方法,使得 通过键盘就可以产生两个连续的 0 x ff字节,而且正好在这之前是两个 A S C I I的‘s’字符,那 么下面的8个字节就会被误认为是窗口大小了。 图2 6 - 4中介绍的是从服务器到客户的 R l o g i n命令,由于大多数的 A P I采用的技术叫做“带 外数据(out-of-band data)”,所以我们就称它为带外信令 (out-of-band signaling)。但是回忆一 下在2 0 . 8节中对T C P紧急方式的讨论,在那里我们说紧急方式数据不是带外数据,命令字节是 按照普通数据流进行传输的,特殊之处是采用了紧急指针。 既然带内信令被用来传输从客户到服务器的命令,那么服务器进程必须检查从客户进程 收到的每个字节,看看是否有两个连续的 0 x ff字节。但是对于采用带外信令的、从服务器传 输到到客户的命令,客户进程不需要检查收到的每个字节,除非服务器进程进入了紧急方 第26章 Telnet和Rlogin:远程登录使用297 字节 描 述 0 x 0 2 清仓输出。客户丢弃所有从服务器收到的数据,直到命令字节(紧急数 据的最后一个字节)。客户还丢弃任何有可能被缓存的挂起输出 ( p e n d i n g o u t p u t )。当服务器收到客户发出的中断命令时,就发送此命令 0 x 1 0 客户停止执行流量控制 0 x 2 0 客户继续进行流量控制处理 0 x 8 0 客户立即响应,将当前窗口大小发送给服务器,并在今后当窗口大小变 化时通知服务器。通常,当连接建立后,服务器就立即发送这个命令式。即使在紧急方式下,客户进程也仅仅需要留意紧急指针所指向的字节。而且由于从客 户进程到服务器的数据流量和相反方向的数据流量之比是 1 : 2 0,这就暗示带内信令适合于数 据量比较小的情况(从客户到服务器),而带外信令适合于数据量比较大的情况(从服务器 到客户)。 26.2.7 客户的转义符 通常情况下,我们向R l o g i n客户进程键入的信息将传输到服务器进程。但是有些时候,我 们并不需要把键入的信息传输到服务器,而是要和 R l o g i n客户进程直接通信。方法是在一行 的开头键入代字符( t i l d e )“~”,紧跟着是下列4个字符之一: 1) 以一个句号结束客户进程。 2) 以文件结束符(通常是C o n t r o l _ D)结束客户进程。 3) 以任务控制挂起符(通常是 C o n t r o l _ Z)挂起客户进程。 4) 以任务控制延迟挂起符(通常是 C o n t r o l _ Y)来挂起仅仅是客户进程的输入。这时,不 管客户运行什么程序,键入的任何信息将由该程序进行解释,但是从服务器发送到客户的信 息还是输出到终端上。这非常适合当我们需要在服务器上运行一个长时间程序的场合,我们 既想知道该程序的输出结果,同时还想在客户上运行其他程序。 只有当客户进程的U n i x系统支持任务控制时,后两个命令才有效。 26.3 Rlogin的例子 在这里举两个例子:第一个是当 R l o g i n会话建立的时候,客户和服务器的协议交互;从第 二个例子可以看到,当用户键入中断键以取消正在服务器运行的程序时,服务器将产生很多 输出。在图1 9 - 2中,我们给出了通常情况下, R l o g i n会话上的数据流交互情况。 26.3.1 初始的客户-服务器协议 图2 6 - 5显示的是从主机b s d i到服务器s v r 4的R l o g i n建立一个连接时的时间系列 (在图中,去 掉了通常的T C P连接的建立过程,窗口通告以及服务类型信息)。 上节介绍的协议对应图中的报文段 1 ~ 9。客户发送一个字节的 0(报文段1)之后发送3个 字符串(报文段 3)。在本例中,这 3个字符串分别是: r s t e v e n s(客户的登录名)、r s t e v e n s (服务器的登录名)和 i b m p c 3 / 9 6 0 0(终端类型和速率)。当服务器确认了这些信息后回送一个 字节的0(报文段5)。 然后服务器发送窗口请求命令(报文段 7)。这是采用T C P紧急方式发送的,我们又一次看 到一个实现( S V R 4 )采用较老的但更普通的解释,即紧急指针指明的序号是紧急数据的最后一 个字节加1。客户回送1 2字节的数据:2字节的0 x ff,2字节的‘s’,4个16 bit长度的窗口数据。 下面的4个报文段( 10, 12, 14和1 6)是由服务器发送的,是从服务器操作系统的问候 ( g r e e t i n g )。之后报文段1 8是一个7字节长度的外壳进程提示符“ s v r 4%”。 客户输入的信息如图 1 9 - 2所示,每次发送一个字节。客户和服务器都可以主动中断该连 接。如果我们输入一个命令,让服务器的外壳程序终止运行,那么服务器将中断该连接。如 果我们给R l o g i n客户键入一个转移符(通常是一个“ ~”),紧跟着一个句点或者是一个文件结 束符号,那么客户将主动关闭该连接。 298使用TCP/IP详解,卷1:协议图2 6 - 5中,客户进程的端口号是 1 0 2 3,这是由I A N A分配的(在 1 . 9节中介绍)。 R l o g i n协议要求客户进程用小于1 0 2 4的端口号,术语叫做保留端口。在U n i x系统中,客 户进程一般不能使用保留端口号,除非客户进程具有超级用户权限。这是客户进程和服 务器进程相互鉴别的一部分,这种鉴别可以使得用户不需要口令而可以登录。[ S t e v e n s 1 9 9 0 ]详细讨论了客户进程和服务器进程相互鉴别的过程和有关保留端口号的问题。 图26-5 Rlogin连接时间次序 26.3.2 客户中断键 让我们看一下另外一个例子,这个例子涉及到 T C P的紧急方式。当数据流已经终止时, 我们键入中断键。这个例子要用到前面讲到的很多 T C P算法如:紧急方式、糊涂窗口避免技 术、窗口流量控制和坚持计时器。在主机 s u n上运行客户进程。我们登录到主机 b s d i,向终 端输出一个大文本文件,然后键入 C o n t r o l _ S中断输出。当输出停止时,我们键入中断键 (D E L E T E)以异常方式中止该进程。 第26章 Telnet和Rlogin:远程登录使用299 1字节的0 1字节的0 命令0x80: 窗口大小请求 窗口大小信息 操作系统的问候 操作系统的问候 操作系统的问候 操作系统的问候 shell提示符sun % rlogin bsdi 所有操作系统的问候 bsdi % cat /usr/share/misc/termcap向终端输出大文件 大量的终端输出 键入C o n t r o l _ S以中断输出, 然后等待直到输出停止 ^? 键入中断键,而这被回显了, bsdi % 然后输出了提示符 下面这些要点是关于客户、服务器和连接的状态的概述: 1) 键入C o n t r o l _ S以停止终端的输出。 2) 用户终端的输出缓存很快被填满,所以 R l o g i n的客户向终端的写操作被阻塞。 3) 此时客户也不能从网络连接上读取数据,所以客户的 T C P接收缓存也将被填满。 4) 当接收缓存已满时,客户进程的 T C P会向服务器进程的T C P通告现在的接收窗口是0。 5) 当服务器收到客户的窗口为 0时,将停止向客户发送数据,这样,服务器的发送缓存也 将被填满。 6) 由于发送缓存已满,所以R l o g i n服务器进程将停止。这样, R l o g i n服务器将不能从服务 器运行的应用程序(c a t)处读取数据。 7) 当c a t程序的输出缓存也被填满时, c a t也将停止。 8) 然后我们用中断键来终止服务器上的 c a t程序。这个命令从客户的 T C P传输到服务器 的T C P,这是因为该方向的数据传输没有被流量控制所终止。 9) c a t应用程序收到中断命令并且终止。这使得它的输出缓存(也就是 R l o g i n服务器进程 读取数据的地方)被清空,这将唤醒R l o g i n服务器进程。然后R l o g i n服务器进程进入紧急方式, 向客户进程发送“清仓输出”命令( 0 x 0 2)。 图2 6 - 6概括了从服务器到客户的数据流(图中的序号就是下面将介绍的图中的时间系列)。 图26-6 Rlogin例子中,服务器进程到客户进程的数据流概述 发送缓存的阴影部分是4 0 9 6字节的缓存中没有被使用的部分。图2 6 - 7是该例子的时间系列。 在报文段1 ~ 3,服务器进程向客户进程发送满长度(即 1 0 2 4字节)的T C P报文段。由于此 时客户进程不能向终端写信息,客户进程也不能从网络上读数据,所以在报文段 4中,客户进 程向服务器进程发送A C K确认时,告诉服务器进程此时接收窗口是1 0 2 4个字节。在报文段5中, 服务器进程发送的数据长度就不再是满长度的了。同样,报文段 6中客户进程的确认信号所带 的接收窗口大小是此时接收缓存的空余字节长度。那么在报文段 5中,客户进程A C K信号中为 什么接收窗口大小是 3 4 9而不是0呢?这是因为如果发送的是 0(糊涂窗口避免技术),那么窗 口指针将右边界移动到了左边界,而这是绝对不能发生的(见 2 0 . 3节)。当服务器进程收到报 300使用TCP/IP详解,卷1:协议 Rlogin 客户进程 4096字节的接收缓存 数据已收到,并也得到了 客户的确认信息,正等待 Rlogin客户进程来读 Rlogin客户进程写的数 据,这也是服务器等 待发途的数据 紧急指针 4096字节的发送缓存 Rlogin服 务器进程文段6的A C K信号后,它就不能再发送全长的数据报了,这时候它就采用糊涂窗口症避免技术, 不发送任何东西,同时置一个 5秒的坚持计时器。当计时器超时,服务器进程就发送一个 3 4 9 字节大小的数据(如报文段 7)。由于此时客户进程依然不能输出接收缓存的信息,所以接收 缓存将被填满,客户进程将发送 A C K信号,此时接收窗口大小为 0(如报文段8)。 这时候我们键入中断键并且以报文段 9显示的那样传输。此时的接收窗口大小依然为 0。 当服务器进程接收到该中断键后,服务器进程把它发送给应用程序( c a t),应用程序就终止。 由于应用程序被终端中断键所终止,应用程序就清空它的输出缓存。服务器进程发现该变化 后就通过T C P紧急方式向客户进程发送“清仓输出”命令,这如报文段 1 0所示。注意命令字 节0 x 0 2放在第3 0 1 4 6字节中(紧急指针减1)。报文段1 0告诉客户进程在命令字节前还有 3 4 1 9个 字节(从2 6 7 2 7到3 0 1 4 5)在服务器进程的发送缓存中等待发送。 报文段1 0采用紧急通知方式发送,包含了服务器进程向客户进程发送的下一个字节(序 号是2 6 7 2 7)。它不包含“清仓输出”命令字节。记得在 2 2 . 2节中曾经介绍过,发送进程可以 发送一个字节的数据来试探对方的接收窗口是否关闭。报文段 1 0就是采用了这个原理。然后 客户进程T C P就立即发送如报文段 11所示的数据。虽然此时接收窗口还是 0,但是在客户进程 内部,由于客户进程的 T C P收到了对方的紧急通知,它把该通知告诉客户进程,客户进程就 知道服务器进程已经进入了紧急方式了。 图26-7 Rlogin举例:当客户程停止输出然后终止服务器的应用程序的情况 第26章 Telnet和Rlogin:远程登录使用301当R l o g i n客户进程从它的T C P收到了紧急通知,并且客户进程开始读取已经在输入缓存中 等待被读取的数据时,接收窗口就会重新打开(报文段 1 3)。然后服务器进程就开始正常发送 数据(报文段14, 15, 17和1 8)。注意报文段1 8的数据报中包含紧急数据的最后一个字节的数据 (序号3 0 1 4 6),该字节包含服务器进程发送给客户进程的命令字节。当客户进程收到该命令后, 它就丢弃报文段 1 4、1 5、1 7和1 8所收到的数据,并且清空终端的输出缓存。在报文段 1 9中的 下两个字节是中断键的回显“ ^ ?”。最后一个报文段(2 1)包含了客户进程的外壳提示符。 这个例子描述了当用户键入中断键后,连接的双方数据如何被存储的情况。如果这些动 作仅仅丢弃在服务器的 3 4 1 9个字节数据,而不丢弃已经在客户的 4 0 9 6个字节的数据,那么这 些已经在客户的终端输出缓存中的 4 0 9 6字节数据将输出到终端上。 26.4 Telnet协议 Te l n e t协议可以工作在任何主机(例如,任何操作系统)或任何终端之间。 RFC 854 [Postel 和Reynolds 1983a]定义了该协议的规范,其中还定义了一种通用字符终端叫做网络虚 拟终端N V T(Network Virtual Te r m i n a l)。N V T是虚拟设备,连接的双方,即客户机和服务器, 都必须把它们的物理终端和 N V T进行相互转换。也就是说,不管客户进程终端是什么类型, 操作系统必须把它转换为 N V T格式。同时,不管服务器进程的终端是什么类型,操作系统必 须能够把N V T格式转换为终端所能够支持的格式。 N V T是带有键盘和打印机的字符设备。用户击键产生的数据被发送到服务器进程,服务 器进程回送的响应则输出到打印机上。默认情况下,用户击键产生的数据是发送到打印机上 的,但是我们可以看到这个选项是可以改变的。 26.4.1 NVT ASCII 术语NVT ASCII代表7比特的A S C I I字符集,网间网协议族都使用 NVT ASCII。每个7比特 的字符都以8比特格式发送,最高位比特为 0。 行结束符以两个字符 C R(回车)和紧接着的 L F(换行)这样的序列表示。以 \ r \ n来表 示。单独的一个 C R也是以两个字符序列来表示,它们是 C R和紧接着的 N U L(字节0),以 \ r \ 0表示。 在下面的章节中可以看到, F T P, SMTP, Finger和W h o i s协议都以NVT ASCII来描述客户命 令和服务器的响应。 26.4.2 Telnet命令 Te l n e t通信的两个方向都采用带内信令方式。字节 0 x ff(十进制的 2 5 5)叫做 I A C (interpret as command,意思是“作为命令来解释”)。该字节后面的一个字节才是命令字节。 如果要发送数据2 5 5,就必须发送两个连续的字节 2 5 5(在前面一节中我们讲到数据流是 N V T A S C I I,它们都是 7 b i t的格式,这就暗示着 2 5 5这个数据字节不能在 Te l n e t上传输。其实在 Te l n e t中有一个二进制选项,在 R F C 8 5 6 [ P o s t e l和Reynolds 1983b]中有定义,关于这点我们没 有讨论,该选项允许数据以 8 b i t进行传输)。图2 6 - 8列出了所有的Te l n e t命令。 由于这些命令中很多命令很少用到,所以对于一些重要的命令,如果在下面章节的例子 或叙述中遇到,我们再做解释。 302使用TCP/IP详解,卷1:协议图26-8 当前一个字节是IAC(255)时的Telnet命令集 26.4.3 选项协商 虽然我们可以认为 Te l n e t连接的双方都是 N V T,但是实际上Te l n e t连接双方首先进行交互 的信息是选项协商数据。选项协商是对称的,也就是说任何一方都可以主动发送选项协商请 求给对方。 对于任何给定的选项,连接的任何 一方都可以发送下面 4种请求的任意一 个请求。 1) WILL: 发 送 方 本 身 将 激 活 ( e n a b l e )选项。 2) DO:发送方想叫接收端激活选 项。 3) WONT:发送方本身想禁止选 项。 4) DON’T:发送方想让接收端去禁 止选项。 由于Te l n e t规则规定,对于激活选 项请求(如1和2),有权同意或者不同意。而对于使选项失效请求(如 3和4),必须同意。这 样,4种请求就会组合出6种情况,如图2 6 - 9所示。 选项协商需要3个字节:一个I A C字节,接着一个字节是 WILL, DO, WONT和D O N T这四 第26章 Telnet和Rlogin:远程登录使用303 名称 代码(十进制) 描 述 E O F 2 3 6 文件结束符 S U S P 2 3 7 挂起当前进程(作业控制) A B O RT 2 3 8 异常中止进程 E O R 2 3 9 记录结束符 S E 2 4 0 子选项结束 N O P 2 4 1 无操作 D M 2 4 2 数据标记 B R K 2 4 3 中断 I P 2 4 4 中断进程 A O 2 4 5 异常中止输出 AY T 2 4 6 对方是否还在运行? E C 2 4 7 转义字符 E L 2 4 8 删除行 G A 2 4 9 继续进行 S B 2 5 0 子选项开始 W I L L 2 5 1 选项协商(图 2 6 - 9) W O N T 2 5 2 选项协商 D O 2 5 3 选项协商 D O N T 2 5 4 选项协商 I A C 2 5 5 数据字节2 5 5 发送方 接收方 描 述 1 . W I L L → 发送方想激活选项 ← D O 接收方说同意 2 . W I L L → 发送方想激活选项 ← D O N T 接收方说不同意 3 . D O → 发送方想让接收方激活选项 ← W I L L 接收方说同意 4 . D O → 发送方想让接收方激活选项 W O N T ← 接收方说不同意 5 . W O N T → 发送方想禁止选项 ← D O N T 接收方必须说同意 6 . D O N T → 发送方想让接收方禁止选项 ← W O N T 接收方必须说同意 图26-9 Telnet选项协商的6种情况者之一,最后一个I D字节指明激活或禁止选项。 现在,有4 0多个选项是可以协商的。 A s s i g n e d Number RFC文档中指明选项字节的值,并且 一些相关的 R F C文档描述了这些选项。图 2 6 - 1 0显示了在本章中会出现的选项代码。 Te l n e t的选项协商机制和Te l n e t协议的大部 分内容一样,是对称的。连接的双方都可以发 起选项协商请求。但我们知道,远程登录不是 对称的应用。客户进程完成某些任务,而服务 器进程则完成其他一些任务。下面我们将看到, 某些Te l n e t选项仅仅适合于客户进程(例如要 求激活行模式方式),某些选项则仅仅适合于 服务器进程。 26.4.4 子选项协商 有些选项不是仅仅用“激活”或“禁止”就能够表达的。指定终端类型就是一个例子, 客户进程必须发送用一个 A S C I I字符串来表示终端类型。为了处理这种选项,我们必须定义子 选项协商机制。 在R F C 1 0 9 1 [ VanBokkelen 1989]中定义了如何表示终端类型这样的子选项协商机制。首先 连接的某一方(通常是客户进程)发送 3个字节的字符序列来请求激活该选项。 这里的2 4(十进制)是终端类型选项的 I D号。如果收端(通常是服务器进程)同意,那 么响应数据是: 然后服务器进程再发送如下的字符串: 该字符串询问客户进程的终端类型。其中 S B是子选项协商的起始命令标志。下一个字节 的“2 4”代表这是终端类型选项的子选项(通常S B后面的选项值就是子选项所要提交的内容)。 下一个字节的“ 1”表示“发送你的终端类型”。子选项协商的结束命令标志也是 I A C,就像 S B是起始命令标志一样。如果终端类型是 i b m p c,客户进程的响应命令将是: <IAC, SB, 24, 0‘I’, ‘B’, ‘M’, ‘P’, ‘C’, IAC, SE> 第4个字节“0”代表“我的终端类型是”(在Assigned Numbers RFC文档中有正式的关于 终端类型的数值定义,但是最起码在 U n i x系统之间,终端类型可以用任何对方可理解的数据 进行表示。只要这些数据在 t e r m c a p或t e r m i n f o数据库中有定义)。在Te l n e t子选项协商过程中, 终端类型用大写表示,当服务器收到该字符串后会自动转换为小写字符。 26.4.5 半双工、一次一字符、一次一行或行方式 对于大多数Te l n e t的服务器进程和客户进程,共有 4种操作方式。 1. 半双工 304使用TCP/IP详解,卷1:协议 选项标识(十进制) 名 称 R F C 1 回显 8 5 7 3 抑制继续进行 8 5 8 5 状态 8 5 9 6 定时标记 8 6 0 2 4 终端类型 1 0 9 1 3 1 窗口大小 1 0 7 3 3 2 终端速率 1 0 7 9 3 3 远程流量控制 1 3 7 2 3 4 行方式 11 8 4 3 6 环境变量 1 4 0 8 图26-10 本章中将讨论的Telnet选项代码这是Te l n e t的默认方式,但现在却很少使用。 N V T默认是一个半双工设备,在接收用户输 入之前,它必须从服务器进程获得 GO AHEAD(G A)命令。用户的输入在本地回显,方向是 从N V T键盘到N V T打印机,所以客户进程到服务器进程只能发送整行的数据。 虽然该方式适用于所有类型的终端设备,但是它不能充分发挥目前大量使用的支持全双 工通信的终端功能。RFC 857 [Postel 和Reynolds 1983c]定义了E C H O选项,RFC 858 [Postel 和Reynolds 1983d]定义了SUPPRESS GO AHEAD(抑制继续进行)选项。如果联合使用这两 个选项,就可以支持下面将讨论的方式:带远程回显的一次一个字符的方式。 2. 一次一个字符方式 这和前面的R l o g i n工作方式类似。我们所键入的每个字符都单独发送到服务器进程。服务 器进程回显大多数的字符,除非服务器进程端的应用程序去掉了回显功能。 该方式的缺点也是显而易见的。当网络速度很慢,而且网络流量比较大的时候,那么回 显的速度也会很慢。虽然如此,但目前大多数 Te l n e t实现都把这种方式作为默认方式。 我们将看到,如果要进入这种方式,只要激活服务器进程的 SUPPRESS GO AHEAD选项 即可。这可以通过由客户进程发送 DO SUPPRESS GO AHEAD(请求激活服务器进程的选项) 请求完成,也可以通过服务器进程给客户进程发送 WILL SUPPRESS GO AHEAD(服务器进 程激活选项)请求来完成。服务器进程通常还会跟着发送 WILL ECHO,以使回显功能有效。 3. 一次一行方式 该方式通常叫做准行方式( kludge line mode),该方式的实现是遵照RFC 858的。该R F C 规定:如果要实现带远程回显的一次一个字符方式, E C H O选项和SUPPRESS GO AHEAD选 项必须同时有效。准行方式采用这种方式来表示当两个选项的其中之一无效时, Te l n e t就是工 作在一次一行方式。在下节中我们将介绍一个例子,可以看到如何协商进入该方式,并且当 程序需要接收每个击键时如何使该方式失效。 4. 行方式 我们用这个术语代表实行方式选项,这是在 RFC 1184[Borman 1990]中定义的。这个选项 也是通过客户进程和服务器进程进行协商而确定的,它纠正了准行方式的所有缺陷。目前比 较新的Te l n e t实现支持这种方式。 图2 6 - 11是不同的Te l n e t客户进程和服务器进程之间默认的操作方式。“c h a r”表示一次一 个字符方式,“k l u d g e”表示准行方式,“l i n e m o d e”表示如RFC 11 8 4定义的实行方式。 图26-11 不同的Telnet客户进程和服务器进程之间默认的操作方式 从图中可以看出,只有当客户进程和服务器进程都是 B S D / 3 8 6或4 . 4 B S D的时候才支持实 行方式。当服务器进程的操作系统是这两者之一时,如果客户进程不支持实行方式,才会协 商进入准行方式。从图中还可以看出,其实任何类型的客户进程和服务器进程都支持准行方 式,但是一般都不把它作为默认方式,除非服务器进程指定。 第26章 Telnet和Rlogin:远程登录使用305 客户端 服 务 器 端26.4.6 同步信号 Te l n e t以Data Mark命令(即图2 6 - 8中的D M)作为同步信号,该同步信号是以 T C P紧急数 据形式发送的。 D M命令是随数据流传输的同步标志,它告诉收端回到正常的处理过程上来。 Te l n e t的双方都可以发送该命令。 当一端收到对方已经进入了紧急方式的通知后,它将开始读数据流,一边读一边丢弃所读 的数据,直到读到Te l n e t命令为止。紧急数据的最后一个字节就是 D M字节。采用T C P紧急方式 的原因就是:即使T C P数据流已经被T C P流量控制所终止,Te l n e t命令也可以在连接上传输。 在下节中我们将看到Te l n e t同步信号的使用情况。 26.4.7 客户的转义符 和R l o g i n的客户进程一样, Te l n e t客户进程也可以使用户直接和客户进程进行交互,而不 是被发送到服务器进程。通常客户的转义字符是 C o n t r o l _ ](c o n t r o l键和右中括号键,通常以 “^ ]”表示)。这使得客户进程显示它的提示符,通常是“ t e l n e t >”。这时候有很多命令可供 用户选择,以改变连接的特性或打印某些信息。大多数的 U n i x客户进程提供“ h e l p”命令, 该命令将显示所有可用的命令。 在下节中我们将看到客户进程转义的例子,以及此时可以输入的命令。 26.5 Telnet举例 在这里我们将介绍在三种不同的操作方式下 Te l n e t选项协商的情况。这些方式包括:单字 符方式、实行方式和准行方式。同样我们还将讨论当用户在服务器端按了中断键退出了一个 正在运行的进程后,系统的运行情况。 26.5.1 单字符方式 首先介绍基本的单字符方式,该方式类似于 R l o g i n。用户在终端输入的每个字符都将由终 端发送到服务器进程,服务器进程的响应也将以字符方式回显到终端上。在这里运行的是一 个新的客户进程B S D / 3 8 6,它试图激活很多新的选项,服务器进程还是运行老的 S V R 4,我们 将看到很多选项被服务器拒绝。 为了看到服务器和客户机之间选项协商的内容,我们将激活客户进程的一个选项来显示 所有的选项协商。同样我们运行 t c p d u m p来获得数据报交换的时间次序。图 2 6 - 1 2显示了这个 交互会话。 在图中,我们已经对由 S E N T或R C V D开头的选项协商的每一步都进行了标注。关于每一 步的解释如下: 1) 客户发起SUPPRESS GO AHEAD选项协商。由于GO AHEAD命令通常是由服务器发送 给客户的,而且客户希望服务器激活该选项,因此该选项的请求方式是 D O(由于激活这一选 项将会禁止G A命令的发送,上述过程很容易让人混淆)。在第1 0行可以看到服务器进程同意 该选项。 2) 客户进程要按照在RFC 1091[VanBokkelen 1989]中的定义发送终端类型。这对U n i x类型的 客户进程来讲是很普通的。因为客户进程要激活本地的选项,所以该选项的请求方式是W I L L。 306使用TCP/IP详解,卷1:协议图26-12 Telnet双方选项协商的初始化过程 3) NAW S的意思是“协商窗口大小”,它在RFC 1073 [Wa i t z m a n ]中有定义。如果服务器 进程同意该选项(实际上不同意,见 11行),客户进程就要发送终端窗口的行、列大小的子选 项。而且只要窗口大小发生变化,客户进程随时都将向服务器进程发送这一子选项(这和图 2 6 - 4中R l o g i n的0 x 8 0命令类似)。 4) TSPEED选项允许发送方(通常是客户进程)发送它的终端速率,这在 RFC 1079 [Hedrick 1988b]中有定义。如果服务器进程同意(实际上不同意,见 1 2行),客户进程将发送 其发送速率和接收速率的子选项。 5) LFLOW代表“本地流量控制”,这在RFC1371 [Hedrick 和Borman 1992]中定义。客户 进程给服务器进程发送该选项,表示客户进程希望用命令方式激活或禁止流量控制。如果服 务器进程同意(实际上不同意,见 1 3行),只要C o n t r o l _ S和C o n t r o l _ Q进程需要在客户进程和 服务器进程进行切换,客户进程都要向服务器进程发送子选项(这类似于图 2 6 - 4中R l o g i n的 0 x 1 0和0 x 2 0命令)。正如在关于R l o g i n的讨论中我们所提到的那样,由客户进程进行流量控制 的效果比由服务器进程来完成要好。 6) LINEMODE代表在2 6 . 4中所说的实行方式。所有终端字符的处理由 Te l n e t客户进程完成 (例如回格,删除行等),然后整行发送给服务器进程。在本节后面,我们将介绍一个例子。 该选项同样被服务器进程拒绝,如 1 4行所示。 7) ENVIRON选项允许客户进程把环境变量发送给服务器进程,这在 RFC 1408 [Borman 第26章 Telnet和Rlogin:远程登录使用307 调用客户进程,不带任何命令行选项 告诉客户进程显示所有的选项协商过程 现在和服务器建立连接 (后面将讨论的行序号) 我们键入用户和口令,服务进程不回显这些数据, 然后操作系统问候输出,然后是外壳提示符1 9 9 3 a ]中有定义。这样就可以把客户进程的用户环境变量自动传播到服务器进程。在 1 5行, 服务器进程拒绝该选项( U n i x中的环境变量通常是大写字母,紧跟一个等号,然后是一个字 符串值,当然这只是一个惯例而已)。默认情况下,BSD/386 Te l n e t客户进程发送两个环境变 量:D I S P L AY和P R I N T E R,前提是这两个变量已经定义并且有效。 Te l n e t用户可以定义其他 一些要发送的环境变量。 8) STAT U S选项(RFC 859 [Postel 和Reynolds 1983e]中定义)允许连接的一方询问对方 对Te l n e t选项目前状态的理解。在这个例子中,客户进程要求对方激活选项( D O)。如果服务 器进程同意(实际上不同意,见 1 6行),客户进程就可以要求服务器进程以子选项的形式发送 它的状态值。 9) 这是服务器进程的第一个响应。服务器进程同意激活终端类型选项(几乎所有的 U n i x 类型的服务器进程都支持该选项)。但现在客户进程还不能立即发送它的终端类型。它必须要 等到服务器进程用子选项的形式询问终端类型的时候才能够发送( 1 7行)。 10) 服务器进程同意抑制发送GO AHEAD命令。 11) 服务器进程不同意客户进程发送它的窗口大小。 12) 服务器进程不同意客户进程发送它的终端速率。 13) 服务器进程不同意客户进程实施流量控制。 14) 服务器进程不同意客户进程激活行方式选项。 15) 服务器进程不同意客户进程发送环境变量。 16) 服务器进程不发送状态信息。 17) 这是服务器进程要求客户进程发送终端类型的子选项。 18) 客户进程把终端类型“I B M P C 3”以6字节的字符串形式发送给服务器进程。 19) 服务器进程要求客户进程发起请求,要求服务器进程激活回显选项。这是本例中服务 器进程第一次主动发起选项协商。 20) 客户进程同意由服务器进程实现回显功能。 21) 服务器进程要求客户进程实现回显功能。这个命令是多余的,它只是将前两行进行了 交换。这是目前大多数 U n i x的Te l n e t服务器进程判断客户进程是否运行 4 . 2 B S D或更新的B S D 版本时的一个方法。如果客户进程回送 WILL ECHO,就表明客户进程运行的是老版本的 4 . 2 B S D,不支持T C P的紧急方式(在这种情况下就不能采用 T C P紧急方式)。 22) 客户进程回送WONT ECHO,表示它不是一台4 . 2 B S D主机。 23) 对于客户进程回送的WONT ECHO,服务器进程以DONT ECHO作为响应。 图2 6 - 1 3显示的是本例中服务器进程和客户进程交互的时间系列(去掉了连接建立部分)。 报文段1包含了图2 6 - 1 2中的1 ~ 8行。该报文段中包含2 4个字节数据,每个选项占 3个字节。 这是客户进程发起的选项协商。该报文段显示多个 Te l n e t选项可以打在一个T C P段中发送。 报文段3是图2 6 - 1 2中的第9行,即DO TERMINAL TYPE命令。报文段5包含下面的8个选 项协商中服务器进程的响应,即图 2 6 - 1 2中的1 0 ~ 1 7行。该报文段的长度是 2 7个字节,因为 1 0 ~ 1 6行是常规选项,每个占 3个字节,而1 7行的子选项部分占 6个字节。报文段6包含1 2个字 节,和1 8行对应,这是客户发送它的终端类型的子选项。 报文段8(5 3个字节)包含两个 Te l n e t命令和4 7字节的输出数据。前面的两个服务器进程 发送Te l n e t命令占6字节,:WILL ECHO和DO ECHO(1 9和2 1行)。后4 7个字节的数据是: 308使用TCP/IP详解,卷1:协议\r\n\r\nUNIX(r) System V Release 4.0 (svr4) \r\n\r\0\r\n\r\0 前面4个字节数据在字符串输出之前产生两个空行。两字节的字符序列“ \ r \ n”在Te l n e t中 被认为是换行命令,而两字节的字符序列“ \ r \ 0”则被认为是回车命令。这表明数据和命令可 以在一个数据段中传输。 Te l n e t服务器进程和客户进程必须扫描接收到的每个字符,寻找 I A C 字节并执行它后续的命令。 图26-13 Telnet服务器进程和客户进程选项协商初始化过程 报文段9包含客户进程发送的最后两个选项: 2 0和2 2行。2 3行是报文段1 0的响应,也是服 务器进程发送的最后一个选项数据。 从现在开始,双方就可以交互数据了。当然在交互数据的过程中还可以进行选项协商, 我们在该例子中就不多介绍了。报文段 1 2是服务器进程发送的提示符“ l o g i n :”。报文段1 4是 用户输入的登录用户名的第一个字符,它的回显在报文段 1 5中。这和我们在 1 9 . 2节中介绍的 R l o g i n交互类似:客户进程每次发送一个字符,服务器进程完成回显工作。 图2 6 - 1 2中的选项协商由客户进程初始化的,但是在本书中我们已经介绍了用 Te l n e t客户进程连接某些标准服务器进程如:日间(d a y t i m e)服务器、回显( e c h o )服务 器等情况。当然我们介绍这些的目的是为了描述 T C P的各种特性。但考察这些例子中 第26章 Telnet和Rlogin:远程登录使用309的分组交换,如图1 8 - 1,我们并没有看到客户进程发起的选项协商。为什么?这是因 为在U n i x系统中,除非使用标准的Te l n e t端口号2 3,否则客户进程不进行选项协商。这 个特性使得Te l n e t客户进程可以使用标准的N V T同其他一些非Te l n e t服务器进程交换数 据。我们已经在日间服务器、回显服务器和丢弃( d i s c a r d )服务器中使用了这个特性,在 后面章节介绍FTP和SMTP服务器的时候我们还将使用该特性。 26.5.2 行方式 为了描述 Te l n e t的行方式选项协商过程,我们在主机 b s d i运行客户进程,服务器是位于 v a n g o g h . v s . b e r k e l e y . e d u节点运行4 . 4 B S D操作系统的一台主机。 B S D / 3 8 6和4 . 4 B S D都 支持这个选项。 我们不详细讨论所有的报文、选项和子选项协商过程,因为这个过程和前面的例子类似, 而且对于行方式选项我们已经论述得比较清楚。下面我们仅仅讨论在选项协商中的一些区别。 1) 对于B S D / 3 8 6希望协商的选项例如:窗口大小、本地流量控制、状态、环境变量和终 端速率等,4 . 4 B S D服务器进程都支持。 2) 4 . 4 B S D服务器进程将协商一个 B S D / 3 8 6客户进程不支持的新选项:鉴别(为避免以明 文形式在网络上传输用户口令)。 3) 和上个例子一样,客户进程发送 WILL LINEMODE选项,由于服务器进程支持该选项, 所以服务器进程发送DO LINEMODE。此时客户进程以子选项形式给服务器进程发送1 6个 特定字符。这些字符是能影响客户进程的特定终端字符值:如中断字符,文件结束符等。 服务器进程给客户进程发送一个子选项,让客户进程处理所有的输入,执行所有的编 辑功能(删除字符,删除行等)。客户进程把除控制字符以外的字符以行的形式发送给 服务器进程。服务器进程还要求客户进程把所有中断键和信号键转换为相应的 Te l n e t字 符。例如中断键是C o n t r o l _ C,我们可以按C o n t r o l _ C来中断服务器端的某个进程。客户 进程必须把C o n t r o l _ C转换为Te l n e t的I P命令()传输给服务器进程。 4) 当用户输入口令时情况也有所不同。在 R l o g i n和一次一字符方式的 Te l n e t中,都是由服 务器进程负责回显,所以当服务器进程读到口令时,它并不回显这些字符。但在行方 式中由客户进程负责回显。下面这些交互过程将处理这种情况: (a) 服务器进程发送WILL ECHO,以告诉客户进程:服务器进程将处理回显。 (b) 客户进程回送DO ECHO。 (c) 服务器进程向客户进程发送字符串 P a s s w o r d:,客户进程把它发送到终端上。 (d) 然后用户输入口令,当用户按下 R E T U R N键的时候,客户进程把口令发送给服务器 进程。此时口令不回显,因为客户进程认为服务器进程将回显它。 (e) 由于口令的结束符 R E T U R N没有回显,服务器进程发送两字节字符序列 C R和L F以 移动光标。 (f) 服务器进程发送WONT ECHO。 (g) 客户进程回送DONT ECHO。然后继续由客户进程负责回显。 一旦登录完成,客户进程将把数据以整行的方式发送给服务器进程。这就是行方式选项 的目的。行方式大大地减少了客户进程和服务器进程之间的数据交互数量,而且对于用户的 310使用TCP/IP详解,卷1:协议击键(也就是回显和编辑)提供更快的响应。图 2 6 - 1 4显示的是当我们输入命令时,在行方式 连接下分组交换的情况。 Vangogh % d a t e (去掉了业务种类信息和窗口通告信息)。 图26-14 Telnet行方式下客户进程向服务器进程发送命令的情况 把它和在R l o g i n中输入同样命令(图 1 9 - 2)时的情况进行一下比较。我们看到在 Te l n e t行 方式下只需要 2个报文段(一个包含数据,另一个用于 A C K,连同 I P和T C P首部共8 6字节), 而在R l o g i n中要发送1 5个报文段(5个有键入的数据, 5个有回显的数据, 5个是A C K,共6 11 字节)。可见节省的数据量是非常可观的。 如果在服务器端运行一个需要进入单个字符方式的应用程序(例如 v i编辑器)会怎么样 呢?实际上将发生如下的一些交互: 1) 当服务器的应用程序启动了,并改变其伪终端方式时, Te l n e t服务器进程被通告需要进 入单个字符方式。然后服务器发送 WILL ECHO命令和行方式子选项,以告知客户不要再以行 方式工作,转而进入单个字符方式。 2) 客户响应以DO ECHO,并确认行方式子选项。 3) 应用程序在服务器上运行。我们键入的每个字符将发送到服务器(当然要强制使用 N a g l e算法),此时服务器将处理必要的回显工作。 4) 当应用程序终止时,就恢复其伪终端方式,并通告 Te l n e t服务器。服务器将向客户发送 WONT ECHO命令,同时发送行方式子选项,告诉客户恢复进入行方式。 5) 客户响应DONT ECHO,确认进入行方式。 上述情况同我们键入口令之间的区别表明:回显功能和单个字符方式与一次一行方式没 有依赖关系。当我们键入口令时,回显功能必须失效,但一次一行方式有效。对于一个全屏 应用来讲,例如编辑器,回显必须失效而单个字符方式必须有效。 图2 6 - 1 5概括了R l o g i n和Te l n e t不同方式之间的差异。 第26章 Telnet和Rlogin:远程登录使用311图26-15 Rlogin和不同方式的Telnet之间的比较 26.5.3 一次一行方式(准行方式) 从图2 6 - 11可以看出,如果客户不支持行方式,那么较新的服务器支持行方式选项,它也 将转入准行方式(Kludge line mode)。我们同时指出所有的客户进程和服务器进程都支持准行 方式,但它不是默认方式,必须由客户进程或用户特地激活它。让我们来看看如何用 Te l n e t选 项激活准行方式。 首先介绍当客户进程不支持行方式时, B S D / 3 8 6服务器进程如何协商进入该方式。 1) 当客户进程不同意服务器进程激活行方式的请求时,服务器进程发送 DO TIMING M A R K选项。RFC 860 [Postel 和Reynolds 1983f]定义了这个Te l n e t选项。它的作用是让收发双 方同步,关于这个问题将在本节的后面讲到用户键入中断键时讨论。该选项只是用来判断客 户进程是否支持准行方式。 2) 客户响应WILL TIMING MARK,表明支持准行方式。 3) 服务器发送WONT SUPPRESS GO AHEAD和WONT ECHO选项,告诉客户它希望禁 止这两个选项。我们在前面已经强调:单个字符方式下是假定 SUPPRESS GO AHEAD和 E C H O选项同时有效的,所以禁止两个选项就进入了准行方式。 4) 客户响应DONT SUPPRESS GO AHEAD和DONT ECHO命令。 5) 服务器发送l o g i n :提示符,然后用户键入用户名。用户名是以整行的方式发送给服务 器,回显由客户进程在本地处理。 6) 服务器发送P a s s w o r d :提示符和WILL ECHO命令。这将使客户进程的回显失效,因 为此时客户进程认为服务器进程将处理回显工作,所以用户键入的口令就不回显到屏幕上。 客户响应DO ECHO命令。 7) 我们键入口令。客户以整行方式发送到服务器。 8) 服务器发送WONT ECHO命令,使得客户重新激活回显功能,客户响应 DONT ECHO。 从此以后的普通命令处理过程就和行方式相似了。客户进程负责所有的编辑和回显,并 以整行的方式发送给服务器进程。 在图2 6 - 11中,我们已经强调:所有标注为“ c h a r”的记录都支持准行方式,只不过默认 是单个字符方式罢了。如果要客户进入行方式,我们就能很容易看到选项协商的过程: 312使用TCP/IP详解,卷1:协议 应用程序 客户进程发送 客户进程回显? 例 子 一次一字符 一次一行 R l o g i n • 否 Te l n e t • 否 Te l n e t,行方式 • 是 正常命令 Te l n e t,行方式 • 否 键入我们的口令 Te l n e t,行方式 • 否 v i编辑器 客户是sun,服务器是svr 4 键入Control]以和Telnet客户进程通信(无回显) 检验现在是否在一次一字符方式下这将使Te l n e t会话进入准行方式,此时SUPPRESS GO AHEAD和E C H O选项都是失效的。 如果在服务器端运行如v i编辑器这样的应用程序,同样会有行方式下遇到的问题。当要运 行这样的应用程序时,服务器进程必须告诉客户进程从准行方式切换到单字符方式。当应用 程序结束时,必须告诉客户进程返回到准行方式。下面是这个过程需要用到的技术要点。 1) 当应用程序改变其伪终端方式并通知服务器进程时,服务器进程将进入单字符方式。 服务器进程向客户进程发送 WILL SUPPRESS GO AHEAD和WILL ECHO,这将使客户进程进 入单字符方式。 2) 客户进程回送DO SUPPRESS GO AHEAD和WILL ECHO。 3) 应用程序开始在服务器端运行。 4) 当应用程序结束并改变其伪终端方式时,服务器进程发送 WONT SUPPRESS GO A H E A D和WONT ECHO命令,使得客户进程返回准行方式。 5) 客户进程回送DONT SUPPRESS GO AHEAD和DONT ECHO命令,告诉服务器进程它 已经回到了准行方式。 图2 6 - 1 6概括了单个字符方式及准行方式中不同的SUPPRESS GO AHEAD和E C H O选项设置。 图26-16 准行方式下Telnet选项的设置 26.5.4 行方式:客户中断键 看一下当用户键入中断键时 Te l n e t将发生什么情况。假定在客户主机 b s d i和服务器 c a n g o g h . c s . b e r k e l e y . e d u之间建立了一个Te l n e t会话。图2 6 - 1 7显示了当用户键入中断 键后的时间系列(去掉了窗口通告和服务类型)。 报文段1中显示的是中断键(通常是C o n t r o l _ C或D E L E T E)已经转换为Te l n e t的I P(中断进程) 命令:。下面的3个字节:,组成了Te l n e t的DO TIMING MARK选项。这 个标志由客户进程发送,必须使用W I L L或W O N T响应。所有在响应前收到的数据都要丢弃(除 非是Te l n e t命令)。这是服务器进程和客户机端的同步过程。报文段1没有采用T C P紧急方式。 Host Requirements RFC叙述了I P命令不能使用Te l n e t的同步信号来发送。如果可以的 话,那么的后面将跟随,同时紧急指针指向D M字节。大多数的 Unix Telnet 客户有一个选项来使用同步信号发送 I P命令,但是这个选项默认是不用的 (正如我们这里看到的)。 第26章 Telnet和Rlogin:远程登录使用313 方 式 SUPPRESS GO AHEAD E C H O 举 例 一次一字符 √ √ 准行方式下的 v i编辑器 准行方式 × × 正常命令 准行方式 × √ 键入我们的口令 注意选项协商过程 切换到准行方式 客户发送这两个选项 服务器把WONT做为上述两个选项协商的响应图26-17 行方式下键入中断键后的情况 报文段 2是服务器进程对 DO TIMING MARK选项的响应。紧随其后的是报文段 3和4中 Te l n e t的同步信号:。报文段3中的紧急指针指向将在报文段 4中发送的D M字节。 如果服务器进程到客户进程的窗口已满,那么客户进程发送了如报文段 1中的I P命令后就 丢弃收到的所有数据。即使服务器进程被 T C P流量控制所终止而不能发送如报文段 2、3和4中 的数据,紧急指针仍然可以发送。这和图 2 6 - 7中的R l o g i n类似。 为什么同步信号要分为两个数据段发送( 3和4)?原因就是我们在 2 0 . 8节中详细讨论T C P 紧急指针时提到的情况。有关主机需求的 R F C中提到紧急指针应指向紧急数据的最后一个字 节,而很多衍生于伯克利的系统中,紧急指针指向紧急数据的倒数第 2个字节(回忆一下在图 2 6 - 6中,紧急指针指向命令字节的前一个字节)。Te l n e t服务器进程故意把同步信号的第 1个字 节作为紧急数据,它知道紧急指针将指向下 1个字节(即D M字节),而I A C字节和紧急指针必 须立即发送,在下一步才发送 D M字节。 最后一个报文段6发送的是数据,它是服务器进程发生的提示符。 26.6 小结 本章我们介绍了 R l o g i n和Te l n e t操作。两者都提供了从客户进程远程登录到服务器进程, 是我们能够在服务器端运行程序的方法。 这两个应用是不同的。 R l o g i n假定连接的双方都是 U n i x系统,所以只提供一个选项,它 是1个简单的协议。Te l n e t则不同,它用于在不同类型的主机之间建立连接。 为了支持这种多机环境, Te l n e t提供客户进程和服务器进程的选项协商机制。如果连接的 双方都支持这些选项,则可以增强一些功能。对于比较简单的客户进程和服务器进程,它可 以提供Te l n e t的基本功能,而当双方都支持某些选项时,它又可以充分利用双方的新特性。 我们介绍了Te l n e t的选项协商机制,也介绍了 3种数据传输的方式:单字符方式、准行方 式和实行方式。现在的趋势是只要有可能,就尽量工作在准行方式下。这样可以减少网络上 的数据量,同时为交互用户提供更好的行编辑和回显的响应。 图2 6 - 1 8概括并比较了R l o g i n和Te l n e t的不同特性。 314使用TCP/IP详解,卷1:协议 键入中断键图26-18 Rlogin和Telnet的不同特性 R l o g i n服务器和Te l n e t服务器通常都将设置 T C P的保活选项以检测客户主机是否崩溃(如 果服务器的T C P实现支持,见第 2 3章)。这两种应用都采用了 T C P紧急方式,以便即使从服务 器到客户的数据传输被流量控制所终止,服务器仍然可以向客户发送命令。 习题 26.1 在图2 6 - 5中,标出所有延迟的A C K。 26.2 在图2 6 - 7中,为什么要发送报文段1 2? 26.3 我们说过 R l o g i n客户进程必须使用保留端口号(见 1 . 9节)(通常 R l o g i n客户使用 5 1 2 ~ 1 0 2 3之间的保留端口)。这会给主机带来什么限制?有没有解决的办法? 26.4 阅读RFC 1097,它描述了Te l n e t的阈下报文( s u b l i m i n a l - m e s s a g e )选项。 第26章 Telnet和Rlogin:远程登录使用315 特 征 R l o g i n Te l n e t 运输协议 一个T C P连接。使用紧急方式 一个T C P连接。使用紧急方式。 分组方式 总是一次一字符,远程回显 通常的默认是一次一字符,远程 回显。带客户回显的准行方式也支 持带回显的实行模式。当服务器上 的应用进程请求时,总是一次一字 符的方式 流量控制 通常由客户完成,可以被服务器禁止 通常由服务器完成,选项允许客 户来完成 终端类型 总是提供 选项,通常被支持 终端速率 总是提供 选项 窗口大小 大多数服务器支持此选项 选项 环境变量 不支持 选项 自动登录 默认。提示用户键入口令,口令以明 默认是键入登录名和口令。口令 文发送。较新的版本支持K e r b e r o s方式 以明文发送。较新的版本支持鉴别选 的登录 项第27章 FTP:文件传送协议 27.1 引言 F T P是另一个常见的应用程序。它是用于文件传输的 I n t e r n e t标准。我们必须分清文件传 送(file transfer)和文件存取 (file access)之间的区别,前者是 F T P提供的,后者是如 N F S (S u n的网络文件系统,第 2 9章)等应用系统提供的。由 F T P提供的文件传送是将一个完整的 文件从一个系统复制到另一个系统中。要使用 F T P,就需要有登录服务器的注册帐号,或者通 过允许匿名F T P的服务器来使用(本章我们将给出这样的一个例子)。 与Te l n e t类似,F T P最早的设计是用于两台不同的主机,这两个主机可能运行在不同的操作系 统下、使用不同的文件结构、并可能使用不同字符集。但不同的是,Te l n e t获得异构性是强制两端 都采用同一个标准:使用7比特A S C I I码的N V T。而F T P是采用另一种方法来处理不同系统间的差 异。F T P支持有限数量的文件类型(A S C I I,二进制,等等)和文件结构(面向字节流或记录)。 参考文献959 [Postel 和 Reynolds 1985] 是F T P的正式规范。该文献叙述了近年来文件传输 的历史演变。 27.2 FTP协议 F T P与我们已描述的另一种应用不同,它采用两个 T C P连接来传输一个文件。 1) 控制连接以通常的客户服务器方式建立。服务器以被动方式打开众所周知的用于 F T P的端口(2 1),等待客户的连接。客户则以主动方式打开 T C P端口2 1,来建立连 接。控制连接始终等待客户与服务器之间的通信。该连接将命令从客户传给服务器, 并传回服务器的应答。 由于命令通常是由用户键入的,所以I P对控制连接的服务类型就是“最大限度地减小迟延”。 2) 每当一个文件在客户与服务器之间传输时,就创建一个数据连接。(其他时间也可以创 建,后面我们将说到)。 由于该连接用于传输目的,所以I P对数据连接的服务特点就是“最大限度提高吞吐量”。 图2 7 - 1描述了客户与服务器以及它们之间的连接情况 从图中可以看出,交互式用户通常不处理在控制连接中转换的命令和应答。这些细节均 由两个协议解释器来完成。标有“用户接口”的方框功能是按用户所需提供各种交互界面 (全屏幕菜单选择,逐行输入命令,等等),并把它们转换成在控制连接上发送的 F T P命令。 类似地,从控制连接上传回的服务器应答也被转换成用户所需的交互格式。 从图中还可以看出,正是这两个协议解释器根据需要激活文件传送功能。 27.2.1 数据表示 F T P协议规范提供了控制文件传送与存储的多种选择。在以下四个方面中每一个方面都必 须作出一个选择。第27章 FTP:文件传送协议使用317 图27-1 文件传输中的处理过程 1. 文件类型 (a) ASCII码文件类型 (默认选择)文本文件以NVT ASCII码形式在数据连接中传输。这要求 发方将本地文本文件转换成NVT ASCII码形式,而收方则将NVT ASCII码再还原成本地文本文件。 其中,用NVT ASCII码传输的每行都带有一个回车,而后是一个换行。这意味着收方必须扫描每 个字节,查找C R、L F对(我们在第1 5 . 2节见过的关于T F I P的A S C I I码文件传输情况与此相同)。 (b) EBCDIC文件类型 该文本文件传输方式要求两端都是 E B C D I C系统。 (c) 图像文件类型(也称为二进制文件类型) 数据发送呈现为一个连续的比特流。通常 用于传输二进制文件。 (d) 本地文件类型 该方式在具有不同字节大小的主机间传输二进制文件。每一字节的比特 数由发方规定。对使用8 bit字节的系统来说,本地文件以8 bit字节传输就等同于图像文件传输。 2. 格式控制 该选项只对A S C I I和E B C D I C文件类型有效。 (a) 非打印 (默认选择)文件中不含有垂直格式信息。 (b) 远程登录格式控制 文件含有向打印机解释的远程登录垂直格式控制。 (c) Fortran 回车控制 每行首字符是F o r t r a n格式控制符。 3. 结构 (a) 文件结构 (默认选择)文件被认为是一个连续的字节流。不存在内部的文件结构。 (b) 记录结构 该结构只用于文本文件(A S C I I或E B C D I C)。 (c) 页结构 每页都带有页号发送,以便收方能随机地存储各页。该结构由 TO P S - 2 0操 作系统提供(主机需求R F C不提倡采用该结构)。 4. 传输方式 它规定文件在数据连接中如何传输。 (a) 流方式 (默认选择)文件以字节流的形式传输。对于文件结构,发方在文件尾提 示关闭数据连接。对于记录结构,有专用的两字节序列码标志记录结束和文件结束。 (b) 块方式 文件以一系列块来传输,每块前面都带有一个或多个首部字节。 (c) 压缩方式 一个简单的全长编码压缩方法,压缩连续出现的相同字节。在文本文件 客户 用户接口 用户协议 解释器 用户数据传 输功能文件系统 数据连接 控制连接 服务器 服务器协 议接口 服务器数据传 输功能 文件系统 ( F T P命令) ( F T P应答) 在终端上 的用户318使用TCP/IP详解,卷1:协议 中常用来压缩空白串,在二进制文件中常用来压缩 0字节(这种方式很少使用,也不受支持。 现在有一些更好的文件压缩方法来支持 F T P)。 如果算一下所有这些选择的排列组合数,那么对传输和存储一个文件来说就有 7 2种不同 的方式。幸运的是,其中很多选择不是废弃了,就是不为多数实现环境所支持,所以我们可 以忽略掉它们。 通常由U n i x实现的FTP 客户和服务器把我们的选择限制如下: • 类型:A S C I I或图像。 • 格式控制:只允许非打印。 • 结构:只允许文件结构。 • 传输方式:只允许流方式。 这就限制我们只能取一、两种方式: A S C I I或图像(二进制)。 该实现满足主机需求 R F C的最小需求(该 R F C也要求能支持记录结构,但只有操作系统 支持它才行,而U n i x不行)。 很多非U n i x的实现提供了处理它们自己文件格式的 F T P功能。主机需求R F C指出“F T P协 议有很多特征,虽然其中一些通常不实现,但对 F T P中的每一个特征来说,都存在着至少一种 实现”。 27.2.2 FTP命令 命令和应答在客户和服务器的控制连接上以 NVT ASCII码形式传送。这就要求在每行结 尾都要返回C R、L F对(也就是每个命令或每个应答)。 从客户发向服务器的 Te l n e t命令(以I A C打头)只有中断进程( < I A C , I P >)和Te l n e t的同 步信号(紧急方式下 < I A C , D M >)。我们将看到这两条 Te l n e t命令被用来中止正在进行的文件 传输,或在传输过程中查询服务器。另外,如果服务器接受了客户端的一个带选项的 Te l n e t命 令(W I L L,W O N T,D O或D O N T),它将以DONT 或W O N T响应。 这些命令都是3或4个字节的大写A S C I I字符,其中一些带选项参数。从客户向服务器发送 的F T P命令超过3 0种。图2 7 - 2给出了一些常用命令,其中大部分将在本章再次遇到。 图27-2 常用的FTP命令 下节我们将通过一些例子看到,在用户交互类型和控制连接上传送的 F T P命令之间有时是 一对一的。但也有些操作下,一个用户命令产生控制连接上多个 F T P命令。 命 令 说 明 A B O R 放弃先前的F T P命令和数据传输 LIST f i l e l i s t 列表显示文件或目录 PASS p a s s w o rd 服务器上的口令 P O RT n1 ,n2 ,n3 ,n4 ,n5 ,n6 客户端I P地址(n1 .n2 .n3 .n4)和端口(n5×2 5 6 +n6) Q U I T 从服务器注销 RETR f i l e n a m e 检索(取)一个文件 S TOR f i l e n a m e 存储(放)一个文件 S Y S T 服务器返回系统类型 TYPE t y p e 说明文件类型:A表示A S C I I码,I表示图像 USER u s e r n a m e 服务器上用户名27.2.3 FTP应答 应答都是A S C I I码形式的3位数字,并跟有报文选项。其原因是软件系统需要根据数字代码来 决定如何应答,而选项串是面向人工处理的。由于客户通常都要输出数字应答和报文串,一个可 交互的用户可以通过阅读报文串(而不必记忆所有数字回答代码的含义)来确定应答的含义。 应答3位码中每一位数字都有不同的含义(我们将在第 2 8章看到简单邮件传送输协议, S M T P,使用相同的命令和应答约定)。 图2 7 - 3给出了应答代码第1位和第2位的含义。 图27-3 应答代码3位数字中第1位和第2位的含义 第3位数字给出差错报文的附加含义。例如,这里是一些典型的应答,都带有一个可能的 报文串。 • 125 数据连接已经打开;传输开始。 • 200 就绪命令。 • 214 帮助报文(面向用户)。 • 331 用户名就绪,要求输入口令。 • 425 不能打开数据连接。 • 452 错写文件。 • 500 语法错误(未认可的命令)。 • 501 语法错误(无效参数)。 • 502 未实现的M O D E (方式命令)类型。 通常每个F T P命令都产生一行回答。例如, Q U I T命令可以产生如下应答: 221 Goodbye. 如果需要产生一条多行应答,第1行在3位数字应答代码之后包含一个连字号,而不是空格, 最后一行包含相同的3位数字应答代码,后跟一个空格符。例如,HELP命令可以产生如下应答: 第27章 FTP:文件传送协议使用319 应答 说 明 1 y z 肯定预备应答。它仅仅是在发送另一个命令前期待另一个应答时启动 2 y z 肯定完成应答。一个新命令可以发送 3 y z 肯定中介应答。该命令已被接受,但另一个命令必须被发送 4 y z 暂态否定完成应答。请求的动作没有发生,但差错状态是暂时的,所以 命令可以过后再发 5 y z 永久性否定完成应答。命令不被接受,并且不再重试 x 0 z 语法错误 x 1 z 信息 x 2 z 连接。应答指控制或数据连接 x 3 z 鉴别和记帐。应答用于注册或记帐命令 x 4 z 未指明 x 5 z 文件系统状态320使用TCP/IP详解,卷1:协议 27.2.4 连接管理 数据连接有以下三大用途: 1) 从客户向服务器发送一个文件。 2) 从服务器向客户发送一个文件。 3) 从服务器向客户发送文件或目录列表。 F T P服务器把文件列表从数据连接上发回,而不是控制连接上的多行应答。这就避免了行 的有限性对目录大小的限制,而且更易于客户将目录列表以文件形式保存,而不是把列表显 示在终端上。 我们已说过,控制连接一直保持到客户-服务器连接的全过程,但数据连接可以根据需要 随时来,随时走。那么需要怎样为数据连接选端口号,以及谁来负责主动打开和被动打开? 首先,我们前面说过通用传输方式( U n i x环境下唯一的传输方式)是流方式,并且文件 结尾是以关闭数据连接为标志。这意味着对每一个文件传输或目录列表来说都要建立一个全 新的数据连接。其一般过程如下: 1) 正由于是客户发出命令要求建立数据连接,所以数据连接是在客户的控制下建立的。 2) 客户通常在客户端主机上为所在数据连接端选择一个临时端口号。客户从该端口发布 一个被动的打开。 3) 客户使用P O RT命令从控制连接上把端口号发向服务器。 4) 服务器在控制连接上接收端口号,并向客户端主机上的端口发布一个主动的打开。服 务器的数据连接端一直使用端口 2 0。 图2 7 - 4给出了第3步执行时的连接状态。假设客户用于控制连接的临时端口是 11 7 3,客户 用于数据连接的临时端口是 11 7 4。客户发出的命令是P O RT命令,其参数是6个A S C I I中的十进 制数字,它们之间由逗点隔开。前面 4个数字指明客户上的 I P地址,服务器将向它发出主动打 开(本例中是1 4 0 . 2 5 2 . 1 3 . 3 4),而后两位指明16 bit端口地址。由于16 bit端口地址是从这两个 数字中得来,所以其值在本例中就是 4×256+150 = 11 7 4。 图2 7 - 5给出了服务器向客户所在数据连接端发布主动打开时的连接状态。服务器的端点 是端口2 0。 图27-4 在FTP控制连接上通过的PORT命令 图27-5 主动打开数据连接的FTP服务器 FTP客户 端口1173 端口1174 (被动打开) 端口21 FTP服务器 FTP服务器 端口21 端口20 (主动打开) IP地址 控制连接 控制连接 SYN到140.252.13.34, 端口1174 IP地址140.252.13.34 (被动打开) FTP客户 端口1173 端口1174服务器总是执行数据连接的主动打开。通常服务器也执行数据连接的主动关闭,除非当 客户向服务器发送流形式的文件时,需要客户来关闭连接(它给服务器一个文件结束的通 知)。 客户也有可能不发出P O RT命令,而由服务器向正被客户使用的同一个端口号发出主动打 开,来结束控制连接。这是可行的,因为服务器面向这两个连接的端口号是不同的:一个是 2 0,另一个是2 1。不过,下节我们将看到为什么现有实现通常不这样做。 27.3 FTP的例子 现在看一些使用F T P的例子:它对数据连接的管理,采用 NVT ASCII码的文本文件如何发 送,F T P使用Te l n e t同步信号来中止进行中的文件传输,最后是常用的“匿名 F T P”。 27.3.1 连接管理:临时数据端口 先看一下F T P的连接管理,它只在服务器上用简单 F T P会话显示一个文件。我们用- d标志 (d e b u g)来运行s v r 4主机上的客户。这告诉它要打印控制连接上变换的命令和应答。所有前 面冠以- - - >的行是从客户上发向服务器的,所有以 3位数字开头的行都是服务器的应答。客户 的交互提示是f t p >。 svr4 % ftp -d bsdi -d 选项用作排错输出 Connected to bsdi. 客户执行控制连接的主动打开 220 bsdi FTP server (Version 5.60) ready 服务器响应就绪 Name (bsdi:rstevens): 客户提示我们输入 ---> USER rstevens 键入R E T U R N,客户发送默认信息 331 Password required for rstevens. P a s s w o r d : 键入口令;它不需要回显 ---> PASS XXXXXXXX 客户以明文发送它 230 User rstevens logged in. ftp> dir hello.c 要求列出一个文件的目录 ---> PORT 140,252,13,34,4,150 见图2 7 - 4 200 PORT Command successful. ---> LIST hello.c 150 Opening ASCII mode data connection for /bin/ls. -rw-r--r-- 1 rstevens staff 38 Jul 17 12:47 hello.c 226 Transfer complete. remote: hello.c 客户输出 56 bytes received in 0.03 seconds (1.8 Kbytes/s) ftp> q u i t 我们已完成 ---> QUIT 221 Goodbye 当F T P客户提示我们注册姓名时,它打印了默认值(我们在客户上的注册名)。当我们敲 R E T U R N键时,默认值被发送出去。 对一个文件列出目录的要求引发一个数据连接的建立和使用。本例体现了我们在图 2 7 - 4 和图2 7 - 5中给出的程序。客户要求 T C P为其数据连接的终端提供一个临时端口号,并用 P O RT 命令发送这个端口号( 11 7 4)给服务器。我们也看到一个交互用户命令( d i r)成为两个F T P 命令(P O RT和L I S T)。 第27章 FTP:文件传送协议使用321图2 7 - 6是控制连接上分组交换的时间系列(已除去了控制连接的建立和结束,以及所有 窗口大小的通知)。我们关注该图中数据连接在哪儿被打开、使用和过后的关闭。 图2 7 - 7是数据连接的时间系列。图中的起始时间与图 2 7 - 6中的相同。已除去了所有窗口大 小通知,但留下服务类型字段,以说明数据连接使用另一个服务类型(最大吞吐量),而不同 于控制连接(最小时延)(服务类型( TO S )值在图3 - 2中)。 在时间系列上,F T P服务器执行数据连接的主动打开,从端口 2 0(称为f t p - d a t a)到来 自P O RT命令的端口号( 11 7 4)。本例中还可以看到服务器在哪儿向数据连接上执行写操作, 服务器对数据连接执行主动的关闭,这就告诉客户列表已完成。 图27-6 FTP控制连接示例 322使用TCP/IP详解,卷1:协议 使用数据连接,然后关闭 打开数据连接 键入 键入 键入 键入口令图27-7 FTP数据连接示例 27.3.2 连接管理:默认数据端口 如果客户没有向服务器发出 P O RT命令,来指明客户数据连接端的端口号,服务器就用与 控制连接正在用的相同的端口号给数据连接。这会给使用流方式( Unix FTP客户和服务器一 直使用)的客户带来一些问题。正如下面所示: Host Requirements RFC建议使用流方式的F T P客户在每次使用数据连接前发一个 PORT命令来启用一个非默认的端口号。 回到先前的例子(图 2 7 - 6),如果我们要求在列出第 1个目录后几秒钟再列出另一个目录, 那该怎么办?客户将要求其内核选择另一个临时端口号(可能是 11 7 5),下一个数据连接将建 立在s v r 4端口11 7 5和b s d i端口2 0之间。但在图2 7 - 7中服务器执行数据连接的主动打开,我们在 1 8 . 6节说明了服务器将不把端口 2 0分配给新的数据连接,这是因为本地端口号已被更早的连 接使用,而且还处于2 M S L等待状态。 服务器通过指明我们在1 8 . 6节中提到的S O _ R E U S E A D D R选项,来解决这个问题。这让它 把端口2 0分配给新连接,而新连接将从处于 2 M S L等待状态的端口(11 7 4)处得到一个不一样 的外部端口号(11 7 5),这样一切都解决了。 如果客户不发送P O RT命令,而在客户上指明一个临时端口号,那么情况将改变。我们可 以通过执行用户命令s e n d p o r t给F T P来使之发生。Unix FTP客户用这个命令在每个数据连接使 用之前关闭向服务器发送P O RT命令。 图2 7 - 8给出了用于两个连续L I S T命令的数据连接时间系列。控制连接起自主机 s v r 4上的端 口11 7 6,所以在没有P O RT命令的情况下,客户和服务器给数据连接使用相同的端口号(除去 了窗口通知和服务类型值)。 事件序列如下: 1) 控制连接是建立在客户端口 11 7 6到服务器端口2 1上的(这里我们不展示)。 第27章 FTP:文件传送协议使用323 主动打开 主动关闭图27-8 两个连续LIST命令的数据连接 2) 当客户为端口11 7 6上的数据连接做被动打开时,由于该端口已被客户上的控制连接使 用,所以必须确定S O _ R E U S E A D D R选项。 3) 服务器给端口2 0到端口11 7 6的数据连接(报文段1)做主动打开。即便端口 11 7 6已在客 户上被使用,客户仍会接受它(报文段 2),这是因为下面这一对插口是不同的: (在b s d i上的端口号是不同的)。T C P通过查看源I P地址、源端口号、目的 I P地址、目 的端口号分用各呼入报文段,只要这 4个元素中的一个不同,就行。 4) 服务器对数据连接(报文段 5)做主动的关闭,即把这对插口置入服务器上的一个 2 M S L等待。 5) 客户在控制连接上发送另一个 L I S T命令(这里我们不展示)。在此之前,客户在端口 11 7 6上为其数据连接端做一个被动打开。客户必须再一次指明 S O _ R E U S E A D D R,这是 因为端口号11 7 6已在使用。 324使用TCP/IP详解,卷1:协议 (第1个LIST命令的输出) 主动打开 主动关闭 主动打开 主动关闭 (所有要打开从bsdi.ftp-data到svr4.1176的TCP 连接的尝试在这里都失败了) (第2个LIST命令的输出)6) 服务器给从端口2 0到端口11 7 6的数据连接发出一个主动打开。在此之前,服务器必须指 明S O _ R E U S E A D D R,这是因为本地端口(2 0)与处于2 M S L等待状态的连接是相关联的, 但从1 8 . 6节所示可知,该连接将不成功。其原由是这个连接用插口对 (socket pair)与步骤 4中的仍处于2 M S L等待状态的插口对相同。T C P规定禁止服务器发送同步信息(S Y N)。 这样就没办法让服务器跨过插口对的2 M S L等待状态来重用相同的插口对。 在这一步伯克利软件分发(B S D)服务器每隔5秒就重试一次连接请求,直到满1 8次,总共 9 0秒。我们看到报文段9将在大约1分钟后成功(我们在第1 8章提到过,S V R 4使用一个3 0秒 的M S L,以两个M S L来达到持续1分钟的等待)。我们没看到在这个时间系列上的这些失败 有任何同步(S Y N)信息,这是因为主动打开失败,服务器的T C P不再发送一个S Y N。 Host Requirements RFC建议使用P O RT命令的原因是在两个相继使用数据连接之间避免出 现这个2 M S L。通过不停地改变某一端的端口号,我们所说的这个问题就不会出现。 27.3.3 文本文件传输:NVT ASCII表示还是图像表示 让我们查证一下默认的文本文件传输使用 NVT ASCII码。这次不指定- d标志,所以不看 客户命令,但注意到客户还将打印服务器的响应: sun % ftp bsdi Connected to bsdi. 220 bsdi FTP server (Version 5.60) ready. Name (bsdi:retevens); 键入R E T U R N 331 Password required for rstevens. Passord : 键入口令 230 User rstevens logged in. ftp> get hello.c 取一个文件 200 PORT command successful. 150 Opening ASCII mode data connection for hello.c (38 bytes). 226 Transfer complete. 服务器说明文件含有3 8字节 local: hello.c remote: hello.c 由客户输出 42 bytes received in 0.0037 seconds (11 Kbytes/s) 42字节传过数据连接 f t p > q u i t 221 Goodbye. Sun % ls -l hello.c -rw-rw-r-- 1 rstevens 38 Jul 18 08:48 hello.c 但文件还含有3 8字节 sun % wc -l hello.c 在文件中记行数 4 hello.c 因为文件有4行,所以从数据连接上传输 4 2个字节。U n i x下的每一新行符(\ n)被服务器 转换成NVT ASCII码的2字节行结尾序列( \ r \ n)来传输,然后再由客户转换成原先形式来 存储。 新客户试图确定服务器是否是相同类型的系统,一旦相同,就可以用二进制码(图像文 件类型)来传输文件,而不是 A S C I I码。这可以获得两个方面的好处: 1) 发方和收方不必查看每一字节(很大的节约)。 2 ) 如果主机操作系统使用比 2字节的NVT ASCII码序列更少的字节来作行尾,就会传输更 少的字节数(很小的节约)。 我们可以看到使用一个 B S D / 3 8 6客户和服务器的最优效果。启动排错( d e b u g)方式来看 第27章 FTP:文件传送协议使用325客户F T P命令: bsdi & ftp -d slip 指明 - d来看客户命令 Connected to slip. 220 slip FTP server (Version 5.60) ready. Name (slip:rstevens): 我们键入R E T U R N ---> USER rstevns 331 Password required for rstevens. Password : 我们键入自己的口令 ---> PASS XXXX 230 User rstevns logged in . ---> SYST 这由客户服务器的应答自动发送 215 UNIX Type: L8 Version : BSD-199103 Remote system type is UNIX. 由客户发出的信息 Using binary mode to transfer files. 由客户发出的信息 ftp> get hello.c 取一个文件 ---> TYPE I 由客户自动发送 200 Type set to I. ---> PORT 140,252,13,66,4,84 端口号= 4×2 5 6 + 8 4 = 1 1 0 8 200 PORT command successful. ---> RETR hello.c 150 Opening BINARY mode data connection for hello.c (38 bytes) . 226 Transefer complete . 38 bytes received in 0.035 seconds (1.1 Kbytes/s) 这时只有3 8个字节 ftp> q u i t ---> QUIT 221 Goodbye. 注册到服务器后,客户 F T P自动发出S Y S T命令,服务器将用自己的系统类型来响应。如 果应答起自字符串“215 UNIX Type : L8”,并且如果客户在每字节为 8 bit的U n i x系统上运行, 那么二进制方式(图像)将被所有文件传输所使用,除非被用户改变。 当我们取文件h e l l o . c时,客户自动发出命令 TYPE I把文件类型定成图像。这样在数据连 接上只有3 8字节被传输。 Host Requirements RFC指出一个FTP服务器必须支持SYST命令(这曾是RFC 959中 的一个选项)。但支持它的使用文本的系统(见封 2)仅仅是B S D / 3 8 6和AIX 3.2.2。 SunOS 4.1.3和Solaris 2.x 用500(不能理解的命令)来应答。SVR4采用极不大众化的应 答行为500,并关闭控制连接! 27.3.4 异常中止一个文件的传输:Telnet 同步信号 现在看一下F T P客户是怎样异常中止一个来自服务器的文件传输。异常中止从客户传向服 务器的文件很容易— 只要客户停止在数据连接上发送数据,并发出 A B O R命令到控制连接 上的服务器即可。而异常中止接收就复杂多了,这是因为客户要告知服务器立即停止发送数 据。我们前面提到要使用Te l n e t同步信号,下面的例子就是这样。 我们先发起一个接收,并在它开始后键入中断键。这里是交互会话,其中初始注册被略 去: 326使用TCP/IP详解,卷1:协议ftp> get a.out 取一个大文件 ---> TYPE I 客户和服务器都是8 bit字节的U n i x系统 200 Type set to I. ---> PORT 140,252,13,66,4,99 200 PORT command successful. ---> RETR a.out 150 Opening BINARY mode data connection for a.out (28672 bytes). ^ ? 键入的中断键 receive aborted 由客户输出 waiting for remote to finish abort 由客户输出 426 Transfer aborted. Data connection closed. 226 Abort successful 1536 bytes received in 1.7 seconds (0.89 Kbytes/s) 在我们键入中断键之后,客户立即告知我们它将发起异常中止,并正在等待服务器完成。 服务器发出两个应答: 4 2 6和2 2 6。这两个应答都是由Unix 服务器在收到来自客户的紧急数据 和A B O R命令时发出的。 图2 7 - 9和图2 7 - 1 0展示了会话时间系列。我们已把控制连接(实线)和数据连接(虚线) 合在一起来说明它们之间的关系。 图27-9 异常中止一个文件的传输(前半部) 图2 7 - 9的前面1 2个报文段是我们所期望的。通过控制连接的命令和应答建立起文件传输, 数据连接被打开,第1个报文段的数据从服务器发往客户。 第27章 FTP:文件传送协议使用327 打开数 据连接 开始传 送数据 第1个数据段图27-10 异常中止一个文件的传输(后半部) 在图2 7 - 1 0中,报文段1 3是数据连接上来自服务器的第 6个数据报文段,后跟由我们键入 的中断键产生的报文段1 4。客户发出1 0个字节来异常中止传输: < I A C , I P , I A C , D M , A , B , O , R , \ r , \ n > 由于2 0 . 8节中详细讨论过这个问题,我们看到有两个报文段( 1 4和1 5)涉及到T C P的紧急 指针(我们在图2 6 - 1 7中看过对Te l n e t问题也做相同的处理)。Host Requirements RFC指出紧急 指针应指向紧急数据的最后一个字节,而多数伯克利的派生实现使之指向紧急数据最后一个 字节后面的第一个字节。了解到紧急指针将(错误地)指向下一个要写的字节(数据标志, D M。在序号为5 4处),F T P客户进程特意写前 3个字节作为紧急数据。首先写下的 3字节紧急 数据与紧急指针一起被立即发送,紧接着是后面 7个字节(BSD FTP 服务器不会出现由客户 使用的紧急指针的解释问题。当服务器收到控制连接上的紧急数据时,它读下一个 F T P命令, 寻找A B O R或S TAT,忽略嵌入的Te l n e t命令)。 注意到尽管服务器指出传输被异常中止(报文段 1 8,在控制连接上),客户进程还要在数 据连接上再接收1 4个报文段的数据(序列号是 1 5 3 7 ~ 5 1 2 0)。这些报文段可能在收到异常中止 328使用TCP/IP详解,卷1:协议 键入中断 数据传送 继续 关闭数据 连接时,还在服务器上的网络设备驱动器中排队,但客户打印“收到 1 5 3 6字节”,意思是在发出异 常中止后(报文段1 4和1 5),略去收到的所有数据报文段。 一旦Te l n e t用户键入中断键,我们在图 2 6 - 1 7中看到U n i x客户在默认情况下不发出中断进 程命令作为紧急数据。因为几乎没有机会用流控制来中止从客户进程到服务器进程的数据流, 所以我们说这样就行了。F T P的客户进程也通过控制连接发送一个中断进程命令,因为两个连 接正在被使用,因此没有机会用流控制来中止控制连接。为什么 F T P发送中断进程命令作为紧 急数据而Te l n e t不呢?答案在于 F T P使用两个连接,而 Te l n e t只使用一个,在某些操作系统上 要求一个进程同时监控两个连接的输入是困难的。 F T P假设这些临界的操作系统至少提供紧急 数据在控制连接上已到达的通知,而后让服务器从处理数据连接切换到控制连接上来。 27.3.5 匿名FTP F T P的一种形式很常用,我们下面给出它的例子。它被称为匿名 F T P,当有服务器支持时, 允许任何人注册并使用F T P来传输文件。使用这个技术可以提供大量的自由信息。 怎样找出你正在搜寻的站点是一个完全不同的问题。我们将在 3 0 . 4节简要介绍。 我们将把匿名F T P用在站点f t p . u u . n e t上(一个常用的匿名F T P站点)来取本书的勘误 表文件。要使用匿名F T P,须使用“a n o n y m o u s”(复习数遍就能正确地拼写)用户名来注册。 当提示输入口令时,我们键入自己的电子邮箱地址。 sun % ftp ftp.uu.net Connected to ftp.uu.net 220 ftp.UU.NET FTP server (Version 2.0WU(13) Fri Apr 9 20:44:32 EDT 1993) ready Name (ftp.uu.net:rstevens): a n o n y m o u s 331 Guest login ok, send your complete e-mail addraess as password. Password : 键入r s t e v e n s @ n o a o . e d u;它没有回显 2 3 0 - 230- Welcome to the UUNET archive. 230- A service of UUNET Technologies Inc, Falls Church, Virginia 230- For information about UUNET, call +1 703 204 8000, or see the files 230- in /uunet-info 还有一些问候行 230 Guest login ok, access restrictions apply. ftp> cd published/books 换成需要的目录 250 CWD command successful. ftp> b i n a r y 我们将传送一个二进制文件 200 Type set to I. ftp> get stevens.tcpipivl.errata.Z 取文件 200 PORT command successful. 150 Opening BINARY mode data connection for stevens.tcpipivl.errata.Z (150 bytes). 226 Transfer complete. (你可能得到一个不同的文件大小 ) local: stevens.tcpipivl.errata.Z remote: stevens.tcpipivl.errata.Z 105 bytes received in 4.1 seconds (0.83 Kbytes/s) ftp> q u i t 221 Goodbye. sun % uncompress stevens.tcpipivl.errata.Z sun % more stevens.tcpipivl.errata 第27章 FTP:文件传送协议使用329不压缩是因为很多现行匿名 F T P文件是用Unix compress( 1 )程序压缩的,这样导致文 件带有. Z的扩展名。这些文件必须使用二进制文件类型来传输,而不是 A S C I I码文件类型。 27.3.6 来自一个未知IP地址的匿名FTP 可以把一些使用匿名F T P的域名系统(D N S)特征和选路特征结合在一起。在 1 4 . 5节中我 们谈到D N S中指针查询现象— 取一个I P地址并返回其主机名。不幸的是并非所有系统管理 员都能正确地创立涉及指针查询的名服务器。他们经常记得把新主机加入名字到地址匹配的 文件中,却忘了把他们加入到地址到名字匹配的文件中。对此,可用 t r a c e r o u t e经常看到 这种现象,即它打印一个I P地址,而不是主机名。 有些匿名F T P服务器要求客户有一个有效域名。这就允许服务器来记录正在执行传输的主 机域名。由于服务器在来自客户 I P数据报中收到的关于客户的唯一标识是客户的 I P地址,所 以服务器能叫 D N S来做指针查询,并获得客户的域名。如果负责客户主机的名服务器没有正 确地创立,指针查询将失败。 要看清这个错误,我们来做以下诸步骤: 1) 把主机s l i p(见封2的图)的I P地址换成1 4 0 . 2 5 2 . 1 3 . 6 7。这是给作者子网的一个有效 I P地址,但没有涉及到n o a o . e d u域的域名服务器。 2) 把在b s d i上S L I P连接的目的I P地址换成1 4 0 . 2 5 2 . 1 3 . 6 7。 3) 把将数据报引向1 4 0 . 2 5 2 . 1 3 . 6 7的s u n上的路由表入口加入路由器 b s d i(回忆一下我们 在9 . 2节中关于这个选路表的讨论)。 从I n t e r n e t上仍然可以访问我们的主机 s l i p,这是因为在 1 0 . 4节中路由器 g a t e w a y和 n e t b正好把所有目的是子网 1 4 0 . 2 5 2 . 1 3的所有数据报都发送给路由器 s u n。路由器s u n知道 利用我们在上述第 3步建立的路由表入口来如何处理这些数据报。我们所创建的是拥有完整 I n t e r n e t连接性的主机,但没有有效的域名。结果,指针查询 I P地址1 4 0 . 2 5 2 . 1 3 . 6 7将失败。 现在给一个我们所知的服务器使用匿名 F T P,需要一个有效的域名: 来自服务器的出错应答是无需加以说明的。 330使用TCP/IP详解,卷1:协议27.4 小结 F T P是文件传输的 I n t e r n e t标准。与多数其他 T C P应用不同,它在客户进程和服务器进程 之间使用两个 T C P连接— 一个控制连接,它一直持续到客户进程与服务器进程之间的会话 完成为止;另一个按需可以随时创建和撤消的数据连接。 F T P使用的关于数据连接的连接管理让我们更详细地了解 T C P连接管理需求。我们看到 T C P在不发出P O RT命令的客户进程上对2 M S L等待状态的作用。 F T P使用NVT ASCII码做跨越控制连接的所有远程登录命令和应答。数据传输的默认方式 通常也是NVT ASCII码。我们看到较新的U n i x客户进程会自动发送命令来查看服务器是否是 8 b i t字节的U n i x主机,并且如果是,那么就使用二进制方式来传输所有文件,那将带来更高的 效率。 我们也展示了匿名F T P的一个例子,它是在I n t e r n e t上分发软件的常用形式。 习题 27.1 图2 7 - 8中,如果客户对第 2个数据连接做一次主动打开,而不是由服务器来做,那将发 生什么变化? 27.2 在本章F T P客户例子中,我们加入诸如由客户输出行的行注释。如果不看源代码,我们 如何确定这些不是来自服务器? local: hello.c remote: hello.c 42 bytes received in 0.0037 seconds (11 Kbytes/s) 第27章 FTP:文件传送协议使用331第28章 SMTP: 简单邮件传送协议 28.1 引言 电子邮件(e - m a i l)无疑是最流行的应用程序。 [Caceres et al.1991]说明,所有T C P连接中 大约一半是用于简单邮件传送协议 SMTP (Simple Mail Transfer Protocol)的(以比特计算为基 础,F T P连接传送更多的数据)。[Paxson 1993] 发现,平均每个邮件中包含大约 1 5 0 0字节的数 据,但有的邮件中包含兆比特的数据,因为有时电子邮件也用于发送文件。 图2 8 - 1显示了一个用T C P / I P交换电子邮件的示意图。 图28-1 Internet电子邮件示意图 用户与用户代理( user agent)打交道,可能会有多个用户代理可供选择。常用的 U n i x上 的用户代理包括M H,Berkeley Mail, Elm和M u s h。 用T C P进行的邮件交换是由报文传送代理 M TA(Message Transfer Agent)完成的。最普 通的U n i x系统中的M TA是S e n d m a i l。用户通常不和M TA打交道,由系统管理员负责设置本地 的M TA。通常,用户可以选择它们自己的用户代理。 本章研究在两个M TA之间如何用T C P交换邮件。我们不考虑用户代理的运行或实现。 RFC 821 [Postel 1982] 规范了S M T P协议,指定了在一个简单T C P连接上,两个M TA如何进行 通信。RFC 822 [Crocker 1982] 指定了在两个M TA之间用RFC 821 发送的电子邮件报文的格式。 28.2 SMTP协议 两个M TA之间用NVT ASCII进行通信。客户向服务器发出命令,服务器用数字应答码和 可选的人可读字符串进行响应。这与上一章的 F T P类似。 客户只能向服务器发送很少的命令:不到 1 2个(相比较而言, F T P超过4 0个)。我们用简 单的例子说明发送邮件的工作过程,并不仔细描述每个命令。 28.2.1 简单例子 我们将发送一个只有一行的简单邮件,并观察 S M T P连接。我们用 -v 标志调用用户代理, 在终端上 的用户 用户代理 要发送邮件 的队列 报文传送 代理 客户 TCP连接 TCP端口25 服务器报文传送 代理用户邮箱用户代理在终端上 的用户 接收方 发送方它被传送给邮件传送代理(本例中是 S e n d m a i l)。当设置该标志时,该 M TA显示在S M T P连接 上发送和接收的内容。以 > > >开始的行是S M T P客户发出的命令,以 3位数字的应答码开始的 行是从S M T P服务器来的。以下就是交互会话: 只有5个S M T P命令用于发送邮件:H E L O,M A I L,R C T P,D ATA和Q U I T。 我们键入m a i l启动用户代理,然后键入主题( s u b j e c t)的提示;键入后,再键入报文的 正文。在一行上键入一个句点结束报文,用户代理把邮件传给 M TA,由M TA进行交付。 客户主动打开T C P端口2 5。返回时,客户等待从服务器来的问候报文(应答代码为 2 2 0)。 该服务器的应答必须以服务器的完全合格的域名开始:本例中为 n o a o . e d u(通常,跟在数 字应答后面的文字是可选的。这里需要域名。以 S e n d m a i l打头的文字是可选的)。 下一步客户用 H E L O命令标识自己。参数必须是完全合格的的客户主机名: s u n . t u c . n o a o . e d u。 M A I L命令标识出报文的发起人。下一个命令, R C P T,标识接收方。如果有多个接收方, 可以发多个R C P T命令。 邮件报文的内容由客户通过 D ATA命令发送。报文的末尾由客户指定,是只有一个句点的 一行。最后的命令Q U I T,结束邮件的交换。 图2 8 - 2是在发送方S M T P(客户端)与接收方S M T P(服务器)之间的一个S M T P连接。 我们键入到用户代理的数据是一行报文(“1,2,3”),但在报文段1 2中共发送了3 9 3字节 的数据。下面的1 2行组成了客户发送的3 9 3字节数据: 第28章 SMTP:简单邮件传送协议使用333 调用我们的代理 这是用户代理的输出 然后指示我们键入主题 用户代理在首部和正文之间加上一行空行 这是我们键入的正文 我们在一行上输入一个句点,说明完成了 用户代理上详细的输出 以下是MTA(Sendmail)的输出 这是用户代理的输出前三行,Received: 和M e s s a g e - I d: 由M TA加上;下一行由用户代理生成。 图28-2 基本SMTP邮件交付 28.2.2 SMTP命令 最小S M T P实现支持 8种命令。我们在前面的例子中遇到 5个:H E L O,M A I L,R C P T, D ATA和Q U I T。 R S E T命令异常中止当前的邮件事务并使两端复位。丢掉所有有关发送方、接收方或邮件 的存储信息。 334使用TCP/IP详解,卷1:协议V R F Y命令使客户能够询问发送方以验证接收方地址,而无需向接收方发送邮件。通常是 系统管理员在查找邮件交付差错时手工使用的。我们将在下一节中给出这方面的例子。 N O O P命令除了强迫服务器响应一个 O K应答码(2 0 0)外,不做任何事情。 还有附加和可选命令。 E X P N扩充邮件表,与 V R F Y类似,通常是由系统管理员使用的。 事实上,许多S e n d m a i l的版本都把这两者等价地处理。 4.4BSD 中的S e n d m a i l版本8不再将两者等同处理。 V R F Y不扩充别名也不接 受.forward文件。 T U R N命令使客户和服务器交换角色,无需拆除 T C P连接并建立新的连接就能以相反方向 发送邮件(S e n d m a i l不支持这个命令)。其他还有三个很少被实现的命令( S E N D、S O M L和 S A M L)取代M A I L命令。这三个命令允许邮件直接发送到客户终端(如果已注册)或发送到 接收方的邮箱。 28.2.3 信封、首部和正文 电子邮件由三部分组成: 1) 信封(e n v e l o p e)是M TA用来交付的。在我们的例子中信封由两个 S M T P命令指明: MAIL From: RCPT To: RFC 821指明了信封的内容及其解释,以及在一个 T C P连接上用于交换邮件的协议。 2) 首部由用户代理使用。在我们的例子中可以看到 9个首部字段: R e c e i v e d、 M e s s a g e - I d、F r o m、D a t a、R e p l y - T o、X - P h o n e、X - M a i l e r、T o和S u b j e c t。每个 首部字段都包含一个名,紧跟一个冒号,接着是字段值。 RFC 822指明了首部字段的格式的解 释(以X-开始的首部字段是用户定义的字段,其他是由 RFC 822定义的)。长首部字段,如例 子中的R e c e i v e d,被折在几行中,多余行以空格开头。 3) 正文(b o d y)是发送用户发给接收用户报文的内容。 RFC 822 指定正文为NVT ASCII 文字行。当用D ATA命令发送时,先发送首部,紧跟一个空行,然后是正文。用 D ATA命令发 送的各行都必须小于1 0 0 0字节。 用户接收我们指定为正文的部分,加上一些首部字段,并把结果传到 M TA。M TA加上一 些首部字段,加上信封,并把结果发送到另一个 M TA。 内容(c o n t e n t)通常用于描述首部和正文的结合。内容是客户用 D ATA命令发送的。 28.2.4 中继代理 在我们的例子中本地M TA的信息输出的第1行是:“Connecting to mailhost via ether”(即 “通过以太网连接到邮件主机”)。这是因为作者的系统已被配置成把所有非本地的向外的邮件 发送到一台中继机上进行转发。 这样做的原因有两个。首先,简化了除中继系统 M TA外的其他所有M TA的配置(所有曾 使用过S e n d m a i l的人都能证明,配置一个 M TA并不简单)。第二,它允许某个机构中的一个系 统作为邮件集线器,从而可能把其他所有系统隐藏起来。 在这个例子中,中继系统在本地域( . t u c . n o a o . e d u)中有一个m a i l h o s t的主机名,而其他 所有系统都被配置成把它们的邮件发往该主机。我们可以执行 h o s t命令来看看在D N S中这个名 第28章 SMTP:简单邮件传送协议使用335是如何定义的: sun % host mailhost mailhost.tuc.noao.edu CNAME noao.edu 规范名 noao.edu A 140.252.1.54 它的真实I P地址 如果将来用于中继的主机改变了,只需改变它的 D N S名— 其他所有单个系统的邮箱配 置都无需改变。 目前许多机构都采用中继系统。图 2 8 - 3是修改后的I n t e r n e t邮件图(图2 8 - 2),考虑发送主 机和最后的接收主机都可能使用中继主机。 图28-3 在两端都有一个中继系统的Internet电子邮件 在这种情况下,在发送方和接收方之间有 4个M TA。发送方主机上的本地 M TA只把邮件 交给它自己的中继 M TA(该中继M TA可能在该机构的域中有一个 m a i l h o s t的主机名)。这个通 信就在该机构的本地互联网上用 S M T P。然后,发送方机构的中继 M TA就在I n t e r n e t上把邮件 发送到接收方机构的中继 M TA上,而这个中继 M TA就通过与接收方主机上的本地 M TA通信, 把邮件交给接收方主机。尽管可能存在其他协议,但这个例子中所有 M TA均使用S M T P协议。 336使用TCP/IP详解,卷1:协议 发送主机 在终端上 的用户 用户代理 要发送邮 件的队列 本地MTA 本地MTA 本地MTA 一个机构 中继MTA 在Internet上 中继MTA 本地MTA 本地MTA 一个机构 用户邮箱用户代理 接收主机 在终端上 的用户 本地MTA 邮件队列 邮件队列28.2.5 NVT ASCII S M T P的一个特色是它用NVT ASCII表示一切:信封、首部和正文。正如我们在 2 6 . 4节中 谈到的,这是一个7 bit的字符码,以8 bit字节发送,高位比特被置为 0。 在2 8 . 4节中,我们讨论了 I n t e r n e t邮件的一些新特性、允许发送和接收诸如音频和视频数 据的扩充S M T P和多媒体邮件(M I M E)。我们将看到,M I M E和NVT ASCII一起表示信封、首 部和正文,只需对用户代理作一些改变。 28.2.6 重试间隔 当用户把一个新的邮件报文传给它的 M TA时,通常立即试图交付。如果交付失败, M TA 必须把该报文放入队列中以后再重试。 Host Requirements RFC推荐初始时间间隔至少为 3 0分钟。发送方至少4 ~ 5天内不能放弃。 而且,因为交付失败通常是透明的(接收方崩溃或临时网络连接中断),所以当报文在队列中 等待的第1个小时内,尝试两次连接是有意义的。 28.3 SMTP的例子 上面我们说明了普通邮件发送,在这里我们将说明 M X记录如何用于邮件发送,以及 V R F Y和E X P N命令的用法。 28.3.1 MX记录:主机非直接连到Internet 在1 4 . 6节中我们提到D N S中的一种资源记录类型是邮件交换记录,称为 M X记录。在下面 的例子中我们将说明如何用 M X记录向不直接连到 I n t e r n e t的主机发送邮件。 RFC 974 [Partridge 1986 ] 描述了M TA对M X记录的处理。 主机m l f a r m . c o m不是直接连到I n t e r n e t的,但是有一个M X记录指向I n t e r n e t上的一个邮 件转发器。 有两个M X记录,各有不同的优先级。我们希望 M TA从优先级数值低的开始。 第28章 SMTP:简单邮件传送协议使用337 -v标志看MTA在做什么 在这里键入报文的正文(没显示出来) 找到MX记录 先试优先级低的那一个 下面是正常的SMTP邮件传送 一行中的一个句号,结束报文从输出中我们看到, M TA发现目的主机有一个 M X记录,并使用具有低优先级数值的 M X 记录。 在主机s u n运行这个例子之前,它被配置成不使用本地中继主机,所以我们会看到与目 的主机的邮件交换。主机 s u n还被配置成可使用主机 n o a o . e d u(通过拨号S L I P链路)上的 域名服务器,所以我们能用 t c p d u m p捕获在S L I P链路上进行的邮件发送和 D N S通信。图2 8 - 4 显示了t c p d u m p输出的开始部分。 图28-4 向一个使用MX记录的主机发送邮件 在第1行,M TA向它的域名服务器查询 m l f a r m . c o m的M X记录。跟在2后面的加号“+” 意思是设置要求递归的标志位。第 2行的响应置位授权比特(跟在 2后面的星号“*”),并包含 两个回答R R(两个M X主机名),0个授权R R,以及两个附加的R R(两个主机的I P地址)。 第3 ~ 5行与主机m e r c u r y . h s i . c o m上的S M T P建立了一个T C P连接。服务器的初始响应 2 2 0显示在第6行。 由于某种原因,主机m e r c u r y . h s i . c o m必须把这个邮件报文交付给目的地,m l f a r m . c o m。 对于没有连接到I n t e r n e t上与它的M X站点交换邮件的系统,U U C P协议是一种常用的办法。 在这个例子中,M TA要求一个M X记录,得到一个肯定的结果,然后发送邮件。但不幸的 是,M TA与D N S之间的交互随不同的实现而不同。 RFC 974指定M TA必须首先要求M X记录, 如果没有,就尝试提交给目的主机(也就是说,向 D N S要主机的记录和I P地址)。M TA也必须 处理D N S中的C N A M记录(规范的名)。 作为一个例子,如果我们从一个 B S D / 3 8 6 主机上向 r s t e v e n s @ m a i l h o s t . t u c . n o a o . e d u发送邮件,则M TA(S e n d m a i l)执行以下步骤: 1) Sendmail 向D N S询问主机 m a i l h o s t . t u c . n o a o . e d u的C N A M E记录。我们看到存 在一个C N A M E记录: sun % host -t cname mailhost.tuc.noao.edu mailhost.tuc.noao.edu CNAME noao.edu 2) 发布一个要求n o a o . e d u的C N A M E记录的D N S查询,回答是不存在。 3) Sendmail向D N S寻求n o a o . e d u的M X记录并得到一个记录: sun % host -t mx noao.edu noao.edu M X n o a o . e d u 4) Sendmail 向D N S查询n o a o . e d u的A记录(I P地址),并得到返回值1 4 0 . 2 5 2 . 1 . 5 4(这个 A记录大概是由域名服务器为 n o a o . e d u返回的,作为第3步中M X应答的一个附加的R R)。 5) 启动一个到1 4 0 . 2 5 2 . 1 . 5 4的S M T P连接并发送邮件。 C N A M E查询不是为M X记录(n o a o . e d u)中返回的数据做的。M X记录中的数据不能是 338使用TCP/IP详解,卷1:协议别名— 必须是具有一个A记录的主机名。 与只用DNS 的SunOS 4.1.3一起发布的Sendmail版本查询MX记录,并且如果没有找 到MX记录就放弃。 28.3.2 MX记录:主机出故障 M X记录的另一个用途是在目的主机出故障时可提供另一个邮件接收器。如果看一下主机 s u n的D N S入口,我们就会看到它有两个 M X记录: 最低优先级的M X记录表明应该首先尝试直接发送到主机本身,下一个优先级是把邮件发 送到主机n o a o . e d u。 在下面的描述中,在关掉目的S M T P服务器后,我们从主机v a n g o g h . c s . b e r k e l e y . e d u 向位于主机s u n . t u c . n o a o . e d u的我们自己发送邮件。当端口2 5上的连接请求到达时,T C P应 该响应一个RST,因为没有被动打开的进程为等待该端口而挂起。 我们看到M TA尝试联系s u n . t u c . n o a o . e d u,然后放弃,并转而联系n o a o . e d u。 图2 8 - 5显示了T C P用一个R S T向到来的S Y N响应的t c p d u m p输出。 图28-5 尝试连接一个不在运行的SMTP服务器 第1行v a n g o g h向s u n的第1个I P地址140.252.1.29 的端口25 发送一个S Y N。在第2行它被 拒绝。然后,v a n g o g h上的S M T P客户尝试s u n的第2个I P地址1 4 0 . 2 5 2 . 1 3 . 3 3(第3行),也产 生一个R S T的返回(第4行)。 S M T P客户不区分第1行它主动打开时所返回的不同差错,而这是导致它在第 2行尝试其他 I P地址的原因。如果第 1次的差错是类似“ host unreachable(主机不可达)”,那么第2次尝试或 许可行。 如果S M T P客户的主动打开失败的原因是因为服务器主机出故障了,我们将看到客户会向 I P地址1 4 0 . 2 5 2 . 1 . 2 9重传S Y N总共7 5秒(类似于图1 8 - 6)。然后客户向I P地址1 4 0 . 2 5 2 . 1 3 . 3 3发送 另一个7 5秒的其他3个S Y N。1 5 0秒后客户会移到下一个具有更高优先级的 M X记录。 第28章 SMTP:简单邮件传送协议使用339 下面是正常的SMTP邮件传送28.3.3 VRFY和EXPN命令 V R F Y命令无需发送邮件而验证某个接收方地址是否 O K。E X P N的目的是无需向邮件表发 送邮件就可以扩充该表。许多 S M T P实现(如S e n d m a i l)把两者看成一个,但我们提到新的 S e n d m a i l区分这两者。 作为一个简单测试,我们可以连到一个新的 S e n d m a i l版本,并看到不同之处(已经删除 了无关的Te l n e t客户输出)。 首先注意到我们故意在H E L O命令中键入错误的主机名: b s d i,而不是s u n。许多S M T P 服务器得到客户的I P地址,完成一个D N S指针查询(1 4 . 5节)并比较主机名。这样允许服务器 基于I P地址注册到客户的连接,而不是基于用户可能错误键入的名。某些服务器会用幽默的 报文回答,如“你是一个骗子”,或“为什么叫你自己⋯⋯” 。在这个例子中我们看到,这个 服务器通过指针查询只打印出我们的真实域名以及我们的 I P地址。 然后我们用一个无效的名字键入 V R F Y命令,服务器就响应 5 5 0差错。下一步我们键入一 个有效的名字,服务器用本地主机上的用户名回答。然后我们试试 E X P N命令,并得到一个不 同的回答。E X P N命令决定到该用户的邮件是否被转发,并打印出转发的地址。 许多站点禁止V R F Y和E X P N命令,有时是因为隐私,有时因为相信这是安全漏洞。例如, 我们可以向白宫的S M T P服务器试试下面的命令: 28.4 SMTP的未来 I n t e r n e t邮件发生了很多改变。应当记得 I n t e r n e t邮件的三个组成部分:信封、首部和正文。 新加入的S M T P命令影响了信封,首部中可以使用非 A S C I I字母,正文(M I M E)中也加入了 结构。本节中我们依次对这三部分的扩充进行讨论。 340使用TCP/IP详解,卷1:协议28.4.1 信封的变化:扩充的SMTP RFC 1425 [Klensin等,1993a] 定义了扩充的 S M T P的框架,其结果被称为扩充的 S M T P (E S M T P)。与其他我们已经讨论过的新特性一样,这些变化以向后兼容的方式被加入,所以 不影响已有的实现。 如果客户想使用新的特性,首先通过发布一个 E H L O而不是H E L O命令启动一个与服务器 的会话。相兼容的服务器用 2 5 0应答码响应。这个应答通常有好几行,每行都包含一个关键字 和一个可选的参数。这些关键字指定了该服务器支持的 S M T P扩充。新的扩充将在一个 R F C中 描述并以I A N A注册(在一个多行应答中,各行数字应答码的后面都要有一个连字符。最后一 行的数字应答码后面跟一个空行)。 我们将给出到 4个S M T P服务器的初始连接,其中 3个支持扩充的 S M T P。我们用Te l n e t和 它们连接,但删掉了不必要的 Te l n e t客户输出。 这个服务器用一个多行2 2 0应答作为它的欢迎报文。对 E H L O命令的2 5 0应答中列出的扩充 命令是E X P N、S I Z E和H E L P。第一个和最后一个来自原来的 RFC 821规范,但它们是可选命 令。E S M T P服务器说明除了新命令外,它们还支持哪些可选的 RFC 821命令。 这个服务器支持的S I Z E关键字是在RFC 1427 [Klensin, Freed和Moore 1993] 中定义的。它 让客户在MAIL FROM命令行中以字节的多少指定报文的大小,这样服务器就可以在客户开始 发送该报文之前,验证它是否接收该长度的报文。增加这个命令的原因在于,随着对非 A S C I I 码(如图像、音频等)内容的支持, I n t e r n e t邮件报文的长度在不断增大。 下一个主机也支持 E S M T P,注意2 5 0应答指明支持包含一个可选参数的 S I Z E关键字。这 表明该服务器将接受长度不超过 4 6 1兆字节的报文。 关键字8 B I T M I M E来自于RFC 1426 [Klensin等,1 9 9 3 a ]。它允许客户把关键字B O D Y加到 MAIL FROM命令中,指定正文中是否包含 NVT ASCII字符(默认的)或8 bit数据。除非客户 收到服务器应答E H L O命令发来的8 B I T M I M E关键字,否则禁止客户发送任何非 NVT ASCII字 符(当我们在本节中谈到M I M E时,我们将看到M I M E不要求8 bit传送)。 该服务器也通告了X A D R关键字。任何以X开头的关键字都指的是本地 S M T P扩充。 第28章 SMTP:简单邮件传送协议使用341另一个服务器也支持 E S M T P,通知了我们已经看到的 H E L P和S I Z E关键字。它也支持三 个以X开头的本地扩充。 最后,我们将看到当客户试图通过向一个不支持 E H L O的服务器发布 E H L O命令来使用 E S M T P时将发生什么。 对E H L O命令,客户收到一个 5 0 0应答而不是2 5 0应答。客户应发布 R S E T命令,并跟着一 个H E L O命令。 28.4.2 首部变化:非ASCII字符 RFC 1522 [Moore 1993] 指明了一个在RFC 822报文首部中如何发送非A S C I I字符的方法。 这样做的主要用途是为了允许在发送方名、接收方名以及主题中使用其他的字符。 首部字段中可以包含编码字 (coded word)。它们具有以下格式: = ?c h a r s e t?e n c o d i n g?e n c o d e d - t e x t? = c h a r s e t是字符集规范。有效值是两个字符串 u s - a s c i i和i s o - 8 8 5 9 - x,其中x 是一个单个数字, 例如在i s o - 8 8 5 9 - 1中的数字“1”。 e n c o d i n g是一个单个字符用来指定编码方法,支持两个值。 1) Q编码意思是引号中可打印的( q u o t e d - p r i n t a b l e),目的是用于拉丁字符集。大多数字 符是作为NVT ASCII(当然最高位比特置0)发送的。任何要发送的字符若其第 8比特置1则被 作为3个字符发送:第1个是字符是“=”,跟着两个十六进制数。例如,字符é(它的二进制 8 b i t值为0 x e 9)作为三个字符发送: = E 9。空格通常作为下划线或三个字符 = 2 0发送。这种编码 的目的在于,某些文本中除了大多数 A S C I I字符外,还有几个特殊字符。 2) B意思是以6 4为基数的编码。文本中的 3个连续字节(2 4 b i t)被编码成4个6 bit值。用 于表示所有可能的 6 b i t值的6 4个NVT ASCII字符如图2 8 - 6所示。当要编码的个数不是 3的倍数 时,等号符“=”被用作填充符。 下面两种编码方式的例子取自 RFC 1522: 342使用TCP/IP详解,卷1:协议图28-6 6 bit值的编码(以64为基数编码) 能处理这些首部的用户代理将输出: 为说明以6 4为基数的编码方法是如何工作的,我们看一下主题行中前面 4个编码的字符: S W Y g。按照图2 8 - 6写出这4个字符的6 bit值(S = 0 x 1 2 , W = 0 x 1 6 , Y = 0 x 1 8以及g = 0 x 2 0)的二进 制码: 010010 010110 011000 100000 然后把这24 bit重新分组成3个8 bit字节: 01001001 01100110 00100000 =0x49 =0x66 =0x20 它们是I、f和空格的A S C I I表示。 28.4.3 正文变化:通用Internet邮件扩充 我们已经提到RFC 822指定正文是NVT ASCII文本行,没有结构。RFC 1521 [Borenstein和 Freed 1993] 把扩充定义为允许把结构置入正文。这被称为 M I M E,即通用I n t e r n e t邮件扩充。 M I M E不要求任何扩充,我们在本节前面已作了说明(扩充的 S M T P或非A S C I I标题)。 M I M E正好加入了一些告知收件者正文结构的新标题(与 RFC 822相一致)。正文仍可以用 NVT ASCII码来发送,而不考虑邮件内容。虽然我们前面所述的一些扩充可能会和 M I M E合 在一起产生好的效果— 扩充的SMTP SIZE命令,因为M I M E报文能变得很长,以及非 A S C I I 标题— 这些扩充并不是M I M E所要求的。与另一方交换 M I M E报文所需的一切,就是双方都 要有一个能够理解M I M E的用户代理。在任何一个M TA中不需要做任何改变。 M I M E定义这5个新标题字段如下: M i m e - V e r s i o n : C o n t e n t - T y p e : C o n t e n t - T r a n s f e r - E n c o d i n g : 第28章 SMTP:简单邮件传送协议使用343 6 bit 值 6 bit 值 6 bit 值 6 bit 值 A S C I I 字符 A S C I I 字符 A S C I I 字符 A S C I I 字符C o n t e n t - I D : C o n t e n t - D e s c r i p t i o n : 作为例子,下面两个标题行可以出现在一个 I n t e r n e t邮件报文中: Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII 当前M I M E版本是 1 . 0,内容类型是无格式 A S C I I码文本,即 I n t e r n e t邮件的默认选择。 P L A I N这个字被认为是内容类型( T E X T)的一个子类型,字符串 c h a r s e t = U S - A S C I I是一个 参数。 Te x t是M I M E的7个被定义的内容类型之一。图 2 8 - 7总结了RFC 1521中定义的1 6个不同的 内容类型和子类型。对具体的内容类型和子类型来说都有指定的很多参数。 图28-7 MIME 内容类型和子类型 内容类型和用于内容的传送编码是相互独立的。前者由首部字段 C o n t e n t - Ty p e指明,后者 由首部字段C o n t e n t - Tr a n s f e r- E n c o d i n g指明。在RFC 1521中定义了5种不同的编码格式。 1) 7bit,是默认的NVT ASCII; 2) quoted-printable,我们在前面的一个例子中看到有非 A S C I I首部。当字符中只有很少一 部分的第8 bit 置1时非常有用; 3) base64,如图2 8 - 6所示; 4) 8bit,包含字符行,其中某些为非 A S C I I字符且第8 b i t置1; 5) binary编码,无需包含多行的8 bit数据。 对RFC 821 MTA,以上5种编码格式中只有前 3种是有效的。因为这 3种产生只包含 N V T A S C I I字符的正文。使用有8 B I T M I M E支持的扩充S M T P允许使用8 b i t编码。 尽管内容类型和编码是独立的, R F C 1 5 2 1推荐有非A S C I I数据的t e x t使用q u o t e d - p r i n t a b l e, 而i m a g e、a u d i o、v i d e o和octet-stream application使用b a s e 6 4。这样允许与符合 RFC 821的 M TA保持最大的互操作性。而且, m u l t i p a r t和m e s s a g e内容类型必须以7 b i t编码。 344使用TCP/IP详解,卷1:协议 内容类型 子类型 描 述 t e x t p l a i n 无格式文本 r i c h t e x t 简单格式文本,如粗体、斜体或下划线等 e n r i c h e d r i c h t e x t的简化和改进 m u l t i p a r t m i x e d 多个正文部分,串行处理 p a r a l l e l 多个正文部分,可并行处理 d i g e s t 一个电子邮件的摘要 a l t e n a t i v e 多个正文部分,具有相同的语义内容 m e s s a g e r f c 8 2 2 内容是另一个 RFC 822邮件报文 p a r t i a l 内容是一个邮件报文的片断 e x t e r n a l - b o d y 内容是指向实际报文的指针 a p p l i c a t i o n o c t e t - s t r e a m 任意二进制数据 p o s t s c r i p t 一个P o s t S c r i p t程序 i m a g e j p e g ISO 10918格式 g i f C o m p u S e r v e的图形交换格式 a u d i o b a s i c 用8 bit ISDN 律格式编码 v i d e o m p e g ISO 111 7 2格式作为一个m u l t i p a r t内容类型的例子,图 2 8 - 8显示了一个来自R F C发布清单的邮件报文。子 类型是m i x e d,意思是各部分是顺序处理的,各部分的边界是字符串 N e x t P a r t,其前面是行首 的两个连字符。 每个边界上可跟一行用于指明下一部分首部字段。忽略报文中第 1个边界之前和最后一个 边界之后的所有内容。 因为在第一个边界后面跟着一个空行,而不是首部,所以在第 1个和第2个边界之间的数 据的内容类型被假定为具有 u s - a s c i i字符集的t e x t / p l a i n。这是新R F C的文字描述。 但是第2个边界后面跟着首部字段。它指定了另一个 m u l t i p a r t报文,具有边界O t h e r A c c e s s。 子类型为a l t e r n a t i v e,有两种不同的选择。第 1种O t h e r A c c e s s选项是用电子邮件获取R F C,第2 种选项是用匿名F T P获取。M I M E用户代理将列出这两种选项,允许我们选择一个,然后自动 地用电子邮件或匿名F T P获取一份复制的R F C。 图28-8 MIME multipart报文的例子 第28章 SMTP:简单邮件传送协议使用345 第1个边界 这里的细节在新的RFC中 第2个边界 一个具有新边界的嵌套的多部分报文 最后的边界这一部分是 M I M E的一个简要概述。 M I M E的详细细节和例子,见 RFC 1521和[ R o s e 1 9 9 3 ]。 28.5 小结 电子邮件包括在两端(发送方和接收方)都有的一个用户代理以及两个或多个报文传送 代理。可以把一个邮件报文分成三个部分:信封、首部和正文。我们已经看到这三个部分用 S M T P和I n t e r n e t标准是如何进行交换的。所有都作为 NVT ASCII字符进行交换。 我们也看到了一些新的扩充:用于信封和非 A S C I I首部的扩充S M T P,以及使用M I M E的 正文增加了结构。M I M E的结构和编码允许使用已有的 7bit SMTP MTA交换任意二进制数据。 习题 28.1 读RFC 822,找到域文字(domain literal)的意思。试试用其中一个给自己发送邮件。 28.2 除了连接建立和终止外,要发送一个小的邮件报文的最小网络往返次数是多少? 28.3 T C P是一个全双工协议,但是 S M T P用半双工的形式使用 T C P。客户发送一个命令后停 止等待应答。为什么客户不一次发送多个命令,如一行中包括 H E L O、M A I L、R C P T、 D ATA和Q U I T命令(假定正文不是太大)? 28.4 当网络在接近其容量运行时, S M T P的这种半双工操作如何欺骗缓慢的启动机制? 28.5 当存在多个具有相同优先值的 M X记录时,名服务器是否总能以相同的顺序返回它们? 346使用TCP/IP详解,卷1:协议第29章 网络文件系统 29.1 引言 本章中我们要讨论另一个常用的应用程序: N F S(网络文件系统),它为客户程序提供透 明的文件访问。N F S的基础是Sun RPC:远程过程调用。我们首先必须描述一下 R P C。 客户程序使用 N F S不需要做什么特别的工作,当 N F S内核检测到被访问的文件位于一个 N F S服务器时,就会自动产生一个访问该文件的 R P C调用。 我们对N F S如何访问文件的细节并不感兴趣,只对它如何使用 I n t e r n e t的协议,尤其是 U D P协议,感兴趣。 29.2 Sun远程过程调用 大多数的网络程序设计都是编写一些调用系统提供的函数来完成特定的网络操作的应用 程序。例如,一个函数完成 T C P的主动打开,另一个完成 T C P的被动打开,一个函数在一个 T C P连接上发送数据,另一个设置特定的协议选项(如激活 T C P的k e e p a l i v e定时器)。在1 . 1 5 节我们提到过两个常用的用于网络编程的函数集( A P I):插口( s o c k e t )和T L I。正像客户端和 服务器端运行的操作系统可能会不相同一样,双方使用的 A P I也可能会不相同。由通信协议和 应用协议决定一对客户和服务器是否可以彼此通信。如果两台主机连接在一个网络上,并且 都有一个T C P / I P的实现,那么一台主机上的一个使用 C语言编写的、使用插口和 T C P的U n i x客 户程序可以和另一台主机上的一个使用 C O B O L语言编写的、使用其他 A P I和T C P的大型机服 务器进行通信。 一般来说,客户发送命令给服务器,服务器向客户发送应答。目前为止,我们讨论过的 所有应用程序— P i n g,Tr a c e r o u t e,选路守护程序、以及 D N S、T F T P、B O O T P、S N M P、 Te l n e t、F T P和S M T P的客户和服务器— 都是采用这种方式实现的。 远程过程调用RPC (Remote Procedure Call)是一种不同的网络程序设计方法。客户程序编 写时只是调用了服务器程序提供的函数。这只是程序员所感觉到的,实际上发生了下面一些 动作。 1) 当客户程序调用远程的过程时,它实际上只是调用了一个位于本机上的、由 R P C程序 包生成的函数。这个函数被称为客户残桩( s t u b)。客户残桩将过程的参数封装成一个网络报 文,并且将这个报文发送给服务器程序。 2) 服务器主机上的一个服务器残桩负责接收这个网络报文。它从网络报文中提取参数, 然后调用应用程序员编写的服务器过程。 3) 当服务器函数返回时,它返回到服务器残桩。服务器残桩提取返回值,把返回值封装 成一个网络报文,然后将报文发送给客户残桩。 4) 客户残桩从接收到的网络报文中取出返回值,将其返回给客户程序。 网络程序设计是通过残桩和使用诸如插口或 T L I的某个A P I的R P C库例程来实现的,但是用户程序— 客户程序和被客户程序调用的服务器过程— 不会和这个A P I打交道。客户应用 程序只是调用服务器的过程,所有网络程序设计的细节都被 R P C程序包、客户残桩和服务器 残桩所隐藏。 一个R P C程序包提供了很多好处。 1) 程序设计更加容易,因为很少或几乎没有涉及网络编程。应用程序设计员只需要编写 一个客户程序和客户程序调用的服务器过程。 2) 如果使用了一个不可靠的协议,如 U D P,像超时和重传等细节就由 R P C程序包来处理。 这就简化了用户应用程序。 3) RPC库为参数和返回值的传输提供任何需要的数据转换。例如,如果参数是由整数和 浮点数组成的, R P C程序包处理整数和浮点数在客户机和服务器主机上存储的不同形式。这 个功能简化了在异构环境中的客户和服务器的编码问题。 R P C程序设计的细节可以参看参考文献 [Stevens 1990]的第1 8章。两个常用的R P C程序包 是Sun RPC和开放软件基金(O S F)分布式计算环境(D C E)的R P C程序包。我们对于R P C的 兴趣在于想了解 Sun RPC中过程调用和过程返回报文的形式,因为本章中讨论的网络文件系 统使用了它们。Sun RPC的第2版定义在RFC 1057 [Sun Microsystems 1988a]中。 Sun RPC Sun RPC有两个版本。一个版本建立 在插口A P I基础上,和 T C P和U D P打交道。 另一个称为 T I - R P C的(独立于运输层), 建立在TLI API基础上,可以和内核提供的 任何运输层协议打交道。尽管本章中我们 只讨论 T C P和U D P,从讨论的观点来看, 两者是一样的。 图2 9 - 1显示的是使用 U D P时,一个 R P C过程调用报文的格式。 I P首部和U D P 首部是标准的首部,我们已经在图 3 - 1和图 11 - 2中显示过。 U D P首部以下是 R P C程序 包定义的部分。 事务标识符( X I D)由客户程序设置, 由服务器程序返回。当客户收到一个应答, 它将服务器返回的 X I D与它发送的请求的 X I D相比较。如果不匹配,客户就放弃这 个报文,等待从服务器返回的下一个报文。 每次客户发出一个新的 R P C,它就会改变 报文的X I D。但是如果客户重传一个以前发送过的 R P C(因为它没有收到服务器的一个应答), 重传报文的X I D不会修改。 调用( c a l l )变量在过程调用报文中设置为 0,在应答报文中设置为 1。当前的R P C版本是2。 接下来三个变量:程序号、版本号和过程号,标识了服务器上被调用的特定过程。 348使用TCP/IP详解,卷1:协议 图29-1 RPC过程调用报文作为一个UDP数据报的格式 IP首部 20字节 UDP首部 事务标识符(XID) 调用(0) RPC版本(2) 程序号 过程号 版本号 证书 最多400字节 最多400字节验证 过程参数依赖于所调用的 具体过程 Sun RPC过程调 用的公共部分证书( c r e d e n t i a l )字段标识了客户。有些情 况下,证书字段设置为空值;另外一些情况下, 证书字段设置为数字形式的客户的用户号和组 号。服务器可以查看证书字段以决定是否执行 请求的过程。验证 ( v e r i f i e r )字段用于使用了 D E S加密的安全 R P C。尽管证书字段和验证字 段是可变长度的字段,它们的长度也作为字段 的一部分被编码。 接下来是过程参数 (procedure parameter)字 段。参数的格式依赖于远程过程的定义。接收者 (服务器残桩)如何知道参数字段的大小呢?既 然使用的是U D P协议,U D P数据报的大小减去验 证字段以上所有字段的长度就是参数的大小。如 果使用的不是U D P而是T C P,因为T C P是一个字 节流协议,没有记录边界,所以没有固定的长度。为了解决这个问题,在T C P首部和X I D之间增 加了一个4字节的长度字段,告诉接收者这个R P C调用由多少字节组成。这也使得一个R P C调用 报文在必要时可以用多个T C P段来传输(D N S使用了类似的技术,参见习题1 4 - 4)。 图2 9 - 2显示了一个R P C应答报文的格式。当远程过程返回时,服务器残桩将这个报文发送 给客户残桩。 应答报文中的X I D字段是从调用报文的 X I D字段复制而来。应答字段设置为 1,以区别于 调用报文。如果调用报文被接受,状态字段设置为 0(如果R P C的版本号不为2,或者服务器 不能鉴别客户的身份,调用报文可能被拒绝)。安全的R P C使用验证字段来标识服务器。 如果远程过程调用成功,接受状态字段置为 0。一个非零的值可能表示一个不合法的版本 号或者一个不合法的过程号。如果使用的不是 U D P而是T C P,如同R P C调用报文一样,在T C P 首部和X I D字段之间插入一个4字节的长度字段。 29.3 XDR: 外部数据表示 外部数据表示XDR (eXternal Data Representation)是一个标准,用来对R P C调用报文和应 答报文中的值进行编码。这些值包括 R P C首部字段(X I D、程序号、接受状态等)、过程参数 和过程结果。采用标准化的方法对这些值进行编码使得一个系统中的客户可以调用另一个不 同架构的系统中的一个过程。 X D R在RFC 1014中定义[Sun Microsystems 1987]。 X D R定义了很多数据类型以及它们如何在一个 R P C报文中传输的具体形式(如比特顺序, 字节顺序等)。发送者必须采用X D R格式构造一个R P C报文,然后接收者将X D R格式的报文转 换为本机的表示形式。例如,在图2 9 - 1和图2 9 - 2中,我们显示的所有整数值(X I D、调用字段、 程序号等)都是4字节的整数。在X D R中,所有的整数的确占据 4个字节。X D R支持的其他数 据类型包括无符号整数、布尔类型、浮点数、定长数组、可变长数组和结构。 29.4 端口映射器 包含远程过程的 R P C服务器程序使用的是临时端口,而不是知名端口。这就需要某种形 第29章 网络文件系统使用349 图29-2 RPC应答报文作为一个UDP数据报的格式 IP首部 20字节 UDP首部 事务标识符(XID) 应答(1) 状态(0=接受) 验证 接受状态(0=成功) 过程结果 ⋯ 依赖于具 体过程 Sun RPC过 程应答的 公共部分 最多400字节式的“注册”程序来跟踪哪一个 R P C程序使用了哪一个临时端口。在 Sun RPC中,这个注册程 序被称为端口映射器(port mapper)。 “端口”这个词作为I n t e r n e t协议族的一个特征,来自于T C P和U D P端口号。既然T I - R P C可以工作在任何运输层协议之上,而不仅仅是 T C P和U D P,所以使用T I - R P C的系 统中(如S V R 4和Solaris 2.2),端口映射器的名字变成了r p c b i n d。下面我们继续使用更 为常见的端口映射器的名字。 很自然地,端口映射器本身必须有一个知名端口: U D P端口111和T C P端口111。端口映射 器也就是一个R P C服务器程序。它有一个程序号( 1 0 0 0 0 0)、一个版本号(2)、一个T C P端口 111和一个U D P端口111。服务器程序使用 R P C调用向端口映射器注册自身,客户程序使用 R P C调用向端口映射器查询。端口映射器提供四个服务过程: 1) PMAPPROC_SET。一个R P C服务器启动时调用这个过程,注册一个程序号、版本号和 带有一个端口号的协议。 2) PMAPPROC_UNSET。R P C服务器调用此过程来删除一个已经注册的映射。 3) PMAPPROC_GETPORT。一个R P C客户启动时调用此过程。根据一个给定的程序号、 版本号和协议来获得注册的端口号。 4) PMAPPROC_DUMP。返回端口映射器数据库中所有的记录(每个记录包括程序号、 版本号、协议和端口号): 在一个R P C服务器程序启动,接着被一个 R P C客户程序调用的过程中,进行了以下一些 步骤: 1) 一般情况下,当系统引导时,端口映射器必须首先启动。它创建一个 T C P端点,并且被 动打开T C P端口111。它也创建一个U D P端点,并且在U D P端口111等待着U D P数据报的到来。 2) 当R P C服务器程序启动时,它为它所支持的程序的每一个版本创建一个 T C P端点和一 个U D P端点(一个给定的 R P C程序可以支持多个版本。客户调用一个服务器过程时,说明它 想要哪一个版本)。两个端点各自绑定一个临时端口( T C P端口号和U D P端口号是否一致无关 紧要)。服务器通过 R P C调用端口映射器的 P M A P P R O C _ S E T过程,注册每一个程序、版本、 协议和端口号。 3) 当R P C客户程序启动时,它调用端口映射器的 P M A P P R O C _ G E T P O RT过程来获得一个 指定程序、版本和协议的临时端口号。 4) 客户发送一个R P C调用报文给第3步返回的端口号。如果使用的是 U D P,客户只是发送 一个包含R P C调用报文(见图 2 9 - 1)的U D P数据报到服务器相应的 U D P端口。服务器发送一 个包含R P C应答报文(见图2 9 - 2)的U D P数据报到客户作为响应。 如果使用的是T C P,客户对服务器的T C P端口号做一个主动打开,然后在建立的 T C P连接 上发送一个R P C调用报文。服务器作为响应,在连接上发送一个 R P C应答报文。 程序 r p c i n f o ( 8 )打印了端口映射器中当前的映射记录(它调用了端口映射器的 P M A P P R O C _ D U M P过程)。这里给出的是典型的输出: 350使用TCP/IP详解,卷1:协议 NFS的安装守护程序可以看出一些程序确实支持多个版本。在端口映射器中,每一个程序号、版本号和协议 的组合都有自己的端口号映射。 安装守护程序(mount daemon)的两个版本可以通过同样的 T C P端口号(7 0 2)和同样的 U D P端口号(6 9 9)来访问,而加锁管理程序( lock manager)的每个版本都有各自不同的端 口号。 29.5 NFS协议 使用N F S,客户可以透明地访问服务器上的文件和文件系统。这不同于提供文件传输的 F T P(第2 7章)。F T P会产生文件一个完整的副本。 N F S只访问一个进程引用文件的那一部分, 并且N F S的一个目的就是使得这种访问透明。这就意味着任何能够访问一个本地文件的客户 程序不需要做任何修改,就应该能够访问一个 N F S文件。 N F S是一个使用Sun RPC构造的客户服务器应用程序。 N F S客户通过向一个N F S服务器发 送R P C请求来访问其上的文件。尽管这一工作可以使用一般的用户进程来实现— 即N F S客 户可以是一个用户进程,对服务器进行显式调用。而服务器也可以是一个用户进程— 因为 两个理由,N F S一般不这样实现。首先,访问一个 N F S文件必须对客户透明。因此, N F S的客 户调用是由客户操作系统代表用户进程来完成的。第二,出于效率的考虑, N F S服务器在服 务器操作系统中实现。如果 N F S服务器是一个用户进程,每个客户请求和服务器应答(包括 读和写的数据)将不得不在内核和用户进程之间进行切换,这个代价太大。 本节中,我们考察在R F C 1 0 9 4中说明的第2版的NFS [Sun Microsystems 1988b]。[ X / O p e n 1991] 中给出了Sun RPC、X D R和N F S的一个更好的描述。 [Stern 1991] 给出了使用和管理 N F S的细节。第3版的N F S协议在1 9 9 3年发布,我们在2 9 . 7节中对它做一个简单的描述。 图2 9 - 3显示了一个N F S客户和一个N F S服务器的典型配置,图中有很多地方需要注意。 1) 访问的是一个本地文件还是一个 N F S文件对于客户来说是透明的。当文件被打开时, 由内核决定这一点。文件被打开之后,内核将本地文件的所有引用传递给名为“本地文件访 问”的框中,而将一个N F S文件的所有引用传递给名为“ N F S客户”的框中。 2) NFS客户通过它的T C P / I P模块向N F S服务器发送R P C请求。N F S主要使用U D P,最新的 实现也可以使用T C P。 3) NFS服务器在端口2 0 4 9接收作为U D P数据报的客户请求。尽管 N F S可以被实现成使用 端口映射器,允许服务器使用一个临时端口,但是大多数的实现都是直接指定 U D P端口2 0 4 9。 4) 当N F S服务器收到一个客户请求时,它将这个请求传递给本地文件访问例程,后者访 问服务器主机上的一个本地的磁盘文件。 5) NFS服务器需要花一定的时间来处理一个客户的请求。访问本地文件系统一般也需要 一部分时间。在这段时间间隔内,服务器不应该阻止其他的客户请求得到服务。为了实现这 一功能,大多数的N F S服务器都是多线程的— 即服务器的内核中实际上有多个 N F S服务器在 第29章 网络文件系统使用351 NFS本身 NFS的加锁管理程序运行。具体怎么实现依赖于不同的操作系统。既然大多数的 U n i x内核不是多线程的,一个共 同的技术就是启动一个用户进程(常被称为 n f s d)的多个实例。这个实例执行一个系统调用, 使自己作为一个内核进程保留在操作系统的内核中。 图29-3 NFS客户和NFS服务器的典型配置 6) 同样,在客户主机上, N F S客户需要花一定的时间来处理一个用户进程的请求。 N F S 客户向服务器主机发出一个 R P C调用,然后等待服务器的应答。为了给使用 N F S的客户主机 上的用户进程提供更多的并发性,在客户内核中一般运行着多个 N F S客户。同样,具体实现 也依赖于操作系统。U n i x系统经常使用类似于N F S服务器的技术:一个叫作b i o d的用户进程执 行一个系统调用,作为一个内核进程保留在操作系统的内核中。 大多数的U n i x主机可以作为一个N F S客户,一个N F S服务器,或者两者都是。大多数 P C机 的实现(M S - D O S)只提供了N F S客户实现。大多数的I B M大型机只提供了N F S服务器功能。 N F S实际上不仅仅由N F S协议组成。图2 9 - 4显示了N F S使用的不同R P C程序。 图29-4 NFS使用的不同RPC程序 在这个图中,程序的版本是在SunOS 4.1.3中使用的。更新的实现提供了其中一些 程序更新的版本。例如,Solaris 2.2还支持端口映射器的第3版和第4版,以及安装守护 程序的第2版。SVR4支持第3版的端口映射器。 在客户能够访问服务器上的文件系统之前, N F S客户主机必须调用安装守护程序。我们 在下面讨论安装守护程序。 加锁管理程序和状态监视器允许客户锁定一个 N F S服务器上文件的部分区域。这两个程 352使用TCP/IP详解,卷1:协议 用户进程 NFS客户 本地文件 访问 客户内核 本地磁盘 服务器内核 本地磁盘 TCP/UDP IP TCP/UDP IP UDP端口 2049 NFS 服务器 本地文件 访问 应用程序 程序号 版本号 过程数 端口映射器 1 0 0 0 0 0 2 4 N F S 1 0 0 0 0 3 2 1 5 安装程序 1 0 0 0 0 5 1 5 加锁管理程序 1 0 0 0 2 1 1, 2, 3 1 9 状态监视器 1 0 0 0 2 4 1 6序独立于N F S协议,因为加锁需要知道客户和服务器的状态,而 N F S本身在服务器上是无状态 的(下面我们对N F S的无状态会介绍得更多)。[X/Open 1991] 的第9, 10和11章说明了使用加 锁管理程序和状态监视器进行 N F S文件锁定的过程。 29.5.1 文件句柄 N F S中一个基本概念是文件句柄 (file handle)。它是一个不透明( o p a q u e )的对象,用来引用 服务器上的一个文件或目录。不透明指的是服务器创建文件句柄,把它传递给客户,然后客 户访问文件时,使用对应的文件句柄。客户不会查看文件句柄的内容— 它的内容只对服务 器有意义。 每次一个客户进程打开一个实际上位于一个 N F S服务器上的文件时,N F S客户就会从N F S 服务器那里获得该文件的一个文件句柄。每次 N F S客户为用户进程读或写文件时,文件句柄 就会传给服务器以指定被访问的文件。 一般情况下,用户进程不会和文件句柄打交道— 只有N F S客户和N F S服务器将文件句柄 传来传去。在第2版的N F S中,一个文件句柄占据3 2个字节,第3版中增加为6 4个字节。 U n i x服务器一般在文件句柄中存储下面的信息:文件系统标识符(文件系统最大 和最小的设备号),i - n o d e号(在一个文件系统中唯一的数值)和一个 i - n o d e的生成码 (每当一个i-node被一个不同的文件重用时就改变的数值)。 29.5.2 安装协议 客户必须在访问服务器上一个文件系统中的文件之前,使用安装协议安装那个文件系统。 一般情况下,这是在客户主机引导时完成的。最后的结果就是客户获得服务器文件系统的一 个文件句柄。 图2 9 - 5显示了一个U n i x客户发出m o u n t( 8 )命令所发生的情况,它说明一个N F S的安装过程。 图29-5 使用Unix mount命令的安装协议 依次发生了下面的动作。 1) 服务器上的端口映射器一般在服务器主机引导时被启动。 2) 安装守护程序( m o u n t d)在端口映射器之后被启动。它创建了一个 T C P端点和一个 第29章 网络文件系统使用353 mount命令 用户进程 用户进程 用户进程 mountd 守护程序 端口 映射器 (6) mount 系统调用 (2) 获取端口号的RPC请求 (3) RPC应答以端口号 (4) 安装文件系统的R P C请求 (5) RPC应答以文件句柄客户内核 服务器内核 (1) 在启 动时注册U D P端点,并分别赋予一个临时的端口号。然后它在端口映射器中注册这些端口号。 3) 在客户机上执行m o u n t命令,它向服务器上的端口映射器发出一个 R P C调用来获得服 务器上安装守护程序的端口号。客户和端口映射器交互既可以使用 T C P也可以使用U D P,但 一般使用U D P。 4) 端口映射器应答以安装守护程序的端口 号。 5) m o u n t命令向安装守护程序发出一个 R P C调用来安装服务器上的一个文件系统。同样, 既可以使用 T C P也可以使用 U D P,但一般使用 U D P。服务器现在可以验证客户,使用客户的 I P 地址和端口号来判别是否允许客户安装指定的文 件系统。 6) 安装守护程序应答以指定文件系统的文 件句柄。 7) 客户机上的m o u n t命令发出m o u n t系统调 用将第5步返回的文件句柄与客户机上的一个本 地安装点联系起来。文件句柄被存储在 N F S客户 代码中,从现在开始,用户进程对于那个服务器 文件系统的任何引用都将从使用这个文件句柄 开始。 上述实现技术将所有的安装处理,除了客户机上的 m o u n t系统调用,都放在用户进程中, 而不是放在内核中。我们显示的三个程序— m o u n t命令、端口映射器和安装守护程序— 都是用户进程。 作为一个例子,在我们的主机 s u n(一个N F S客户机)上执行: sun # mount -t nfs bsdi:/usr /nfs/bsdi/usr 这个命令将主机 b s d i(一个N F S服务器)上的 / u s r目录安装成为本地文件系统 / n f s / b s d i / u s r。图2 9 - 6显示了结果。 当我们引用客户机 s u n上的/nfs/bsdi/usr/rstevens/hello.c 文件时,实际上 引用的是服务器b s d i上的文件/ u s r / r s t e v e n s / h e l l o . c。 29.5.3 NFS过程 现在我们描述N F S服务器提供的1 5个过程(使用的个数与N F S过程的实际个数不一样,因 为我们把它们按照功能分了组)。尽管N F S被设计成可以在不同的操作系统上工作,而不仅仅 是U n i x系统,但是一些提供 U n i x功能的过程可能不被其他操作系统支持(例如硬链接、符号 链接、组的属主和执行权等)。[Stevens 1992]的第4章包含了U n i x文件系统其他的一些信息, 其中有些被N F S采用。 1) GETAT T R。返回一个文件的属性:文件类型(一般文件,目录等)、访问权限、文件 大小、文件的属主者及上次访问时间等信息。 2) SETAT T R。设置一个文件的属性。只允许设置文件属性的一个子集:访问权限、文件 354使用TCP/IP详解,卷1:协议 图29-6 将b s d i : / u s r 目录安装成主机 s u n 上的/ n f s / b s d i / u s r 目录 sun客户 bsdi服务器 NFS安装程序的属主、组的属主、文件大小、上次访问时间和上次修改时间。 3) STAT F S。返回一个文件系统的状态:可用空间的大小、最佳传送大小等。例如 U n i x的 d f命令使用此过程。 4) LOOKUP。查找一个文件。每当一个用户进程打开一个 N F S服务器上的一个文件时, N F S客户调用此过程。 5) READ。从一个文件中读数据。客户说明文件的句柄、读操作的开始位置和读数据的 最大字节数(最多8 1 9 2个字节)。 6) WRITE。对一个文件进行写操作。客户说明文件的句柄、开始位置、写数据的字节数 和要写的数据。 7) CREAT E。创建一个文件。 8) REMOVE。删除一个文件。 9) RENAME。重命名一个文件。 10) LINK。为一个文件构造一个硬链接。硬链接是一个 U n i x的概念,指的是磁盘中的一 个文件可以有任意多个目录项(即名字,也叫作硬链接)指向它。 11) SYMLINK。为一个文件创建一个符号链接。符号链接是一个包含另一个文件名字的 文件。大多数引用符号链接的操作(例如,打开)实际上引用的是符号链接所指的文件。 12) READLINK。读一个符号链接。即返回符号链接所指的文件的名字。 13) MKDIR。创建一个目录。 14) RMDIR。删除一个目录。 15) READDIR。读一个目录。例如,U n i x的l s命令使用此过程。 这些过程实际上有一个前缀 N F S P R O C _,我们把它省略了。 29.5.4 UDP还是TCP N F S最初是用U D P写的,所有的厂商都提供了这种实现。最新的一些实现也支持 T C P。 T C P支持主要用于广域网,它可以使文件操作更快。 N F S已经不再局限于局域网的使用。 当从L A N转换到WA N时,网络的动态特征变化得非常大。往返时间( round-trip time)变 动范围大,拥塞经常发生。 WA N的这些特征使得我们考虑使用具有 T C P属性的算法— 慢启 动,但是可以避免拥塞。既然 U D P没有提供任何类似的东西,那么在 N F S客户和服务器上加 进同样的算法或者使用T C P。 29.5.5 TCP上的NFS 伯克利实现的Net/2 NFS支持U D P或者T C P。[Macklem 1991]描述了这个实现。让我们看 一下使用T C P有什么不同。 1) 当服务器主机进行引导时,它启动一个 N F S服务器,后者被动打开 T C P端口2 0 4 9,等 待着客户的连接请求。这通常是另一个 N F S服务器,正常的NFS UDP服务器在U D P端口2 0 4 9 等待着进入的U D P数据报。 2) 当客户使用T C P安装服务器上的文件系统时,它对服务器上的 T C P端口2 0 4 9做一个主 动打开。这样就为这个文件系统在客户和服务器之间形成了一个 T C P连接。如果同样的客户 安装同样服务器上的另一个文件系统,就会创建另一个 T C P连接。 第29章 网络文件系统使用3553) 客户和服务器在它们连接的两端都要设置 T C P的k e e p a l i v e选项,这样双方都能检测到 对方主机崩溃,或者崩溃然后重启动。 4) 客户方所有使用这个服务器文件系统的应用程序共享这个 T C P连接。例如,在图 2 9 - 6 中,如果在b s d i的/ u s r目录下还有另一个目录 s m i t h,那么对两个目录 / n f s / b s d i / u s r / r s t e v e n s和 / n f s / b s d i / u s r / s m i t h下所有文件的引用将共享同样的 T C P连接。 5) 如果客户检测到服务器已经崩溃,或者崩溃然后重启动(通过收到一个 T C P差错“连 接超时”或者“对方复位连接”),它尝试与服务器重新建立连接。客户做另一个主动打开, 为同一个文件系统请求重新建立 T C P连接。在以前连接上超时的所有客户请求在新的连接上 都会重新发出。 6) 如果客户机崩溃,那么当它崩溃时正在运行的应用程序也要崩溃。当客户机重新启动 时,它很可能使用 T C P重新安装服务器的文件系统,这将导致和服务器的另一个连接。客户 和服务器之间针对同一个文件系统的前一个连接现在打开了一半(服务器方认为它还开着), 但是既然服务器设置了 k e e p a l i v e选项,当服务器发出下一个 k e e p a l i v e探查报文时,这个半开 着的T C P连接就会被中止。 随着时间的流逝,另外一些厂商也计划支持 T C P上的N F S。 29.6 NFS实例 我们使用t c p d u m p来看一下在典型的文件操作中,客户调用了哪些 N F S过程。当t c p d u m p 检测到一个包含 R P C调用(在图 2 9 - 1中调用字段等于 0)、目的端口是 2 0 4 9的U D P数据报时, 它把数据报按照一个 N F S请求进行解码。类似地,如果一个 U D P数据报是一个 R P C应答(在 图2 9 - 2中应答字段为1),源端口是2 0 4 9,t c p d u m p就把此数据报作为一个N F S应答来解码。 29.6.1 简单的例子:读一个文件 第一个例子是使用c a t ( 1 )命令将位于一个N F S服务器上的一个文件复制到终端上: sun % cat /nfs/bsdi/usr/rstevens/hello.c 把文件复制到终端 m a i n ( ) { p r i n t f ("hello, world\n") ; } 如同图2 9 - 6所示,主机s u n(N F S客户机)上的文件系统 /nfs/bsdi/usr 实际上是主机b s d i (N F S服务器)上的 /usr 文件系统。当c a t打开这个文件时, s u n上的内核检测到这一点,然后 使用N F S去访问文件。图2 9 - 7显示了t c p d u m p的输出。 当t c p d u m p解析一个N F S请求或应答报文时,它打印客户的 X I D字段,而不是端口号。第1 行和第2行中的X I D字段值是0 x 7 a a 6。 客户内核中的打开函数一次处理文件名 /nfs/bsdi/usr/rstevens/hello.c 中的一个成员。当处 理到/ n f s / b s d i / u s r时,它发现这是指向一个已安装的 N F S文件系统的一个安装点。 在第1行中,客户调用 G E TAT T R过程取得客户已经安装的服务器目录的属性( / u s r)。这 个R P C请求,除I P首部和U D P首部之外,包含 1 0 4个字节的数据。第 2行中的应答返回了一个 O K值,除了I P首部和U D P首部之外,包含了 9 6个字节的数据。在这个图中,我们可以看出最 小的N F S报文包含大约1 0 0个字节的数据。 356使用TCP/IP详解,卷1:协议图29-7 读一个文件的NFS操作 在第3行中,客户调用 L O O K U P过程来查看 r s t e v e n s文件。在第 4行中收到一个 O K应答。 L O O K U P过程说明了文件名r s t e v e n s和远程文件系统被安装时由内核保存的文件句柄。应答中 包含了下一步要使用的一个新的文件句柄。 在第5行中,客户使用第4行中返回的文件句柄对h e l l o . c调用L O O K U P过程。在第6行返回了 另一个文件句柄。新的文件句柄就是客户在第7行和第9行中引用文件/ n f s / b s d i / u s r / r s t e v e n s / h e l l o . c 所使用的文件句柄。我们看到客户对于正在打开的路径名的每个成员都调用了一次 L O O K U P过 程。 在第7行中,客户又调用了一次 G E TAT T R过程,接着在第 9行中调用了R E A D过程。客户 请求从偏移0开始的1 0 2 4个字节,但是接收到的没有这么多(减去 R P C字段和其他由R E A D过 程返回的值的大小,在第1 0行中返回了3 8个字节的数据。这是文件h e l l o . c的实际大小)。 在这个例子中,应用进程对于内核所做的这些 R P C请求和应答一点儿也不知道。应用进 程只是调用了内核的 o p e n函数,后者引起了 3个R P C请求和3个应答(1 ~ 6行),然后应用进程 又调用了内核的 r e a d函数,它引起了两个请求和两个应答( 7 ~ 1 0行)。该文件位于一个 N F S文 件服务器,这一点对客户应用进程来说是透明的。 29.6.2 简单的例子:创建一个目录 作为另一个简单的例子,我们将当前工作目录改变为一个 N F S服务器上的一个目录,然 后创建一个新的目录: sun % cd /nfs/bsdi/usr/rstevens 改变当前工作目录 sun % mkdir Mail 并且创建一个目录 图2 9 - 8显示了t c p d u m p的输出。 图29-8 NFS的操作:cd到NFS目录,然后mkdir 第29章 网络文件系统使用357改变目录引起客户调用了两次 G E TAT T R过程(1 ~ 4行)。当我们创建新的目录时,客户调 用了G E TAT T R过程(5 ~ 6行),接着调用L O O K U P过程(7 ~ 8行,用来验证将创建的目录不存 在),跟着调用了M K D I R过程来创建目录(9 - 1 0行)。在第8行中,应答O K并不表示目录存在。 它只是表示过程返回了。 t c p d u m p并不理解N F S过程的返回值。它一般打印 O K和应答报文中 数据的字节数。 29.6.3 无状态 N F S的一个特征(N F S的批评者称之为N F S的一个瑕疵,而不是一个特征)是 N F S服务器 是无状态的( s t a t e l e s s )。服务器并不记录哪个客户正在访问哪个文件。请注意一下在前面给出 的N F S过程中,没有一个 o p e n操作和一个c l o s e操作。L O O K U P过程的功能与o p e n操作有些类 似,但是服务器永远也不会知道客户对一个文件调用了 L O O K U P过程之后是否会引用该文件。 无状态设计的理由是为了在服务器崩溃并且重启动时,简化服务器的崩溃恢复操作。 29.6.4 例子:服务器崩溃 在下面的例子中我们从一个崩溃然后重启动的 N F S服务器上读一个文件。这个例子演示 了无状态的服务器是如何使得客户不知道服务器的崩溃。除了在服务器崩溃然后重启动时一 个时间上的暂停外,客户并不知道发生的问题,客户应用进程没有受到影响。 在客户机s u n上,我们对一个长文件( N F S服务器主机s v r 4上的文件/ u s r / s h a r e / l i b / t e r m c a p) 执行c a t命令。在传送过程中把以太网的网线拔掉,关闭然后重启动服务器主机,再重新将网 线连上。客户被配置成每个 NFS read过程读1 0 2 4个字节。图2 9 - 9显示了t c p d u m p的输出。 1 ~ 1 0行对应于客户打开文件,操作类似于图 2 9 - 7所示。在第11行我们看到对文件的第一 个R E A D操作,在1 2行返回了1 0 2 4个字节的数据。这个操作一直继续到 1 2 9行(读1 0 2 4个字节 的数据,跟着一个O K应答)。 在第1 3 0行和第1 3 1行我们看到两个请求超时,并且分别在 1 3 2行和1 3 3行重传。第一个问 题是这里为什么会有两个读请求,一个从偏移 6 5 5 3 6开始读,另一个从偏移 7 3 7 2 8开始读?答 案是客户内核检测到客户应用进程正在进行顺序地读操作,所以试图预先取得数据块(大多 数的U n i x内核都采用了这种预读技术)。客户内核也正在运行多个 N F S块I / O守护程序,后者 试图代表客户产生多个 R P C请求。一个守护程序正在从偏移 6 5 5 3 6处读8 1 9 2个字节(以1 0 2 4字 节为一组数据块),而另一个正在从7 3 7 2 8处预读8 1 9 2个字节。 客户重传发生在1 3 0 ~ 1 6 8行。在第1 6 9行我们看到服务器已经重启动,在它对第 1 6 8行的客 户N F S请求做出应答之前,它发送了一个 A R P请求。对1 6 8行的响应被发送在 1 7 1行。客户的 R E A D操作继续进行下去。 除了从1 2 9行到1 7 1行5分钟的暂停,客户应用进程并不知道服务器崩溃然后又重启动了。 这个服务器的崩溃对于客户是透明的。 为了研究这个例子中的超时和重传时间间隔,首先要意识到这儿有两个客户守护程序, 分别有它们各自的超时。第 1个守护程序(在偏移 6 5 5 3 6处开始读)的间隔,四舍五入到两个 十进制小数点,为0.68, 0.87, 1.74, 3.48, 6.96, 13.92, 20.0, 20.0, 20.0等等。第2个守护程序(在 偏移7 3 7 2 8处开始读)的间隔也是一样的(精确到两个小数点)。可以看出这些 N F S客户使用 了一个这样的超时定时器:间隔为 0 . 8 7 5秒的倍数,上限为2 0秒。每次超时后,重传间隔翻倍: 358使用TCP/IP详解,卷1:协议0.875, 1.75, 3.5, 7.0和1 4 . 0。 图29-9 当一个NFS服务器崩溃然后重启动时,客户正在读一个文件的过程 客户要重传多久呢?客户有两个与此有关的选项。首先,如果服务器文件系统是“硬” 安装的,客户就会永远重传下去。但是如果服务器文件系统是“软”安装的,客户重传了固 定数目的次数之后就会放弃。在“硬”安装的情况下,客户还有一个选项决定是否允许用户 中断无限制的重传。如果客户主机安装服务器文件系统时说明了中断能力,并且如果我们不 想在服务器崩溃之后等 5分钟,等着服务器重启动,就可以键入一个中断键以终止客户应用 第29章 网络文件系统使用359 连续地读 连续重传 服务器重启动 连续读程序。 29.6.5 等幂过程 如果一个 R P C过程被服务器执行多次仍然返回同样的结果,那么就把它叫作等幂过程 (Idempotent Procedure)。例如,N F S的读过程是等幂的。正像我们在图 2 9 - 9中看到的,客户 只是重发一个特定的R E A D调用直到它得到一个响应。在我们的例子中,重传的原因是服务器 崩溃了。如果服务器没有崩溃,而是 R P C应答报文丢失了(既然 U D P是不可靠的),客户只是 重传请求,服务器再一次执行同样的 R E A D过程。同一个文件的同一部分被重读一次,发送给 客户。 这种方法行得通的原因在于每个 R E A D请求指出了读操作开始的偏移位置。如果有一个 N F S过程要求服务器读一个文件的下 N个字节,这种方法就不行了。除非服务器被做成是有状 态的(与无状态相反),如果一个应答丢失了,客户重发读下 N个字节的R E A D请求,结果将 是不一样的。这就是为什么 N F S的R E A D和W R I T E过程要求客户说明开始的偏移位置的原因。 客户维护着状态(每个文件当前的偏移位置),而不是服务器。 不幸的是并不是所有的文件系统操作都是等幂的。例如,考虑下面的动作:客户 N F S发 出R E M O V E请求来删除一个文件;服务器 N F S删除了文件,并回答 O K;服务器的回答丢失 了;客户N F S超时,然后重传请求;服务器 N F S找不到指定的文件,回答指出一个错误;客户 应用程序接收到一个错误表示文件不存在。这个返回给客户应用程序的错误是不对的— 该 文件的确存在并且被删除了。 等幂的N F S过程是:G E TAT T R、S TAT E S、L O O K U P、R E A D、W R I T E、R E A D L I N K和 R E A D D I R。不是等幂的过程是: C R E AT E、R E M O V E、R E N A M E、L I N K、S Y M L I N K、 M K D I R和R M D I R。S E TAT T R过程如果不用来截断文件,一般是等幂的。 既然使用U D P总会发生响应报文丢失的现象, N F S服务器需要一种方法来处理非等幂的 操作。大多数的服务器实现了一个最近应答的高速缓存,用于存放非等幂操作最近的应答。 每当服务器收到一个请求,它首先检查这个高速缓存,如果找到了一个匹配,就返回以前的 应答而不再调用相应的N F S过程。[Juszczak 1989]提供了这种高速缓存的实现细节。 等幂服务器过程的概念可以应用于任何基于 U D P的应用程序,而不仅仅是 N F S。例如, D N S也提供了一个等幂服务。一个 D N S的服务器可以任意多次地执行一个解析者的请求而没 有任何不良的后果(如果不考虑网络资源浪费的话)。 29.7 第3版的NFS 1 9 9 3年发布了第3版的N F S协议规范[Sun Microsystem 1994]。其实现有望在1 9 9 4年成为可 能。 我们总结一下第2版和第3版的主要区别。下面把两者分别称为 V 2和V 3。 1) V2中的文件句柄是3 2字节的固定大小的数组。在 V 3中,它变成了一个最多为6 4个字节 的可变长度的数组。在 X D R中,一个可变长度的数组被编码为一个 4字节的数组成员个数跟着 实际的数组成员字节。这样在实现时减少了文件句柄的长度,例如 U n i x只需要1 2个字节,但 又允许非U n i x实现维护另外的信息。 2) V2将每个R E A D和WRITE RPC过程可以读写的数据限制为 8 1 9 2个字节。这个限制在V 3 360使用TCP/IP详解,卷1:协议中取消了,这就意味着一个 U D P上的实现只受到 I P数据报大小的限制( 6 5 5 3 5字节)。这样允 许在更快的网络上读写更大的分组。 3) 文件大小以及R E A D和W R I T E过程开始偏移的字节从 3 2字节扩充到6 4字节,允许读写 更大的文件。 4) 每个影响文件属性值的调用都返回文件的属性。这样减少了客户调用 G E TAT T R过程的 次数。 5) WRITE过程可以是异步的,而在 V 2中要求同步的W R I T E过程。这样可以提高 W R I T E 过程的性能。 6) V3中删去了一个过程( S TAT F S),增加了七个过程: A C C E S S(检查文件访问权限)、 M K N O D(创建一个U n i x特殊文件)、R E A D D I R P L U S(返回一个目录中的文件名字和它们的 属性)、F S I N F O(返回一个文件系统的静态信息)、F S S TAT(返回一个文件系统的动态信息)、 PAT H C O N F(返回一个文件的 P O S I X . 1信息)和C O M M I T(将以前的异步写操作提交到外存 中)。 29.8 小结 R P C是构造客户-服务器应用程序的一种方式,使得看起来客户只是调用了服务器的过程。 所有的网络操作细节都被隐藏在 R P C程序包为一个应用程序生成的客户和服务器残桩以及 R P C库的例程中。我们显示了 R P C调用和应答报文的格式,并且提到了使用 X D R对传输的值 进行编码,使得R P C客户和服务器可以运行在不同架构的机器上。 最广泛使用的R P C应用之一就是S u n的N F S,一个在各种大小的主机上广泛实现的异构的 文件访问协议。我们浏览了 N F S和它使用U D P和T C P的方式。第2版的N F S协议定义了1 5个过 程。 一个客户对一个 N F S服务器的访问开始于安装协议,返回给客户一个文件句柄。客户接 着可以使用那个文件句柄来访问服务器文件系统中的文件。在服务器上,一次检查文件名的 一个成员,返回每个成员的一个新的文件句柄。最后的结果就是要引用的文件的一个文件句 柄,它可以在随后的读写操作中被使用。 N F S试图把它的所用过程都做成等幂的,使得如果响应报文丢失了,客户只需要重发一 个请求。我们看到了服务器崩溃然后又重启动时,一个客户读服务器上的一个文件的例子。 习题 29.1 在图2 9 - 7中,我们看到t c p d u m p将分组理解为N F S的请求和应答,打印了 X I D。t c p d u m p 可以为任何的R P C请求或者应答这样做吗? 29.2 在一个 U n i x系统中,你认为为什么 R P C服务器程序使用的是临时端口,而不是知名端 口? 29.3 一个R P C客户调用了两个服务器过程。第 1个服务器过程执行花了 5秒钟的时间,第二个 过程花了1秒钟。客户有一个4秒钟的超时。画出客户与服务器之间在时间轴上交互的信 息(假定信息从客户传到服务器或者相反都不花时间)。 29.4 在图2 9 - 9的例子中,如果N F S服务器关机时,把它的以太网卡给换掉了,将会发生什么 事情? 第29章 网络文件系统使用36129.5 在图2 9 - 9中,当服务器重启动后,它处理了从偏移 6 5 5 3 6开始的请求(1 6 8行和1 7 1行), 然后处理了从偏移 6 6 5 6 0开始的下一个请求( 1 7 2行和1 7 3行)。对于从偏移7 3 7 2 8开始的 请求怎么处理的呢?(1 6 7行) 29.6 当描述等幂N F S过程时,我们给出了一个R E M O V E应答在网络中丢失的例子。在这种情 况下,如果使用的是T C P而不是U D P会怎么样呢? 29.7 如果N F S服务器使用的是一个临时端口而不是 2 0 4 9,那么当服务器崩溃然后又重启动时, 一个N F S客户会发生什么情况呢? 29.8 每个主机最多只有 1 0 2 3个保留端口,所以保留端口是很缺乏的( 1 . 9节)。如果一个N F S 服务器要求它的客户拥有保留端口(公共的端口),一个N F S客户使用T C P安装了N个不 同的服务器上的N个文件系统,那么客户对每个连接都需要一个不同的保留端口号吗? 362使用TCP/IP详解,卷1:协议第30章 其他的TCP/IP应用程序 30.1 引言 本章中我们描述了另外一些很多实现都支持的 T C P / I P应用程序。有些很简单,易于全面 了解(F i n g e r和W h o i s),而另一个则相当复杂( X窗口系统)。我们只提供了这个复杂应用程 序的一个简短的概述,集中介绍其对 T C P / I P协议的使用。 另外,我们提供一些 I n t e r n e t上资源发现工具的概述。包括一组在 I n t e r n e t上导航的工具, 可以帮助寻找一些我们不知道确切位置和名字的信息。 30.2 Finger协议 F i n g e r协议返回一个指定主机上一个或多个用户的信息。它常被用来检查某个人是否登录 了,或者搞清一个人的登录名以便给他发送邮件。 RFC1288 [Zimmerman 1991] 指明了这个协 议。 由于两个原因,很多站点不支持一个 F i n g e r服务器。第一,F i n g e r服务器的一个早期版本 中的一个编程错误被 1 9 8 8年声名狼藉的 I n t e r n e t蠕虫病毒利用,作为进入点之一( R F C 11 3 5 [Reynolds 1989] 和 [Curry 1992] 更详细地描述了蠕虫)。第二,F i n g e r协议有可能会泄露一些 很多管理员认为是有关用户的私有信息(登录名、电话号码,他们上次的登录时间,等等)。 R F C 1 2 8 8的第3节给出了这个有关服务安全方面的细节。 从一个协议的角度来看, F i n g e r服务器有一个知名的端口 7 9。客户对这个端口做一个主动 打开,然后发送一个在线的请求。服务器处理这个请求,把输出发送回去,然后关闭连接。 查询和响应都是采用NVT ASCII,类似于我们在F T P和S M T P协议中所看到的。 尽管大多数的U n i x用户都是使用finger ( 1 )客户来访问F i n g e r服务器,我们将从使用 Te l n e t 客户与F i n g e r服务器直接相连开始,看看客户发出的每一条在线命令。如果客户的查询是一个 空行(在NVT ASCII中,空行以一个回车符 C R跟着一个换行符 L F来传输),它就是一个请求 查询所有在线用户信息的命令。 o ff i c e和o ffice phone的空白输出字段是从用户的口令 ( p a s s w o r d )文件记录的选项字段中取 出的(在这个例子中,这两个字段的值没有提供)。 服务器必须在最后做一个主动的关闭操作,因为服务器返回的是一个可变长度的信息。 Telnet客户输出前三行 这儿我们键入回车作为Finger客户的命令 Telnet客户的输出当客户收到文件结束字符时,就知道服务器的输出结束了。 当客户的请求由一个用户名组成时,服务器只以该用户的信息作为响应。下面是另一个 例子,这个例子中删去了Te l n e t客户的输出: 当一个系统完全禁止了F i n g e r服务时,因为没有进程被动打开端口 7 9,所以客户的主动打 开将从服务器接收到一个R S T。 一些站点在端口 7 9提供了一个服务器,但服务器只是向客户输出信息,而不理睬客户的 任何请求: 对一个组织来说,另一种可能就是实现一个防火墙网关:在组织内部和 I n t e r n e t之间的一 个路由器,负责过滤(也就是扔掉)特定的 I P数据报([Cheswick and Bellovin 1994] 详细讨 论了防火墙网关)。防火墙网关可以被配置成扔掉从 I n t e r n e t进来的这样一些数据报,这些数据 报是目的端口为7 9的T C P报文段。 对于F i n g e r的服务器和U n i x的F i n g e r客户还有其他的实现。欲知详情,请参考 R F C 1 2 8 8和 有关f i n g e r ( 1 )的手册。 R F C 1 2 8 8指出提供了F i n g e r服务器的、具有T C P / I P连接的自动售货机应该对客户的 空行请求响应以现有产品的列表。对于由一个名字组成的客户请求,它们应该响应以 一个数目或者与这个产品有关的可用项的列表。 30.3 Whois协议 W h o i s协议是另一种信息服务。尽管任何站点都可以提供一个 W h o i s服务器,在I n t e r N I C 站点(r s . i n t e r n i c . n e t)的服务器是最常使用的。这个服务器维护着所有的 D N S域和很多连接在 I n t e r n e t上的系统的系统管理员的信息(另一个可用的服务器在 n i c . d d n . m i l,不过只包含了有 关M I L N E T的信息)。不幸的是信息有可能是过期的或不完整的。 RFC954 [Harrenstein, Stahl, 364使用TCP/IP详解,卷1:协议 这是我们键入的客户请求 这一行是Finger客户输出的;其余行是服务器输出的and Feinler 1985] 说明了W h o i s服务。 从协议的角度来看,W h o i s服务器有一个知名的T C P端口4 3。它接受客户的连接请求,客 户向服务器发送一个在线的查询。服务器响应以任何可用的信息,然后关闭连接。请求和应 答都以NVT ASCII来传输。除了请求和应答所包含的信息不一样, W h o i s服务器和F i n g e r服务 器几乎是一样的。 最常用的U n i x客户程序是whois(1) 程序,尽管我们可以使用 Te l e n t自己手工键入命令。开 始的命令是只包含一个问号的请求,服务器会返回所支持的客户请求的具体信息。 当N I C在1 9 9 3年改变为I n t e r N I C时,W h o i s服务器的站点也从 n i c . d d n . m i l移到了 r s . i n t e r n i c . n e t。很多厂商仍然装载了采用n i c . d d n . m i l版本的w h o i s客户程序。为了和正确 的服务器联系上,你可能需要指明命令行参数 -h rs.internic.net。 另外,我们可以使用Telnet登录rs.internic.net站点,登录名采用whois。 我们将使用W h o i s服务器来查询一下本书的作者(已经删去了无关的 Te l n e t客户输出)。第 一个请求是查询所有匹配“ s t e v e n s”的名字。 名字后面的括号中的三个大写字母跟着一个数字,(W R S 2 8),是个人的N I句柄。下一个 查询包含一个感叹号和一个 N I C句柄,用于获得有关这个人的进一步信息。 很多有关I n t e r n e t变量的其他信息也可以查找。例如,请求 net 140.252将返回有关B类地址 1 4 0 . 2 5 2的信息。 白页 使用S M T P的V R F Y命令、F i n g e r协议以及W h o i s协议在I n t e r n e t上查找用户类似于使用电 话号码簿的白页查找一个人的电话号码。在目前阶段,诸如上述的工具已经广泛可用了,为 了提高这种服务的研究正在进行当中。 [Schwartz and Tsirigotis 1991] 包含了正在I n t e r n e t上试验的不同白页服务的其他信息。一 个叫作 N e t f i n d的特别工具可以通过使用 Te l e n t,以 n e t f i n d登录到 b r u n o . c s . c o l o r a d o或者 d s . i n t e r n i c . n e t站点来访问。 RFC1309 [We i d e r, Reynolds, and Heker 1992]提供了对O S I目录服务X . 5 0 0的概述,并且比 较了它与当前的I n t e r n e t技术(F i n g e r和W h o i s)的相同点和不同点。 第30章 其他的TCP/IP应用程序使用365 这是我们键入的客户命令 我们省略了其他25个“stevens”的信息 我们键入的客户请求30.4 Archie、WAIS、Gopher、Veronica和WWW 前两节我们讨论的工具— F i n g e r、W h o i s和一个白页服务— 是用来查找人的信息的。 还有一些工具是用来定位文件和文档的,本节中对这些工具给出了一个概述。我们只提供了 一个概述,因为对每一个工具的细节的研究超出了本书的范围。我们给出了在 I n t e r n e t上找到 这些工具的方法,鼓励你去试一试,找找看哪些工具可以帮助你。还有一些其他的工具正在 被开发。[Obraczka, Danzig, and Li1993] 概述了在I n t e r n e t上的资源发现服务。 30.4.1 Archie 本书中使用的很多资源都是使用匿名 F T P得到的。问题是如何找到有我们想要的程序的 F T P站点。有时候我们甚至不知道精确的文件名,但知道几个很可能在文件名中出现的关键 字。 A r c h i e提供了I n t e r n e t上几千个F T P服务器的目录。我们可以通过登录进一个A r c h i e服务器, 搜索那些名字中包含了一个指定的常规表达式的文件。输出是一个与文件名匹配的 F T P服务器 的列表。然后我们可以使用匿名 F T P去那个站点取得想要的文件。 全世界有很多 A r c h i e服务器。一个比较好的开始点是使用 Te l n e t以a r c h i e名字登录进 d s . i n t e r n i c . n e t,然后执行命令s e r v e r s。这个命令的输出提供了所有 A r c h i e服务器以及它们的地 址的一个列表。 30.4.2 WAIS A r c h i e帮助我们查找名字中包含关键字的文件,但有时候我们需要查找包含一个关键字的 文件或数据库。即,想查找一个内容中包含一个关键字的文件,而不是文件名字中包含关键 字。 WAIS (Wide Area Information Servers广域信息服务系统)知道几百个包含了有关计算机主 题的和其他一般性主题信息的数据库。为了使用 WA I S,我们要选择需要查找的数据库,指明 关键字。尝试WA I S服务请使用Te l n e t,以w a i s名字登录q u a k e . t h i n k . c o m站点。 30.4.3 Gopher G o p h e r是其他I n t e r n e t资源服务如A r c h i e、WA I S和匿名F T P的一个菜单驱动的前端程序。 G o p h e r是最容易使用的工具之一,因为不管它使用了哪个资源服务,它的用户界面都是一样 的。 为了尝试G o p h e r,请使用Te l n e t,以g o p h e r名字登录i s . i n t e r n i c . n e t站点。 30.4.4 Veronica 就像A r c h i e是一个匿名 F T P服务器的索引一样, Ve r o n i c a ( Very Easy Rodent-Oriented Netwide Index to Computerized Archives)是一个G o p h e r标题的索引。一次Ve r o n i c a搜索一般要 查找几百个G o p h e r服务器。 我们必须通过一个 G o p h e r客户来访问 Ve r o n i c a服务。选择 G o p h e r的菜单项 “B e y o n d InterNIC: Virtual Treasures of the Internet”,然后在下一个菜单中选择 Ve r o n i c a。 366使用TCP/IP详解,卷1:协议30.4.5 万维网WWW 万维网使用一个称为超文本的工具,使得我们可以浏览一个大的 /全球范围的服务和文档。 信息和关键字一起显示,不过关键字被突出显示 。我们可以通过选择关键字得到更多的信 息。 为了访问W W W,请使用Te l n e t登录i n f o . c e r n . c h站点。 30.5 X窗口系统 X窗口系统(X Window System),或简称为X,是一种客户-服务器应用程序。它可以使得 多个客户(应用)使用由一个服务器管理的位映射显示器。服务器是一个软件,用来管理显 示器、键盘和鼠标。客户是一个应用程序,它与服务器在同一台主机上或者在不同的主机上。 在后一种情况下,客户与服务器之间通信的通用形式是 T C P,尽管也可以使用诸如 D E C N E T 的其他协议。在有些场合,服务器是与其他主机上客户通信的一个专门的硬件(一个 X终端)。 在另一种场合,一个独立的工作站,客户与服务器位于同一台主机,使用那台主机上的进程 间通信机制进行通信,而根本不涉及任何网络操作。在这两种极端情况之间,是一台既支持 同一台主机上的客户又支持不同主机上的客户的工作站。 X需要一个诸如T C P的、可靠的、双向的流协议( X不是为不可靠协议,如 U D P,而设计 的)。客户与服务器的通信是由在连接上交换的 8 bit字节组成的。[Nye 1992] 给出了客户与服 务器在它们的T C P连接上交换的1 5 0多个报文的格式。 在一个U n i x系统中,当X客户和X服务器在同一台主机上时,一般使用 U n i x系统的本地协 议,而不使用 T C P协议,因为这样比使用 T C P的情况减少了协议处理时间。 U n i x系统的本地 协议是同一台主机上的客户和服务器之间可以使用的一种进程间通信的形式。回忆一下在图 2 - 4中,当使用T C P作为同一台主机上进程间的通信方式时,在 I P层以下发生了这个数据的环 回( l o o p b a c k ),隐含着所有的T C P和I P处理都发生了。 图3 0 - 1显示了三个客户使用一个显示器的可能的脚本。一个客户与服务器在同一台主机 上,使用U n i x系统的本地协议。另外两个位于不同的主机上,使用 T C P。一般来说,其中一 个客户是一个窗口管理程序 (window manager),它有权限管理显示器上窗口的布局。例如, 窗口管理程序允许我们在屏幕上移动窗口,或者改变窗口的大小。 在这里客户和服务器这两个词猛一看含义相反了。对于 Te l n e t和F T P的应用,我们把客户 看作是在键盘和显示器上的交互式用户。但是对于 X,键盘和显示器是属于服务器的。服务器 被认为是提供服务的一方。 X提供的服务是对窗口、键盘和鼠标的访问。对于 Te l n e t,服务是 登录远程的主机。对于F T P,服务是服务器上的文件系统。 当X终端或工作站引导时,一般启动 X服务器。服务器创建一个 T C P端点,在端口6000 + n上做一个被动打开,其中 n是显示器号(一般是 0)。大多数的 U n i x服务器也使用名字 / t m p / . X 11 - u n i x / Xn创建一个U n i x系统的插口,其中n还是显示器的号。 当一个客户在另一台主机上启动时,它创建一个 T C P端点,对服务器上的端口 6 0 0 0 +n做 一个主动打开。每个客户都得到了一个自己与服务器的连接。服务器负责对所有的客户请求 进行复用。从这点开始,客户通过 T C P连接向服务器发送请求(例如,创建一个窗口),服务 第30章 其他的TCP/IP应用程序使用367 例如通过使用不同的颜色— 译者注。器返回应答,服务器也发送事件给客户(鼠标按钮按下,键盘键按下,窗口暴露,窗口大小 改变,等等)。 图30-1 使用一个显示器的三个X客户 图3 0 - 2将图3 0 - 1重新画,但强调了客户与 X服务器进程间的通信, X服务器进程轮流管理 着每个窗口。图中没有显示的是 X服务器管理键盘和鼠标。 图30-2 使用一个显示器的三个客户 单个服务器处理多个客户请求的这种设计与我们在 1 8 . 11节描述的正常的T C P并发服务器 设计不同。例如,每次一个新的 T C P连接请求到达,F T P和Te l n e t服务器都会产生一个新的进 程,因此,每个客户都和一个不同的服务器进程通信。然而,对于 X,运行在同一台主机或者 在不同主机上的所有客户都和同一个服务器通信。 通过X客户和它的服务器之间的T C P连接可以交换很多数据。传输数据的数目依赖于特定的 应用程序设计。例如,如果我们运行Xc l o c k客户,Xc l o c k在服务器的一个窗口中显示客户机当前 的时间和日期。如果我们指定每隔1秒修改一次时间,那么每隔1秒,就会有一个X报文通过T C P 连接从客户传输到服务器。如果我们运行X终端模拟程序,Xt e r m,我们敲的每一个键都会变成一 个3 2字节的X报文(加上标准的I P和T C P首部就是7 2字节),在相反方向上的回送字符将是一个更 大的X报文。[Droms and Dyksen 1990]检查了不同的X客户与一个特定的服务器之间的T C P流量。 30.5.1 Xscope程序 Xs c o p e是检查X客户与它的服务器之间交换的信息的一个方便的程序。大多数的 X窗口实 368使用TCP/IP详解,卷1:协议 客户 进程 客户 进程 客户 进程 TCP连接 窗口 窗口 窗口 显示器 主机A 主机B 主机C 客户 进程 客户 进程 客户 进程 主机BX服务器进程 管理显示 窗口 窗口 窗口 显示器 主机C 主机A现都提供这个程序。它处在客户与服务器之间,双向传输所有的数据,同时解析所有的客户 请求和服务器应答。图3 0 - 3显示了这种设置。 图30-3 使用x s c o p e 监视一个X连接 首先,我们在服务器所在的主机上启动 x s c o p e进程,但是x s c o p e不是在端口6 0 0 0而是 在端口6 0 0 1上监听T C P的连接请求。然后我们在另一台主机上启动一个客户,指明显示器号 为1,而不是0,使得客户与x s c o p e相连,而不直接与服务器相连。当客户的连接请求到达时, x s c o p e创建与端口6 0 0 0上的真正的服务器的一个 T C P连接,在客户与服务器之间复制所有的 数据,同时生成请求与应答的一个可读的描述。 我们将在s u n主机上启动x s c o p e,然后在主机s v r 4上运行x c l o c k客户。 svr4 % DISPLAY=sun:1 xclock -digital -update 5 这条命令在主机s u n的一个窗口中以数字形式显示时间和日期。我们指明了一个每 5秒的更新 时间。 Thu Sep 9 10:32:55 1993 我们对x s c o p e指明一个- q选项以产生最小的输出。为了看到每个报文的所有字段,可 以使用不同的冗长级别。下面的输出显示了前三个请求和应答。 客户的第1个在时刻0 . 0 0的报文和服务器在时刻 0 . 0 2的响应是客户与服务器之间标准的连 接建立过程。客户标识它的字节顺序以及它希望的服务器版本。服务器响应以有关自己的不 第30章 其他的TCP/IP应用程序使用369 客户 进程 客户 进程 主机A 主机B TCP连接 主机C 对请求和应答的描述 X服务器过程 管理显示 窗口 窗口 窗口 显示器同的信息。 下一个在时刻0 . 0 3的报文包含了两个客户请求。第 1个请求在服务器上创建一个客户可以 在其中画的图形上下文。第2个请求从服务器上得到一个属性(R E S O U R C E _ M A N A G E R属性)。 属性可以用于客户之间的通信,经常是在一个应用程序和窗口管理程序之间。服务器在时刻 0 . 2 0的应答包含了这个属性。 下面两个在时刻0 . 3 0和0 . 3 8的客户报文形成了返回一个原子的单个请求(每个属性具有一 个唯一的整型标识符称为原子)。服务器在时刻0 . 4 3的应答包含了这个原子。 如果不提供有关X窗口系统更多的细节是不可能进一步理解这个例子的,但这又不是本节 的目的。在这个例子中,在窗口被显示之前,客户总共发送了 1 6 6 8个字节组成的1 2个报文段, 服务器总共发送了 11 2 0个字节组成的1 0个报文段。耗费的时间为 3 . 1 7秒。从这以后客户每 5秒 发送一个平均4 4个字节的小请求,请求更新窗口。这样一直持续到客户被终止。 30.5.2 LBX:低带宽X 为了将X用于局域网,对X协议使用的编码进行了优化,因为在局域网中花在对数据进行 编码和解码的时间比最小化传输的数据更重要。尽管这种推断对以太网是适用的,但对于低 速的串行线,如S L I P和P P P链路,就存在问题了(2 . 4节和2 . 6节)。 定义一个称为低带宽X(L B X)的标准的工作正在进行当中,它使用了下面的技术来减少 网络流量的数目:快速缓存、只发送与前面分组的不同部分以及压缩技术。标准的规范和在 第6版的X窗口系统中的一个样本实现应该会在 1 9 9 4年的早些时候完成。 30.6 小结 我们介绍的前两个应用, F i n g e r和W h o i s,是用来获得用户信息的。 F i n g e r客户查询一个 服务器,经常是为了找到某个人的登录名(以便给他们发电子邮件),或者去看一下某个人是 否登录了。W h o i s客户一般与I n t e r N I C运行的服务器联系,查找关于一个人、机构、域或网络 号的信息。 我们简单描述了其他一些 I n t e r n e t资源发现服务: A r c h i e、WA I S、G o p h e r、Ve r o n i c a和 W W W, 帮助我们在I n t e r n e t上定位文件和文档。还有一些资源发现工具正在被开发。 本章的最后简单浏览了另一个 T C P / I P的重要客户程序, X窗口系统。我们看到X服务器管 理一个显示器上的多个窗口,处理客户与其窗口的通信。每个客户都有它自己的与服务器的 T C P连接,一个单个的服务器为一个给定的显示器管理着所有的客户。通过 X s c o p e程序,我 们看到怎样把一个程序放在一个客户与服务器之间,输出有关两者之间交换的报文的信息。 习题 30.1 试用W h o i s找到网络号为8 8的A类网络的拥有者。 30.2 试用W h o i s找到管理w h i t e h o u s e . g o v域的D N S服务器。这个应答与 D N S给出的答案 相匹配吗? 30.3 在图3 0 - 3中,你认为x s c o p e进程必须和X服务器运行在同一台主机 上吗? 370使用TCP/IP详解,卷1:协议附录A tcpdump程序 t c p d u m p程序是由Van Jacobson、Craig Leres和Steven McCanne编写的,他们都来自加利 福尼亚大学伯克利分校的劳伦斯伯克利实验室。本书中使用的是 2 . 2 . 1版(1 9 9 2年6月)。 t c p d u m p通过将网络接口卡设置为混杂模式( promiscuous mode)来截获经过网络接口 的每一个分组。正常情况下,用于诸如以太网媒体的接口卡只截获送往特定接口地址或广播 地址的链路层的帧(2 . 2节)。 底层的操作系统必须允许将一个接口设置成混杂模式,并且允许一个用户进程截获帧。 下列的操作系统可以支持 t c p d u m p,或者可以加入对 t c p d u m p的支持:4 . 4 B S D、B S D / 3 8 6、 S u n O S、U l t r i x和H P - U X。参考一下随着 t c p d u m p发布的R E A D M E文件,了解它支持哪些操 作系统以及哪些版本。 除了t c p d u m p还有其他一些选择。在图1 0 - 8中,我们使用了Solaris 2.2的程序s n o o p来查 看一些分组。AIX 3.2.2提供了i p t r a c e程序,该程序也提供了类似的功能。 A.1 BSD 分组过滤器 当前由 B S D演变而来的 U n i x内核提供了 BSD 分组过滤器 BPF (BSD Packet Filter), t c p d u m p用它来截获和过滤来自一个被置为混杂模式的网络接口卡的分组。 B P F也可以工作 在点对点的链路上,如 S L I P(2 . 4节),不需要什么特别的处理就可以截获所有通过接口的分 组。B P F还可以工作在环回接口上( 2 . 7节)。 B P F有一个很长的历史。1 9 8 0年卡耐基梅隆大学的Mike Accetta和Rick Rashid创造 了E n e t分组过滤程序。斯坦福的J e ffrey Mogul将代码移植到B S D,从1 9 8 3年开始继续开 发。从那以后,它演变为D E C的U l t r i x分组过滤器、SunOS 4.1下的一个STREAMS NIT 模块和B P F。劳伦斯伯克利实验室的Steven McCanne在1 9 9 0年的夏天实现了B P F。其中 很多设计来自于Van Jacobson。[McCanne and Jacobson 1993] 给出了最新版本的细节以 及与Sun的NIT的一个比较。 图A - 1显示了用于以太网的B P F的特征。 B P F将以太网设备驱动程序设置为混杂模式,然后从驱动程序那里接收每一个收到的分组 和传输的分组。这些分组要通过一个用户指明的过滤器,使得只有那些用户进程感兴趣的分 组才会传递给用户进程。 多个进程可以同时监视一个接口,每个进程指明了一个自己的过滤器。图 A - 1显示了 t c p d u m p的两个实例进程和一个 R A R P守护进程(5 . 4节)监视同样的以太网接口。 t c p d u m p 的每个实例指明了一个自己的过滤器。 t c p d u m p的过滤器可以由用户在命令行指明,而 r a r p d总是使用只截获R A R P请求的过滤器。 除了指明一个过滤器,B P F的每个用户还指明了一个超时定时器的值。因为网络的数据传 输率可以很容易地超过 C P U的处理能力,而且一个用户进程从内核中只读小块数据的代价昂贵,因此,B P F试图将多个帧装载进一个读缓存,只有缓存满了或者用户指明的超时到期才 将读缓存保存的帧返回。 t c p d u m p将超时定时器置为 1秒,因为它一般从 B P F收到很多数据。 而R A R P守护进程收到的帧很少,所以 r a r p d将超时置为0(收到一个帧就返回)。 图A-1 BSD分组过滤器 用户指明的过滤器告诉B P F用户进程对什么帧感兴趣,过滤器是对一个假想机器的一组指 令。这些指令被内核中的 B P F过滤器解释。在内核中过滤,而不在用户进程中,减少了必须 从内核传递到用户进程的数据量。R A R P守护进程总是使用绑定在程序里的、同样的过滤程序。 另一方面,t c p d u m p在每次运行时,让用户在命令行指明一个过滤表达式。 t c p d u m p将用户 指明的表达式转换为相应的 B P F的指令序列。t c p d u m p表达式的例子如下: % tcpdump tcp port 25 % tcpdump icmp [0] != 8 and icmp[0] != 0 第一个只打印源端口和目的端口为 2 5的T C P报文段。第二个只打印不是回送请求和回送 应答的I C M P报文(也就是非 p i n g的分组)。这个表达式指明了 I C M P报文的第一个字节,图 6 - 2中的t y p e字段,不等于8或0,即图6 - 3中的回送请求和回送应答。正像你所看到的,设计过 滤器需要有底层分组结构的知识。第二个例子中的表达式被放在一对单引号中,防止 U n i x外 壳程序解释特殊字符。 参考t c p d u m p (1) 的手册,了解用户可以指明的表达式的全部细节。 bpf(4) 的手册详细 描述了B P F使用的假想机器指令。 [McCanne and Jacobson 1993] 比较了这个假想机器方法与 其他方法的设计与性能。 A.2 SunOS的网络接口分接头 SunOS 4.1.x提供了一个S T R E A M S伪设备驱动程序(pseudo-device driver),称为网络接口 分接头(Network Interface Ta p )或者N I T([Rago 1993] 包含了流设备驱动程序的其他细节。我 372使用TCP/IP详解,卷1:协议 用户进程 用户进程 用户进程 过滤器过滤器 BPF驱动程序 发送分组的一个复制 接收分组的一个复制 以太网设备 驱动程序 内核 过滤器们把这种特征叫作“流”)。N I T类似于B S D分组过滤器,但不如后者功能强大和效率高。图 A - 2显示了使用N I T所用到的流模块。这个图与图 A - 1之间的一个不同点在于B P F可以截获网络 接口收到的和传送的分组,而 N I T只能截获接口收到的分组。将 t c p d u m p与N I T结合起来意味 着我们只能看见由网络中其他主机发送来的分组— 即根本不可能看见我们自己主机发送的 分组(尽管B P F可以工作在SunOS 4.1.x上,但它需要对以太网设备驱动程序的源代码进行改 变,大多数的用户没有权限访问源代码,因而这是不可能的)。 当设备/ d e v / n i t被打开时,流驱动程序n i t _ i f就会被打开。既然N I T是使用流来构造的,处 理模块可以放在n i t _ i f驱动程序之上。t c p d u m p将模块n i t _ b u f放在S T R E A M之上。这个模块将 多个网络帧聚集在一个读缓存中,允许用户进程指明一个超时的值。这种情况类似于我们在B P F中 所描述的。R A R P守护进程没有把这个模块放在它的流之上,因为它只处理了一小部分分组。 图A-2 SunOS的网络接口分接头 用户指明的过滤由流模块 n i t _ p f处理。在图A - 2中,我们注意到这个模块被 R A R P守护 进程所用,但没有被t c p d u m p使用。在S u n O S操作系统中,t c p d u m p代之以在用户进程中完 成自己的过滤操作。这么做的理由是 n i t _ p f使用的假想机器的指令与 B P F所支持的指令不同 (不如B P F所支持的功能强大)。这就意味着当用户对 t c p d u m p指明了一个过滤表达式时,与 B P F相比较,使用N I T就会有更多的数据在内核与用户进程之间交换。 A.3 SVR4数据链路提供者接口 S V R 4支持数据链路提供者接口DLPI (Data Link Provider Interface),它是O S I数据链路服 务定义的一个流实现。S V R 4的大多数版本支持第1版的 D L P I,S V R 4 . 2同时支持第1版和第2版, S u n的Solaris 2.x支持第2版,但是增强了一些功能。 像t c p d u m p的网络监视程序必须使用 D L P I来直接访问数据链路设备驱动程序。在 S o l a r i s 2 . x中,分组过滤的流模块被改名为 p f m o d,缓存模块被改名为b u f m o d。 附录A tcpdump程序使用373 用户进程 用户进程 过滤器 流模块 流模块 流驱动程序 接收分组的复制 以太网设备 驱动程序 内核尽管Solaris 2.x还很新,t c p d u m p在其上的一个实现有一天也会出现。 S u n还提供了一个 叫作 s n o o p的程序,完成的功能类似于 t c p d u m p( s n o o p代替了 SunOS 4.x的程序 e t h e r f i n d)。作者还不知道t c p d u m p到vanilla SVR4上的任何端口实现。 A.4 tcpdump的输出 t c p d u m p的输出是“原始的”。在本书中包含它的输出时,我们对它进行了修改以便阅读。 首先,它总是输出它正在监听的网络接口的名字。我们把这一行给删去了。 其次,t c p d u m p输出的时间戳在一个微秒精度的系统中采用如同 0 9 : 11 : 2 2 . 6 4 2 0 0 8的格式, 在一个1 0 m s时钟精度的系统中则如同 0 9 : 11 : 2 2 . 6 4一样(在附录 B中,我们更多地讨论了计算 机时钟的精度)。在任何一种情况下, H H : M M : S S的格式都不是我们想要的。我们感兴趣的是 每个分组与开始监听的相对时间以及与下面分组的时间差。我们修改了输出以显示这两个时 间差。第1个差值在微秒精度的系统中打印到十进制小数点后面 6位(对于只有10 ms精度的系 统打印到小数点后面2位),第2个差值打印到十进制小数点后面 4位或2位(依赖于时钟精度)。 本书中大多数t c p d u m p的输出都是在s u n主机上收集的,它提供了微秒精度。一些 输出来自于运行0 . 9 . 4版B S D / 3 8 6操作系统的主机b s d i,它只提供了10 ms的精度(如图5 - 1所示)。一些输出收集于当b s d i主机运行1 . 0版B S D / 3 8 6时,后者提供了微秒级的精度。 t c p d u m p总是打印发送主机的名字,接着一个大于号,然后是目的主机的名字。这样显示 很难追踪两个主机之间的分组流。尽管t c p d u m p输出仍然显示了数据流的方向,但我们经常把 这条输出删掉,代替以产生一条时间线(在本书中的第一次出现是在图 6 - 11)。在我们的时间线 上,一个主机在左边,另一个在右边。这样很容易看出哪一边发送分组,哪一边接收分组。 我们给t c p d u m p的每条输出增加了行号,使得我们可以在书中引用特定的行。还在某些 行之间增加了额外的空白,以区别一些不同的分组交换。 最后,t c p d u m p的输出可能会超出一页的宽度。我们在太长行的适当地方进行了换行。 作为一个例子,相应于图 4 - 4的t c p d u m p的原始输出显示在图 A - 3中。这里假设了一个 8 0 列的终端窗口。 没有显示我们键入的中断键(用于中止 t c p d u m p),也没有显示接收到的和漏掉的分组的 个数(漏掉的分组是那些到达得太快, t c p d u m p来不及处理的分组。因为本文中的例子经常 运行在另外一个空闲网络上,所以漏掉的分组个数总是 0)。 图A-3 图4-4的t c p d u m p 的输出 374使用TCP/IP详解,卷1:协议 我们没有显示其他4个分组 键入中断字符来中断显示A.5 安全性考虑 很明显,截获网络中传输的数据流使我们可以看到很多不应该看到的东西。例如, T e l n e t和F T P用户输入的口令在网络中传输的内容和用户输入的一样(与口令的加密表示相 比,这称为口令的明文表示。在 U n i x口令文件中,一般是 / e t c / p a s s w d或/ e t c / s h a d o w, 存储的是加密的表示)。然而,很多时候一个网络管理员需要使用一个类似于 t c p d u m p的工 具来分析网络中出现的问题。 我们是把t c p d u m p作为一个学习的工具,用来查看网络中实际传输的东西。对 t c p d u m p 以及其他厂商提供的类似工具的访问权限依赖于具体系统。例如,在 S u n O S,对N I T设备的 访问只限于超级用户。 B S D的分组过滤器使用了一种不同的技术:通过对 / d e v / b p f X X设备 的授权来控制访问。一般来说,只有属主才能读写这些设备(属主应该是超级用户),对于同 组用户是可读的(经常是系统管理组)。这就是说如果系统管理员不对程序设置用户的 I D,一 般的用户是不能运行类似于 t c p d u m p的程序的。 A.6 插口排错选项 查看一个T C P连接上发生的事情的另一种方法是使能插口排错选项,当然是在支持这一 特征的系统中。这个特征只能工作在 T C P上(其他协议都不行),并且需要应用程序支持(当 应用程序启动时,使能一个插口排错选项)。 大多数伯克利演变的实现都支持这个特征,包括S u nOS、4.4BSD和SVR4。 程序使能了一个插口选项,内核就会保留在那个连接上发生的事情的一个痕迹记录。在这之 后,所有记录的信息都可以使用 t r p t ( 8 )程序打印出来。使能一个插口排错选项不需要特别 的许可,但是因为t r p t程序访问了内核的内存,所以运行 t r p t需要特别的权限。 s o c k程序(附录C)的- D选项支持这个特征,但是输出的信息比相应的 t c p d u m p的输出 更难解析和理解。然而,我们在 2 1 . 4节确实使用它查看了T C P连接上t c p d u m p不能访问的内 核变量。 附录A tcpdump程序使用375附录B 计算机时钟 既然本书中的大多数的例子都需要测量一个时间间隔,我们需要更仔细地介绍一下当前 U n i x系统所采用的记录时间的方法。下面的描述适用于本书中例子所使用的系统,也适用于 大多数的U n i x系统。[ L e ffler et al. 1989]的3 . 4节和3 . 5节给出了另外的细节。 硬件按照一定的频率产生一个时钟中断。对于 Sun SPA R C和Intel 80386,时钟中断每10 ms 产生一次。 应该注意到大多数的计算机使用一种无补偿的晶体振荡器来生成这些时钟中断。正如 RFC1305 [Mills 1992] 的表7指出的,你不要想知道这种振荡器一天的偏差有多少。这就意味着 几乎没有计算机能维持精确的时间(即,中断并不是精确地每 10 ms发生一次)。一个0 . 0 1%的 误差就会产生一个每天 8 . 6 4秒的差错。为了得到更好的时间测量需要:(1)一个更好的振荡 器;(2)一个外部的更精确的时间资源(如,全球定位卫星提供的时间资源);或者( 3)通 过因特网访问一个具有更精确时钟的系统。后者通过 R F C 1 3 0 5定义的网络时间协议实现,对该 协议的描述超出了本书的范围。 U n i x系统中引起时间差错的另一个公共的原因是 10 ms的中断只是引起内核给一个记 录时间的变量增 1。如果内核丢失了一个中断(也就是说两个连续中断之间间隔 10 ms对 于内核来说太快了),时钟将失去 10 ms。丢失这种类型的中断经常引起 U n i x系统丢失时 间。 尽管时间中断近似于每10 ms到达一次,更新的系统,如 S PA R C,提供了一个更高精度的 定时器来测量时间差异。通过 N I T驱动程序,t c p d u m p(在附录A中描述)已经访问了这个更 高精度的定时器。在 S PA R C上,这个定时器提供 了 微 秒 级 的 精 度 。 用 户 进 程 也 可 以 通 过 g e t t i m e o f d a y( 2 )函数来访问这个更高精度的定 时器。 作者做了下面的试验。我们运行了一个程序,这 个程序在一个循环里调用了10 000次g e t t i m e o f d a y 函数,并将每次的返回值保存在一个数组中。在循环 结束后,打印了9 9 9 9个时间差。对于一个S PARC ELC, 时间差的分布如图B - 1所示。 在一个空闲的系统中,运行这个程序所花的时钟时间为 0 . 3 8秒。根据这一点,我们可以 说进程调用g e t t i m e o f d a y所花的时间大约 3 7微秒。既然E L C的速度是2 1 M I P S(M I P S表 示每秒1 0 0万指令),3 7微秒相应于大约8 0 0个指令。这些指令对于内核处理一个用户进程的 调用、执行系统调用、复制 8个字节的结果及返回给用户进程看起来是合理的( M I P S速度是 不可靠的,很难测量当前系统的指令时间。我们试图做的只是得到一个粗略的估计来评价一 下上面的值是否有意义)。 从这个简单的试验,我们可以说 g e t t i m e o f d a y返回的值确实包含了微秒级的精度。 图B-1 在SPARC ELC上调用g e t t i m e o f d a y 函数10 000次所需要的时间分布 微 秒 次数 其他 4 914 4 831如果我们在S V R 4 / 3 8 6上进行类似的测试,结 果是不同的。这是因为很多 386 Unix系统,如 S V R 4,只计数10 ms的时钟中断,而没有提供更 高的精度。图 B - 2是运行在 25 MHz 80386上的 S V R 4中9 9 9 9个时间差的分布。 这些值是无意义的,因为时间差一般小于 1 0 m s,都被认为是0了。在这些系统中,我们所能做的就是在一个空闲的系统上测量时钟时间, 除以循环的次数。这个结果提供了一个上界,因为它包含了调用 p r i n t f函数9 9 9 9次的时间和 将结果写入一个文件的时间(在 S PA R C的情况,图B - 1,时间差没有包括 p r i n t f的时间,因 为所有10 000个值都是首先获得的,然后才打印结果)。在S V R 4的时钟时间为3 . 1 5秒,每个系 统调用消耗了3 1 5微秒。这个大约比S PA R C慢8 . 5倍的系统调用时间看来是正确的。 BSD/386 1.0版提供了类似于S PA R C的微秒级的精度。它读8 2 5 3时钟寄存器,计算从上次 时钟中断以来的微秒次数。调用 g e t t i m e o f d a y的进程和内核模块,如BSD 分组过滤器,可 以使用这个精度。 和t c p d u m p联系起来,这些数字意味着我们可以相信在 S PA R C和B S D / 3 8 6系统上打印的 毫秒和亚毫秒( s u b m i l l i s e c o n d )的值。而在S V R 4 / 3 8 6上,t c p d u m p打印的值总是10 ms的倍数。 对于其他打印往返时间的程序,如 p i n g(第7章)和t r a c e r o u t e(第8章),在S PA R C和 B S D / 3 8 6系统上,我们可以相信它们输出的毫秒值,但在 S V R 4 / 3 8 6上,打印的值总是 1 0的倍 数。为了在 L A N上测量某个 p i n g的时间,在第 7章中我们显示的时间是 3 ms,所以需要在 S PA R C和B S D / 3 8 6系统上运行p i n g程序。 本书中的一些例子是运行在BSD/386 0.9.4版上,它类似于S V R 4,只提供了10 ms 的时钟精度。在我们显示这个系统的t c p d u m p输出时,只显示到小数点后面两位,因 为这就是所提供的精度。 附录B 计算机时钟使用377 图B-2 在SVR4/386上调用gettimeofday函数 10000次所需要的时间 微 秒 次 数 9 8710 10 000 128附录C sock程序 在本书中一直使用一个称为 s o c k的小测试程序,用来生成 T C P和U D P数据。它既可以用 作一个客户进程,也可以用作一个服务器进程。有这样一个可以从外壳程序执行的测试程序, 使我们避免了为每一个我们想要研究的特征编写新的客户和服务器 C程序。因为本书的目的 是了解网络互联协议,而不是网络编程,所以在这个附录中我们只描述这个程序和它不同的 选项。 有很多与s o c k功能类似的程序。J u e rgen Nickelsen写了一个称为s o c k e t的程序, Dave Yo s t写了一个称为s o c k i o的程序。两者都包含了很多类似的特征。s o c k程序的 某些部分也受到了Mike Muuss和Terry Slattery所写的公开域t t c p程序的启发。 s o c k程序运行在以下四种模式之一: 1) 交互式客户:默认模式。程序和一 个服务器相连,然后将标准输入的数据传 给服务器,再将从服务器那里接收到的数 据复制到标准输出。如图C - 1所示。 我们必须指明服务器主机的名字和想要连接的服务的名字。主机可指明为点分十进制数, 服务可指明为一个整数的端口号。从 s u n到b s d i与标准的e c h o服务器(1 . 1 2节)相连,回显 我们键入的每一个字符: sun % sock bsdi echo a test line 我们键入这一行 a test line e c h o服务器返回一个复制行 ^ D 键入文件结束符来中止 2) 交互式服务器:指明-s选项。需要指明服务名字(或端口号): sun % sock -s 5555 作为一个在端口5 5 5 5监听的服务器 程序等待一个客户的连接请求,然后将标准输入复制给客户,将从客户接收到的东西复 制到标准输出。在命令行中,端口号之前可以有一个因特网地址,用来指明接收哪一个本地 接口上的连接: sun % sock -s 140.252.13.33 5555 只接受来自以太网的连接 默认的模式是接受任何一个本地接口上的连接请求。 3) 源客户:指明- i选项。在默认情况下,将一个 1 0 2 4字节的缓存写到网络中,写 1 0 2 4 次。-n选项和-w选项可以改变默认值。例如, sun % sock -i -n12 -w4096 bsdi discard 把1 2个缓存,每个包含4 0 9 6字节的数据,送给主机b s d i上的d i s c a r d服务器。 4) 接收器服务器:指明-i选项和-s选项。从网络中读数据然后扔掉。 这些例子都使用了T C P(默认情况),-u选项指明使用U D P。 s o c k程序有许多选项,用于对程序的运行提供更好的控制。我们需要使用这些选项来产 图C-1 s o c k 程序作为交互式客户的默认操作 标准输入 TCP连接 服务器 标准输出生本书中用到的所有测试条件。 -b n 将n绑定为客户的本地端口号(在默认情况下,系统给客户分配一个临 时的端口号)。 -c 将从标准输入读入的新行字符转换为一个回车符和一个换行符。类似 地,当从网络中读数据时,将〈回车,换行〉序列转换为新行字符。 很多因特网应用需要 NVT ASCII(2 6 . 4节),它使用回车和换行来终止 每一行。 -f a . b . c . d . p 为一个U D P端点指明远端的I P地址(a . b . c . d)和远端的端口号(p)。 -h 实现T C P的半关闭机制( 1 8 . 5节)。即,当在标准输入中读到一个文件 结束符时并不终止。而是在 T C P连接上发送一个半关闭报文,继续从 网络中读报文直到对方关闭连接。 -i 源客户或接收器服务器。向网络写数据(默认),或者如果和 -s 选项一 起用,从网络读数据。 - n选项可以指明写(或读)的缓存的数目, - w 选项可以指明每次写的大小, -r 选项可以指明每次读的大小。 -n n 当和-i 选项一起使用时, n指明了读或写的缓存的数目。 n的默认值是 1 0 2 4。 -p n 指明每个读或写之间暂停的秒数。这个选项可以和源客户(- i)或接 收器服务器(- i s)一起使用作为每次对网络读写时的延迟。参考- P选 项,实现在第1次读或写之前暂停。 -q n 为T C P服务器指明挂起的连接队列的大小: T C P将为之进行排队的、已 经接受的连接的数目(图1 8 - 2 3)。默认值是5。 -r n 和- i s选项一起使用,n指明每次从网络中读数据的大小。默认是每次读 1 0 2 4字节。 -s 作为一个服务器,而不是一个客户。 -u 使用U D P,而不是T C P。 -v 详细模式。在标准差错上打印附加的细节信息(如客户和服务器的临 时端口号)。 -w n 和- i选项一起使用, n指明每次从网络中写数据的大小。默认值是每次 写1 0 2 4字节。 -A 使能 S O _ R E U S E A D D R插口选项。对于 T C P,这个选项允许进程给自 己分配一个处于2 M S L等待的连接的端口号。对于 U D P,这个选项支持 多播,它允许多个进程使用同一个本地端口来接收广播或多播的数据 报。 -B 使能S O _ B R O A D C A S T插口选项,允许向一个广播 I P地址发送U D P数 据报。 -D 使能S O _ D E B U G插口选项。这个选项使得内核为这个 T C P连接维护另 外的调试信息(A . 6节)。以后可以运行t r p t ( 8 )程序输出这个信息。 -E 如果实现支持,使能 I P _ R E C V D S TA D D R插口选项。这个选项用于 附录C sock程序使用379U D P服务器,用来打印接收到的 U D P数据报的目的I P地址。 -F 指明一个并发的T C P服务器。即,服务器使用 f o r k函数为每一个客户连 接创建一个新的进程。 -K 使能T C P的S O _ K E E PA L I V E插口选项(第2 3章)。 -L n 把一个T C P端点的拖延时间(linger time)(S O _ L I N G E R)设置为n。一 个为0的拖延时间意味着当网络连接关闭时,正在排队等着发送的任何 数据都被丢弃,向对方发送一个重置报文( 1 8 . 7节)。一个正的拖延时 间(百分之一秒)是关闭网络连接必须等待的将所有正在排队等着发 送的数据发送完并收到确认的时间。关闭网络连接时,如果这个拖延 定时器超时,挂起的数据没有全部发送完并收到确认,关闭操作将返 回一个差错信息。 -N 设置T C P _ N O D E L AY插口选项来禁止N a g l e算法(1 9 . 4节)。 -O n 指明一个T C P服务器在接受第一个客户连接之前暂停的秒数。 -P n 指明在第一次对网络进行读或写之前暂停的秒数。这个选项可以和接 收器服务器(-i s)一起使用,完成在接受了客户的连接请求之后但在 执行从网络中第一次读之前的延迟。和接收源(- i)一起使用时,完 成连接建立之后但第一次向网络写之前的延迟。参看- p选项,实现在 接下来的每一次读或写之间进行暂停。 -Q n 指明当一个 T C P客户或服务器收到了另一端发来的一个文件结束符, 在它关闭自己这一端的连接之前需要暂停的秒数。 -R n 把插口的接收缓存( S O _ R C V B U F插口选项)设置为 n。这可以直接影 响T C P通告的接收窗口的大小。对于 U D P,这个选项指明了可以接收 的最大的U D P数据报。 -S n 把插口的发送缓存( S O _ S N D B U F插口选项)设置为 n。对于U D P,这 个选项指明了可以发送的最大的 U D P数据报。 -U n 在向网络写了数字 n后进入T C P的紧急模式。写一个字节的数据以启动 紧急模式(2 0 . 8节)。 380使用TCP/IP详解 卷1:协议附录D 部分习题的解答 第1章 1.1 答案是:27-2(1 2 6)+21 4-2(16 382)+22 1-2(2 097 150)= 2 113 658。每一部分都 减去2是因为全0或全1网络I D是非法的。 1.2 图D - 1显示了直到1 9 9 3年8月的有关数据。 图D-1 宣布加入NSFNET的网络数 如果网络数继续呈指数增长的话,虚线估计了 2 0 0 0年可能达到的最大的网络数。 1.3 “自由地接收,保守地发送。” 第3章 3.1 不,任何网络I D为1 2 7的A类地址都是可行的,尽管大多数系统使用了 1 2 7 . 0 . 0 . 1。 3.2 k p n o有5个接口:3个点对点链路和 2 个以太网接口。 R 1 0有4个以太网接口。 g a t e w a y 有3个接口:2个点对点链路和1 个以太网接口。最后, n e t b有1个以太网接口和2个点对 点链路。 3.3 没有区别:作为一个没有再区分子网的 C类地址,它们都有一个 2 5 5 . 2 5 5 . 2 5 5 . 0的子网掩 码。 3.5 它是合法的,被称为非连续的子网掩码,因为其用于子网掩码的 1 6位是不连续的。但是 R F C建议反对使用非连续的子网掩码。 3.6 这是一个历史遗留问题。值是 1 0 2 4+5 1 2,但是打印的 M T U值包含了所有需要的首部字 节数。Solaris 2.2将回环接口的M T U设置为8 2 3 2(8 1 9 2+4 0),其中包含了8 1 9 2字节的用 户数据加上2 0字节的I P首部和2 0字节的T C P首部。 3.7 第一,数据报降低了路由器中对于连接状态的需求。第二,数据报提供了基本的构件, 在它的上面可以构造不可靠的( U D P)和可靠的( T C P)的运输层。第三,数据报代表 网络总数了最小的网络层假定,使得可以使用很大范围的数据链路层服务。 第4章 4.1 发出一条r s h命令与另一台主机建立一个 T C P连接。这样做引起在两个主机之间交换 I P数 据报。为此,在那台主机的 A R P缓存中必须有我们这台主机的登记项。因此,即使在执 行r s h命令之前,A R P缓存是空的,当r s h服务器执行a r p命令时,必须保证A R P缓存中 登记有我们这台主机。 4.2 保证你的主机上的A R P缓存中没有登记以太网上的某个叫作 f o o的主机。保证f o o引导时 发送一个免费A R P请求,也许是在 f o o引导时,在那台主机上运行 t c p d u m p。然后关闭 主机f o o,使用说明了t e m p选项的a r p命令,在你的系统的A R P缓存中为f o o输入一个不 正确的登记项。引导 f o o并在它启动好之后,察看主机的 A R P缓存,看看不正确的登记 项是不是已经被更正了。 4.3 阅读主机需求(Host Requirement)R F C的2 . 3 . 2 . 2节和本书中的11 . 9节。 4.4 假设当服务器关闭时,客户机保存了关于服务器的一个完整的 A R P登记项。如果我们继续 试图与(已关闭的)服务器联系,过了 2 0分钟以后,A R P将超时。最后,当服务器以另一 个新的硬件地址重启动。如果它没有发出一个免费 A R P,旧的、不再正确的A R P登记项仍 然存在于客户机上。我们将无法和在新硬件地址上的服务器联系直到我们手工删除这个 A R P登记项,或者在2 0分钟内停止与服务器联系的尝试。 第5章 5.1 一个单独的帧类型并不是必需的,因为图4 - 3中的o p字段对于所有的四个操作(A R P请求、 A R P应答、R A R P请求和R A R P应答)都有一个不同的值。但是实现一个 R A R P服务器, 独立于内核中的A R P服务器,更容易处理不同的帧类型字段。 5.2 每个R A R P服务器在发送一个响应之前可以延迟一个小的随机时间。 作为一个优化,可以指定一个 R A R P服务器为主服务器,其他的为次服务器。主服务器发 出响应不需要延迟,而次服务器发出响应则需要一个随机的延迟。 作为另一个优化,也是指定一个主 R A R P服务器,其他为次服务器。次服务器只对在一 个短时间段内发生的重复请求进行响应。这里假设出现重复请求的原因是由于主服务 器停机了。 第6章 6.1 如果在局域网线上有一百个主机,每个都可能在同一时刻发送一个 I C M P端口不可达的报 文。很多报文的传输都可能发生冲突(如果使用的是以太网),这将导致1秒或2秒的时间 里网络不可用。 6.2 它是一个“s h o u l d”。 6.3 如我们在图3 - 2所指出的,发送一个 I C M P差错总是将TO S置为0。发送一个I C M P查询请 求可以将TO S置为任何值,但是发送相应的应答必须将 TO S置为相同的值。 6.4 n e t s t a t-s是查看每个协议统计数据的常用方法。在一台收到了4 8 0 0万个I P数据报的S u n O S 4 . 1 . 1主机(g e m i n i)上,I C M P的统计为: 382使用TCP/IP详解,卷1:协议2 1个类型为1 0的报文是SunOS 4.1.1不支持的路由器的请求。 也可以使用 S N M P(图2 5 - 2 6),有些系统,如 Solaris 2.2,可以生成使用 S N M P变量名的 n e t s t a t-s的输出。 第7章 7.2 8 6字节除以9 6 0字节/秒,乘以2得到179.2 ms。当以这个速率运行 p i n g时,打印的值为 180 ms。 7.3 (8 6+4 8)除以9 6 0字节/秒,乘以2得到279.2 ms。另外的4 8字节是因为5 6字节的数据部 分的最后4 8字节必须忽略:0 x c 0是SLIP END字符。 7.4 C S L I P只压缩了T C P报文段的T C P首部和I P首部。它对p i n g使用的I C M P报文没有作用。 7.5 在一个S PA R C工作站 E L C上,对回环地址的p i n g操作产生一个1.310 ms的RT T,而对一 个主机的以太网地址的 p i n g操作产生一个1.460 ms的RT T。这个差值是由于以太网驱动 程序需要时间来判定这个数据报的目的地址是一个本地的主机。需要一个产生微秒级输 出的p i n g来验证这一点。 第8章 8.1 如果一个输入数据报的 T T L为0,做减一操作然后测试会将把 T T L设置为2 5 5,并且让数 据报继续传输。尽管一个路由器永远不会收到一个 T T L为0的数据报,但这种情况确实会 发生。 8.2 我们注意到t r a c e r o u t e在U D P数据报的数据部分存储了 1 2个字节,其中包含了数据报 发送的时间。然而,从图 6-9可以看出I C M P只返回了出错的I P数据报的头8个字节,实际 上这是8个字节的U D P首部。因此,I C M P的差错报文没有返回 t r a c e r o u t e存储的时间 值。t r a c e r o u t e保存了它发送分组的时间,当收到一个I C M P应答时,取出当时的时间, 把两个值相减就可以得出RT T。 回忆一下第7章中,p i n g在输出的I C M P回显请求中存储了时间,这个值被服务器回显了 回来。这样即使分组返回时失序, p i n g也能打印出正确的RT T。 8.3 第1行输出是正确的,并且标识了 R 1。下一个探测分组启动时将 T T L置为2,并且这个值 被R 1减1。当R 2收到这个分组时,把 T T L从1减为0,但是错误地将它传递给了 R 3。R 3看 见进入的T T L是0就将超时的分组发送回来。这就意味着第2行输出( T T L为2)标识了R 3, 而不是R 2。第3行输出正确地标识了 R 3。这个错误所表现出来的线索就是两个连续的输 附录D 部分习题的解答使用383出行标识了同一个路由器。 8.4 在这种情况下,T T L为1标识了R 1,T T L为2标识了R 2,T T L为3标识了R 3,但是当T T L为 4时,U D P数据报到达了目的地,其输入的 T T L为1。I C M P端口不可达报文生成了,但它 的T T L是1(错误地从进入的 T T L复制而来)。这个I C M P报文到了R 3,在那儿T T L被减1, 报文被丢弃。没有生成一个 I C M P超时报文,因为被丢弃的数据报是一个 I C M P的差错报 文(端口不可达)。类似的现象也出现在 T T L为5的探测分组,但这次输出的端口不可达 报文以T T L为2开始(进入的T T L),这个报文被传给 R 2,在那儿被丢弃。对应于 T T L为6 探测分组的端口不可达报文被传递给 R 1,在那儿被丢弃。最后,对应于 T T L为7探测分组 的端口不可达报文被送回了原地,到达时它的 T T L为1(t r a c e r o u t e认为一个T T L为0 或1的到达I C M P报文是有问题的,因此它在 RT T后面打印了一个惊叹号)。总之,T T L为 1、2和3的行正确地标识了 R 1、R 2和R 3,接下来的三行每个都包含三个超时,再接下来 的T T L为7的行标识了目的地。 8.5 它表明这些路由器都将一个I C M P报文的输出T T L设置为2 5 5,这是共同的。从n e t b输入的 2 5 5的T T L值是我们想要的,而从b u t c h输入的2 5 3的T T L值表明在b u t c h和n e t b之间可能 有一个未觉察的路由器。否则,在这个点上我们应该看到一个 T T L值为2 5 4的输入报文。 类似地,我们希望看到一个值为 2 5 2而不是2 4 9的、来自e n s s 1 4 2 . U T . w e s t n e t . n e t的 报文。这表明这些未觉察的路由器没有正确地处理向外输出的 U D P数据报,但它们都对返 回的I C M P报文正确地进行了T T L减1操作。 我们必须在查看输入的T T L时非常小心,因为有时候一个和我们想要的不同的值可能是由 于返回的I C M P报文采用了一条与输出 U D P数据报不同的路径。但是,在这个例子中证实 了我们所怀疑的— 当使用松源路由选项时,确实存在t r a c e r o u t e没有发现的未察觉的 路由器。 8.7 p i n g的客户把I C M P回显请求报文(图 7 - 1)的标识符字段设置为它的进程 I D。I C M P回 显应答报文包含同样值的标识符字段。每个客户都要查看这个返回的标识符字段,并且 只处理那些它发送过的报文。 t r a c e r o u t e客户将它的U D P源端口号设置为它的进程I D和3 2 7 6 8的逻辑或。因为返回的 I C M P报文总是包含产生错误的 I P数据报的前8个字节(图6 - 9),这8个字节包括了完整的 U D P首部,所以这个源端口号在 I C M P差错报文中被返回。 8.8 p i n g客户将I C M P回显请求报文的可选数据部分设置为分组发送的时间。这个可选的数 据必须在I C M P回显应答中返回。这样使得即使分组返回时失序,客户也能计算出精确的 回环时间。 t r a c e r o u t e客户不能这样操作,因为在I C M P差错报文中返回的只是U D P首部(图6 - 9), 没有U D P数据。因此,t r a c e r o u t e必须记住它发送一个请求的时间,等待应答,然后 计算两者的时间差。 这里显示了 p i n g和t r a c e r o u t e的另一个不同点: p i n g每秒发送一个分组,而不管是 否收到任何应答; t r a c e r o u t e发送一个请求,然后在发送下一个请求前等待一个应答 或者一个超时。 8.9 因为默认情况下Solaris 2.2从3 2 7 6 8开始使用临时的U D P端口,所以目的主机上的目的端 口已经被使用的机会更大。 384使用TCP/IP详解,卷1:协议第9章 9.1 当I C M P标准第1次发布时, RFC 792 [Postel 1981b]所述的划分子网技术还没有使用。另 外,使用一个网络重定向而不是 N个主机重定向(对于目的网络中的所有 N个主机)也节 省了路由表的空间。 9.2 这一项并不需要,但是如果把它删除了,所有到 s l i p的I P数据报将被发送到默认的路由 器(s u n),后者又将把它们送到路由器 b s d i。既然s u n将数据报从与接收数据报相同的 接口转发出去,它把一个 I C M P重定向到s v r 4。这样在s v r 4中又创建了我们删除过的同 样的路由表项,尽管这一次是因为重定向而创建的,而不是在引导时增加的。 9.3 当那个 4 . 2 B S D主机收到目的地址是 1 4 0 . 1 . 2 5 5 . 2 5 5的数据报,发现它有一个通往该网络 (1 4 0 . 1)的路由,因此就试图转发数据报。它发送一个 A R P广播来寻找 1 4 0 . 1 . 2 5 5 . 2 5 5。 这个A R P请求没有收到任何应答,所以这个数据报最终被丢弃。如果在网线上有很多这 样的4 . 2 B S D主机,每一个都在差不多同一时刻发送 A R P这个广播,将会暂时地阻塞网 络。 9.4 这次,每一个 A R P请求都收到一个应答,告诉每个 4 . 2 B S D主机向一个指定的硬件地址 (以太网广播)发送数据报。如果网线上有 k个这样的4 . 2 B S D主机,全部收到了它们自己 的A R P应答,使得每一个生成了另一个广播。每个主机都收到了每一个目的地址为 1 4 0 . 1 . 2 5 5 . 2 5 5的广播I P数据报,既然现在每个主机都有一个 A R P缓存项,这个数据报又 被转发给了广播地址。这个过程继续下去,就会产生一次以太网的熔毁 ( E t h e r n e t m e l t d o w n )。[Manber 1990] 描述了网络中另一种形式的链式反应。 第10章 10.1 路由表中有1 3条来自于 k p n o:除了1 4 0 . 2 5 2 . 1 0 1 . 0和1 4 0 . 2 5 2 . 1 0 4 . 0之外的所有g a t e w a y 直接相连的其他网络。 10.2 丢失的数据报中通告的2 5条路由需要6 0秒才能得到更新。这不成问题,因为一般来说一 条路由如果连续3分钟没有得到更新,R I P才会声明它失效。 10.3 R I P运行在U D P上,而U D P提供了U D P数据报中数据部分的一个可选的检验和( 11 . 3节)。 然而,O S P F运行在I P上,I P的检验和只覆盖了 I P首部,所以O S P F必须增加它自己的检 验和字段。 10.4 负载平衡增加了分组被失序交付的机会,并且很可能使得运输层计算的环回时间出错。 10.5 这叫作简单的分裂范围(split horizon)。 10.6 在图1 2 - 1中,我们显示了 1 0 0个主机的每一个都通过设备驱动程序、 I P层和U D P层来处 理这个广播的U D P数据报。当它们发现 U D P端口5 2 0没有被使用时,这个广播数据报才 最终被丢弃。 第11章 11.1 因为使用IEEE 802封装时,存在8个额外的首部字节,所以 1 4 6 5个字节的用户数据是引 起分片的最小长度。 11.3 对于I P来说有8 2 0 0字节的数据需要发送, 8 1 9 2字节的用户数据和 8个字节的U D P首部。 附录D 部分习题的解答使用385采用t c p d u m p记号,第1个分片是1 4 8 0 @ 0 +(1 4 8 0字节的数据,偏移为0,将“更多片” 比特置1)。第2个是1 4 8 0 @ 1 4 8 0 +,第3个是1 4 8 0 @ 2 9 6 0 +,第4个是1 4 8 0 @ 4 4 4 0 +,第5个 是1 4 8 0 @ 5 9 2 0 +,第6个是8 0 0 @ 7 4 0 0。1 4 8 0×5 + 800 = 8200,正好是要发送的字节。 11.4 每个1 4 8 0字节的数据报片被分成三小片:两个 5 2 8字节和一个4 2 4字节。小于5 3 2(5 5 2- 2 0)的8的最大倍数是5 2 8。8 0 0字节的数据报片被分成两小片:一个 5 2 8字节和一个2 7 2 字节。这样,原来8 1 9 2字节的数据报变成了S L I P链路上的1 7个帧。 11.5 不。问题是当应用程序超时重传时,重传产生的 I P数据报有一个新的标识字段。而重新 装配只针对那些具有相同标识字段的分段。 11.6 IP首部中的标识字段(4 7 9 4 2)是一样的。 11.7 第一,从图11 - 4我们看到 g e m i n i没有使能输出U D P的检验和。如果输出 U D P的检验和 没有被使能,这个主机上的操作系统( SunOS 4.1.1)就不会验证一个进入 U D P的检验 和。第二,大多数的 U D P通信量都是本地的,而不是 WA N的,因此没有服从所有的 WA N特征。 11.8 不严格的和严格的源站选路选项被复制到每一个数据报片中。时间戳选项和记录路由选 项没有被复制到每一个数据报片中— 它们只出现在第1个数据报片中。 11.9 不。在11 . 1 2节中,我们看到很多实现可以根据目的 I P地址、源I P地址和源端口号来过滤 送往一个给定U D P端口号的输入数据报。 第12章 12.1 广播本身不会增加网络通信量,但它增加了额外的主机处理时间。如果接收主机不正确 地响应了诸如 I C M P端口不可达之类的差错,那么广播也可能导致额外的网络通信量。 路由器一般不转发广播分组,而网桥一般转发,所以在一个桥接网络上的广播分组可能 比在一个路由网络上走得更远。 12.2 每个主机都收到了所有广播分组的一个副本。接口层收到了帧,把它传递给设备驱动程 序。如果类型字段指的是其他协议,设备驱动程序就会丢弃该帧。 12.3 首先执行n e t s t a t - r来看一下路由表,结果显示了所有接口的名字。然后对每个接口 执行i f c o n f i g(3 . 8节):标志指出了一个接口是否支持广播,如果支持,相应的广播 地址也会被输出。 12.4 伯克利演变的实现不允许对一个广播数据报进行分片。当我们说明了1 4 7 2字节的长度,产 生的I P数据报将是1 5 0 0字节,正好是以太网的M T U。不允许分片一个广播数据报是一个 策略上的决定— 没有技术上的原因(并不是想要减少广播分组的数目)。 12.5 依赖于1 0 0个主机上不同的以太网接口卡的多播支持,多播数据报可能被接口卡忽略, 或者被设备驱动程序丢弃。 第13章 13.1 生成随机数时要使用对于主机唯一的值。 I P地址和链路层地址是每个主机都应该不一样 的两个值。日期时间是一个不好的选择,尤其是在所有的主机都运行了一个类似于 N T P 的协议来同步它们的时钟的情况下。 13.2 他们增加了一个包括一个序号和一个时间戳的应用协议首部。 386使用TCP/IP详解,卷1:协议第14章 14.1 一个解析器总是一个客户,但一个名字服务器既是一个客户又是一个服务器。 14.2 问题被返回,它占用了前 4 4个字节。一个回答占用了剩下来的 3 1个字节:2个字节指向 域名的指针(即,指向问题中域名的一个指针),1 0字节固定长度的字段(类型、种类、 T T L 和资源长度),1 9字节的资源数据(一个域名)。注意到资源数据中的域名 (s v r 4 . t u c . n o a o . e d u .)没有共享问题( 3 4 . 1 3 . 2 5 2 . 1 4 0 . i n - a d d r . a r p a .) 中域名的后缀,所以不能使用一个指针。 14.3 将顺序颠倒意味着首先使用 D N S,如果使用D N S失败,然后才将参数翻转过来作为一个 点分十进制数。这就是说每次说明一个点分十进制数,都要使用 D N S,涉及一个名字服 务器。这是对资源的一种浪费。 14.4 RFC 1035的4 . 2 . 2节说明了在实际的D N S报文之前的两个字节长度的字段。 14.5 当一个名字服务器启动时,它一般从一个磁盘文件中读出一个根服务器列表(可能已经 过时了)。然后尝试和这些根服务器中的一个联系,请求根域的名字服务器记录(一个 N S的查询类型)。这个请求返回了当前最新的根服务器列表。启动磁盘文件中根服务器 项中至少需要一个是有效的。 14.6 InterNIC的注册服务每一周更新三次根服务器。 14.7 就像应用是不定的一样,解析器也是不定的。如果系统配置成使用多个名字服务器,而 且解析器是无状态的,那么解析器就不能记住不同的名字服务器的往返时间。这样定时 太短的解析器将会超时,引起不必要的重传。 14.8 对A记录的排序应该由解析器来执行,而不是名字服务器,因为解析器一般比服务器了解 更多的客户的网络拓扑(更新版本的B I N D提供了解析器对A记录排序的功能)。 第15章 15.1 送往广播地址的T F T P请求应该被忽略。正像 Host Requirements RFC所描述的,对一个 广播请求的响应可能产生一个非常严重的安全漏洞。但是,问题是并不是所有的实现和 A P I都对接收一个U D P数据报的进程提供了该数据报的目的地址( 11 . 1 2节)。因为这个 原因,很多T F T P服务器没有严格遵守这个限制。 15.2 不幸的是,R F C没有提到这个块数目环绕问题。具体实现时应该能够传输最大为33 553 920 (6 5 5 3 5×5 1 2)字节的文件。但是当文件的长度超过16 776 704(3 2 7 6 7×5 1 2)时,很多实 现都会失败,因为它们将块数目错误地表示为一个有符号的1 6位整数,而不是一个无符号 的整数。 15.3 这样简化了编写一个适合于只读内存的 T F T P客户的工作,因为服务器是引导文件的发 送者,所以服务器必须实现超时和重传机制。 15.4 利用它的停止等待协议,T F T P可以在每一次客户与服务器的往返过程中最多传输5 1 2字节 的数据。T F T P的最大吞吐量就是5 1 2字节除以客户与服务器之间的往返时间。在以太网上, 假设一个往返时间为3 ms,那么最大的吞吐量就是大约170 000字节/秒。 第16章 16.1 一个路由器可以转发一个 R A R P请求到路由器连接的其他网络上的任何一台主机上。但 附录D 部分习题的解答使用387是发送应答就成问题了,路由器还必须转发 R A R P应答。 B O O T P没有这个应答问题,因为应答的地址是路由器知道如何转发的一般 I P地址。问题 是R A R P只使用了链路层地址,路由器一般不知道在其他的、没有连接在路由器的网络上 主机的链路层地址。 16.2 它可能使用了自己的硬件地址。该地址应该是唯一的,在请求报文中设置,在应答中返 回。 第17章 17.1 除了U D P的检验和,其他都是必需的。 I P检验和只覆盖了I P首部,而其他字段都紧接着 I P首部开始。 17.2 源I P地址、源端口号或者协议字段可能被破坏了。 17.3 很多I n t e r n e t应用使用一个回车和换行来标记每个应用记录的结束。这是 NVT ASCII采 用的编码(2 6 . 4节)。另外一种技术是在每个记录之前加上一个记录的字节计数, D N S (习题1 4 . 4)和Sun RPC(2 9 . 2节)采用了这种技术。 17.4 就像我们在6 . 5节所看到的,一个I C M P差错报文必须至少返回引起差错的I P数据报中除了 I P首部的前8 个字节。当T C P收到一个I C M P差错报文时,它需要检查两个端口号以决定差 错对应于哪个连接。因此,端口号必须包含在T C P首部的前8个字节里。 17.5 TCP首部的最后有一些选项,但 U D P首部中没有选项。 第18章 18.1 I S N是一个32 bit的计数器,它在系统引导大约 9 . 5小时后从4 294 912 000环绕到8 7 0 4。 再过大约9 . 5小时它将环绕到 17 408,然后再过9 . 5小时是26 11 2,如此继续下去。因为 系统引导时 I S N从1开始,并且因为最低次序的数字在 4、8、2、6和0之间循环,所以 I S N应该总是一个奇数。 18.2 在第1种情况下,我们使用了 s o c k程序。默认情况下它把 U n i x的新行字符不作改变地进 行传输— 单个A S C I I字符0 1 2(八进制)。在第2种情况下,我们使用了 Te l n e t客户,它 把U n i x的新行字符转变为两个 A S C I I字符— 一个回车符(八进制 0 1 5)跟着一个换行 符(八进制0 1 2)。 18.3 在一个半关闭的连接上,一个端点已经发送了一个 F I N,正等待另一端的数据或者一个 F I N。一个半打开的连接是当一个端点崩溃了,而另一端还不知道的情况。 18.4 一个连接只有经过了已建立状态才能进入 2 M S L等待状态。 18.5 首先,日期服务器在将时间和日期写给客户之后对 T C P连接做一个主动关闭。这可以通 过s o c k程序打印的消息:“connection closed by peer.”表现出来。连接的客户端经历了 被动关闭的状态。这样就把一对插口置于服务器端的 T I M E _ WA I T状态,而不是在客户 端。 其次,正如在1 8 . 6节所示,大多数伯克利演变的实现都允许一个新的连接请求到达一个正 处于T I M E _ WA I T状态的一对插口,这也就是这里所发生的情况。 18.6 因为在一个已经关闭的连接上到达了一个 F I N,所以相应于这个F I N发送了一个复位。 18.7 拨号的一方做主动打开,电话振铃的一方做被动打开。不允许同时打开,但允许同时关 388使用TCP/IP详解,卷1:协议闭。 18.8 我们将只看到 A R P请求,而不是 TCP SYN报文段,但A R P请求将和图中具有相同的计 时。 18.9 客户在主机s o l a r i s上,服务器在主机 b s d i上。客户对服务器 S Y N的确认(A C K)和客 户的第一个数据段结合在一起(第 3行)。这种处理非常符合 T C P的规则,尽管大多数的 实现都没有这么做。接着,客户在等待它的数据的确认之前发送了它的 F I N(第4行)。 这样使得服务器可以在第5行同时确认客户数据和它的 F I N。 这次交互(将一个报文段从客户发送到服务器)需要 7个报文段,而正常的连接建立和 终止(图1 8 - 1 3),以及一个数据段和它的确认,需要 9个报文段。 18.10 首先,服务器对客户的 F I N的确认一般不会被延迟(我们在 1 9 . 3节讨论延迟的确认), 而是在F I N到达后立即发送。应用进程需要一些时间来接收 E O F,告诉它的T C P关闭它 这一端的连接。第二,服务器收到客户的 F I N后,并不一定要关闭它这一端的连接。就 像我们在1 8 . 5节中看到的,仍然可以发送数据。 1 8 . 11 如果一个产生R S T的到达报文段有一个 A C K字段,那么R S T的序号就是到达的 A C K字 段。第6行中值为1的A C K是相对于第2行中的2 6 3 6 8 0 0 1的I S N。 18.12 参见 [Crowcroft et al. 1992]中对分层的评论。 18.13 发出了5个查询。假设有3个分组用于建立连接,1个用于查询,1个用于确认查询,1个 用于响应, 1个用于确认响应, 4个用于终止连接。这就是说每次查询需要 11个分组, 总共需要5 5个分组。使用U D P则可以减少到1 0个分组。 如果对查询的确认和响应结合在一起,每个查询需要的分组可以减少到 1 0个(1 9 . 3节)。 18.14 限制是每秒2 6 8个连接:最大数目的T C P端口号(6 5 5 3 6-1024 = 64512,忽略知名端口) 除以T I M E _ WA I T状态的2 M S L。 18.15 重复的F I N会得到确认,2 M S L定时器重新开始。 18.16 在T I M E _ WA I T状态中收到一个 R S T引起状态过早地终止。这就叫作 T I M E _ WA I T断开 ( a s s a s s i n a t i o n )。RFC1337 [Braden 1992a]仔细讨论了这个现象,并显示了潜在的问题。 这个R F C提出的简单的修改就是在T I M E _ WA I T状态时忽略R S T段。 18.17 它是在具体实现不支持半关闭连接的时候。一旦应用进程引起发送一个 F I N,应用进程 就不能再从这个连接读数据了。 18.18 不。输入的数据段通过源 I P地址、源端口号、目的 I P地址和目的端口号进行区分。在 1 8 . 11节中我们看到对于输入的连接请求,一个 T C P服务器一般可以通过目的 I P地址来 拒绝接收。 第19章 19.1 应用程序的两个写操作,跟着一个读操作,引起了迟延,因为 N a g l e算法很可能被激活。 第一个报文段(包含 8个字节的数据)被发送后,在发送后面 1 2个字节的数据之前必须 等待第一个报文段的确认。如果服务器实现了延迟的确认,在收到这个确认之前,可能 会有一个达到200 ms的时延(加上RT T)。 19.2 假设5个字节的C S L I P首部(I P和T C P)和两个字节的数据,这些段通过 S L I P链路的RT T 大约是14.5 ms。我们要加上通过以太网的 RT T(一般是5~10 ms),加上在s u n和b s d i 附录D 部分习题的解答使用389上的选路时间。因此,观察到的时间看起来是正确的。 19.3 在图1 9 - 6中,第6和第9报文段之间的时间是5 3 3 m s。在图1 9 - 8中,第8和第1 2报文段之间 的时间是2 7 2 m s(我们测量了F 2键的时间,而不是F 1键,因为F 1键的第1个回显在第2个 图中丢掉了)。 第20章 20.1 字节号0是S Y N,字节号8 1 9 3是F I N。S Y N和F I N在序号空间里各占用了一个字节。 20.2 应用程序的第1个写操作引起置位 P U S H标志发送第1个报文段。因为 B S D / 3 8 6总是使用 慢启动,它在发送更多数据之前等待第1个确认。在这段时间里,下面三个写操作发生 了,发送T C P把要发送的数据缓存了起来。因为在缓存中有更多的数据要发送,下面的 三个报文段没有包含 P U S H标志。最后,慢启动跟上了应用程序的写操作,每个应用程 序的写操作引起了发送一个报文段,并且因为那个报文段是缓存中最后的一个,所以设 置P U S H标志。 20.3 为容量求解带宽迟延方程式,第一种情况是 1 9 2 0字节,卫星的情况是2 0 6 2字节。看起来 T C P只声明了一个2 0 4 8字节的窗口。 一个大于1 6 0 0 0字节的窗口应该能够使卫星链路饱和。 20.4 不,因为T C P超时之后可能重新对数据进行分组,就像我们将在 2 1 . 11节中看到的。 20.5 作为应用进程读数据的结果,第 1 5报文段是T C P模块自动发送的窗口更新,它引起窗口 的打开。这类似于图中的第 9报文段。但是,第 1 6报文段是应用进程关闭它这一端连接 的结果。 20.6 这可能引起发送者以比网络实际能够处理的更快的速率向网络发送分组。这叫作确认压 缩(ACK compression)或确认粉碎(ACK smashing) [Mogul 1993, 15.8.13节]。这个引用显 示了在I n t e r n e t上发生的A C K压缩,尽管它很少会导致拥塞。 第21章 21.1 下一个超时设定是4 8秒:0+4×1 2。因子4是指数退避的下一个乘数。 21.2 看起来S V R 4在计算RTO时仍然使用了因子2D,而不是4D。 21.3 T F T P使用的停止等待协议被限制为每个往返过程传送 5 1 2字节的数据。3 2 7 6 8 / 5 1 2×1 . 5 是9 6秒。 21.4 显示了4个报文段,编号为 1、2、3和4。假设接收的顺序是 1、3、2和4,接收者产生的 确认将是ACK 1(一个正常的确认),ACK 1(当收到了报文段3,失序后一个重复的确 认),当收到了报文段 2后的ACK 3(对报文段2和报文段3的确认),然后是ACK 4。这 儿产生了一个重复的确认。如果接收的顺序是 1、3、4和2,将会产生两个重复的确认。 21.5 不,因为斜率仍然是向上和向右,不是向下。 21.6 参见图E - 1。 21.7 在图2 1 - 2中,报文段包含2 5 6个字节的数据,在s l i p和b s d i之间的9600 b/s的C S L I P链 路传输大约需要250 ms。假定数据段没有在b s d i和v a n g o g h之间的某个地方排队,它 们分别需要大约 250 ms到达v a n g o g h。因为这个时间超过了延迟确认定时器的 200 ms 时间,当下一个延迟确认定时器超时时,每个报文段得到确认。 390使用TCP/IP详解,卷1:协议第22章 22.1 主机b s d i上的确认很可能都要被延迟,因为没有理由立即发送它们。这就是为什么相 对次数有一个0 . 1 7 0和0 . 3 7 0的小数部分。看起来b s d i上200 ms的定时器在s u n上同样的 定时器之后18 ms才开始计时。 22.2 F I N标志,和S Y N标志一样,在序号空间占据了 1个字节。通知的窗口看起来小了一个 字节,因为T C P允许F I N标志在序号空间占用1个字节的空间。 第23章 23.1 通常激活k e e p a l i v e选项比显式地编写应用程序探测报文更容易; k e e p a l i v e探测报文比应 用程序探测报文占用更少的网络带宽(因为 k e e p a l i v e探测报文和应答不包含任何数 据);如果连接不是空闲的,就不会发送探测报文。 23.2 k e e p a l i v e选项可能会由于一个临时性的网络中断而引起一个非常好的连接断开;发送探 测报文的间隔(2小时)一般不可以根据应用程序进行配置。 第24章 24.1 它意味着发送T C P支持窗口扩缩选项,但这个连接并不需要扩缩它的窗口。另一端(接 收这个S Y N的)可以说明一个窗口扩缩因子(可以是 0或非0)。 24.2 64 000:接收缓存大小(128 000)向右移1位。55 000:接收缓存(220 000)向右移2位。 24.3 不。问题是确认没有可靠地交付(除非它们被数据捎带在一起发送),因此,一个确认 上的扩缩改变可能会丢失。 24.4 23 2×8 / 1 2 0等于286 Mb/s,2 . 8 6倍于F D D I数据率。 24.5 每个T C P将不得不记住从每个主机的任何一个连接上收到的上一个时间戳。阅读 R F C 1 3 2 3的附录B . 2以了解进一步的细节。 24.6 应用程序必须在和另一端建立连接之前设置接收缓存的大小,因为窗口扩缩选项在初始 的S Y N段中发送。 24.7 如果接收者每次确认第2个数据报文段,吞吐量是 1 118 881字节/秒。若使用一个6 2个报 文段的窗口,每3 1个报文段确认一次,则数值是 1 158 675。 24.8 使用这个选项,确认中回显的时间戳总是来自于引起确认的报文段。对哪个重传的报文段 进行确认没有疑问,但仍然需要K a r n算法的另一部分,即处理重传的指数退避。 24.9 接收T C P对数据进行排队,但只有完成了三次握手后,数据才能传递给应用程序:当接 收T C P进入了E S TA B L I S H状态。 24.10 交换了5个报文段: 1) 客户到服务器:S Y N,数据(请求)和F I N。服务器必须像上个习题所述的一样对数 据进行排队。 2) 服务器到客户:S Y N和对客户S Y N的确认。 3) 客户到服务器:对服务器的 S Y N的确认和客户的F I N(再次)。这样使得服务器进入 已建立状态,并且来自报文段 1的排队数据被传递给服务器应用程序。 4) 服务器到客户:客户 F I N的确认(它也确认了客户的数据)、数据(服务器的应答) 附录D 部分习题的解答使用391和服务器的F I N。这里假定了 S P T足够短以允许这个延迟的确认。当客户 T C P收到这个 报文段,就将应答传递给客户端的应用程序,但是整个时间是 RT T加上S P T的两倍。 5) 客户到服务器:对服务器F I N的确认。 2 4 . 11 每秒16 128次交互(64 512除以4)。 24.12 使用T / T C P的交互时间不可能比两个主机之间交换一个 U D P数据报所需的时间短。因 为T / T C P涉及了U D P没有做的状态处理,所以T / T C P总是要花更多的时间。 第25章 25.1 如果一个系统运行了一个管理进程和一个代理进程,它们很可能是不同的进程。管理进 程在U D P端口1 6 2监听t r a p告警,代理进程在 U D P端口1 6 1等待请求。如果 t r a p告警和 S N M P请求使用了同样的端口,将很难区分管理进程和代理进程。 25.2 参考2 5 . 7节中的“表访问(Table Access)”部分。 第26章 26.1 我们预期从服务器来的第 2、4和9报文段将被延迟。第 2和第4报文段之间的时间差是 190.7 ms,第2和第9报文段之间的时间差是400.7 ms。 从客户到服务器的所有确认看起来都被延迟:第 6、11、1 3、1 5、1 7和1 9报文段。从第 6报文段开始的最后5个时间差是4 0 0 . 0、6 0 0 . 0、8 0 0 . 0、1 0 0 0 . 0和2.600 ms。 26.2 如果连接的一个端点处于T C P的紧急模式,每次收到一个报文段,就会发送一个报文段。 这个报文段没有告诉接收者任何新的东西(例如,它不是对新数据的确认),它也不包 含数据,它只是重申进入了紧急模式。 26.3 只有 5 1 2个这样的保留端口( 5 1 2 ~ 1 0 2 3),限制了一个主机只能有 5 1 2个远程登录的 (R l o g i n)客户。在实际生活中,这个限制一般小于 5 1 2个,因为在这个范围中的一些端 口号被不同的服务器,如远程登录服务器,用作了知名端口。 T C P的限制是一对插口定义的一个连接( 4元组)必须是唯一的。因为 R l o g i n服务器总 是使用了同样的知名端口( 5 1 3),一台主机上多个R l o g i n客户只有在它们和不同的服务 器主机相连接时才可以使用相同的保留端口。然而, R l o g i n客户没有采用重用保留端口 的技术。如果使用了这种技术,理论限制就是在同一时刻最多有 5 1 2个R l o g i n客户和同 一个的服务器主机相连。 第27章 27.1 当一对插口处于 2 M S L等待另一端状态时,理论上不能建立连接。然而,实际上,在 1 8 . 6节中我们看到大多数伯克利演变的实现确实为一个处于 T I M E _ WA I T状态的连接接 受了一个新的S Y N。 27.2 这些行不是以3个数字作为应答代码开始的服务器应答的一部分,因此它们不可能来自 于服务器。 第28章 28.1 一个域文字 (domain literal)是在一对方括号里的点分十进制 I P地址。例如: m a i l 392使用TCP/IP详解,卷1:协议r s t e v e n s @ [ 1 4 0 . 2 5 2 . 1 . 5 4 ]。 28.2 6个来回:H E L O命令、M A I L、R C P T、D ATA报文主体和Q U I T。 28.3 这是合法的,称为流水线技术 (pipelining) [Rose 1993,4 . 4 . 4节]。不幸的是,有一些脑 子坏了(b r a i n - d a m a g e d)的S M T P接收者实现,每处理完一条命令就要清除它们的输入 缓存,使得这种技术不可用。如果使用了这种技术,客户自然不能丢弃报文直到所有的 应答都已检查过,确信报文已被服务器接受了。 28.4 考虑习题2 8 . 2的前5个网络上的往返。每个都是一个小命令(很可能是只有一个报文段), 对网络几乎没有负载。如果所有 5个都没有重传地送到了服务器,当报文主体发送时, 拥塞窗口可能是6个报文段。如果报文主体很大,客户可能一次发送前 6个报文段,造成 网络可能来不及处理。 28.5 更新版本的B I N D使用同样的值来正移M X记录,作为平衡负载的一种方式。 第29章 29.1 不,因为t c p d u m p不能从其他U D P数据报中区别 R P C请求或应答。它只有在源端口号 或目的端口号为2 0 4 9时,才将U D P数据报的内容理解为 N F S分组。随机的R P C请求和应 答可以使用两个端点上的一个临时的端口号。 29.2 回忆一下1 . 9节中,一个进程必须有超级用户权限才能给自己分配一个小于 1 0 2 4的端口 号(一个知名端口)。尽管这对于系统提供的服务器没问题,如 Te l n e t服务器、F T P服务 器、和端口映射器,但我们不想给所有的 R P C服务器提供这个权限。 29.3 这个例子中的两个概念是客户忽略那些服务器应答,如果这些应答不具有客户正在等待 的X I D;U D P对收到的数据报进行排队(队列长度有一个上限),直到应用进程读取了 数据报。另外,X I D不会在超时和重传时改变,它只在调用另一个服务器过程时改变。 客户s t u b执行的事件为:时刻 0:发送请求1;时刻4:超时并重传请求 1;时刻5:接 收服务器应答 1,将应答返回给应用程序;时刻 5:发送请求2;时刻9:超时并重传请 求2;时刻1 0:收到服务器的应答 1,但因为我们在等待应答 2,所以忽略它;时刻 11: 收到服务器的应答2,将应答返回给应用程序。 服务器的事件如下:时刻 0:收到请求1,启动操作;时刻 5:发送应答1;时刻5:收到 请求1(来自于客户在时刻 4的重传),启动操作;时刻 1 0:发送应答1;时刻1 0:收到 请求2(来自于客户在时刻 5的重传),启动操作;时刻 11:发送应答2;时刻11:收到 请求2(来自于客