《TCP/IP详解 卷1:协议》学习笔记(未完待续)_tcpip详解卷一-程序员宅基地

技术标签: 网络  学习笔记  

从书籍摘录,加上了自己的经验,仅用于学习,如有侵权请联系删除。

全书在线阅读地址:《TCP/IP详解 卷1:协议》在线阅读版(全网唯一) - 即时通讯开发者社区!

第一章 概述

1.1分层

1.链路层(数据链路层、网络接口层)

通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡。它们一起处理与电缆(或其他任何传输媒介)的物理接口细节。

2.网络层(互联网层)

处理分组在网络中的活动。网络层协议包括IP协议(网际协议)ICMP协议(Internet互联网控制报文协议),以及IGMP协议(Internet组管理协议)

3.运输层

为两台主机上的应用程序提供端到端的通信。TCP(传输控制协议)UDP(用户数据报协议)

TCP两台主机提供高可靠性的数据通信。它所做的工作包括:把应用程序交给它的数据,分成合适的小块交给下面的网络层,确认接收到的分组,设置发送最后确认分组的超时时钟等。由于运输层提供了高可靠性的端到端的通信,因此应用层可以忽略所有这些细节。

UDP则为应用层提供一种非常简单的服务。它只是把称作数据报的分组从一台主机发送到另一台主机,但并不保证该数据报能到达另一端。任何必需的可靠性必须由应用层来提供。

4.应用层

负责处理特定的应用程序细节。

• Telnet远程登录。

• FTP文件传输协议。

• SMTP简单邮件传送协议。

• SNMP简单网络管理协议。

TCP/IP协议族是一组不同的协议组合在一起构成的协议族。尽管通常称该协议族为TCP/IP,但TCP和IP只是其中的两种协议而已(该协议族的另一个名字是Internet协议族(Internet Protocol Suite))。

1.2TCP/IP的分层

UDP为应用程序发送和接收数据报。

一个数据报是指从发送方传输到接收方的一个信息单元(例如,发送方指定的一定字节数的信息)。

UDP是不可靠的,它不能保证数据报能安全无误地到达最终目的。

IP是网络层上的主要协议,同时被TCP和UDP使用。

TCP和UDP的每组数据都通过端系统和每个中间路由器中的IP层在互联网中进行传输。

在TCP/IP中,网络层和运输层之间的区别是最为关键的:网络层(IP)提供点到点的服务,而运输层(TCP和UDP)提供端到端的服务。

ICMP是IP协议的附属协议。IP层用它来与其他主机或路由器交换错误报文和其他重要信息。

IGMP是Internet组管理协议。它用来把一个UDP数据报多播到多个主机。广播(把一个UDP数据报发送到某个指定网络上的所有主机)

ARP(地址解析协议)和RARP(逆地址解析协议)是某些网络接口(如以太网和令牌环网)使用的特殊协议,用来转换IP层和网络接口层使用的地址。

1.3互联网的地址

互联网上的每个接口必须有一个唯一的Internet地址(也称作IP地址)。IP地址长32 bit。

这些 32 位的地址通常写成四个十进制的数,其中每个整数对应一个字节。这种表示方法称作“点分十进制表示法(Dotted decimal notation)”。例如一个 B 类地址,它表示为: 140.252.13.33。

1.4域名系统

在TCP/IP领域中,域名系统(DNS)是一个分布的数据库,由它来提供IP地址和主机名之间的映射信息。

1.5封装

TCP传给IP的数据单元称作TCP报文段或简称为TCP段(TCP segment)。IP传给网络接口层的数据单元称作IP数据报(IP datagram)。通过以太网传输的比特流称作帧(Frame)。

以太网数据帧的物理特性是其长度必须在46~1500字节之间。

UDP数据与TCP数据基本一致。唯一的不同是UDP传给IP的信息单元称作UDP数据报(UDP datagram),而且UDP的首部长为8字节。

由于TCP、UDP、ICMP和IGMP都要向IP传送数据,因此IP必须在生成的IP首部中加入某种标识,以表明数据属于哪一层。为此,IP在首部中存入一个长度为8bit的数值,称作协议域。1表示为ICMP协议,2表示为IGMP协议,6表示为TCP协议,17表示为UDP协议。

许多应用程序都可以使用TCP或UDP来传送数据。运输层协议在生成报文首部时要存入一个应用程序的标识符。TCP和UDP都用一个16bit的端口号来表示不同的应用程序。TCP和UDP把源端口号目的端口号分别存入报文首部中。

网络接口分别要发送和接收IP、ARP和RARP数据,因此也必须在以太网的帧首部中加入某种形式的标识,以指明生成数据的网络层协议。为此,以太网的帧首部也有一个16 bit的帧类型域

1.6分用

1.7 客户-服务器模型

大部分网络应用程序在编写时都假设一端是客户,另一端是服务器,其目的是为了让服务器为客户提供一些特定的服务。可以将这种服务分为两种类型:重复型或并发型

重复型服务器通过以下步骤进行交互:

重复型服务器主要的问题发生在I2状态。在这个时候,它不能为其他客户机提供服务。

并发型服务器采用以下步骤:

并发服务器的优点在于它是利用生成其他服务器的方法来处理客户的请求。也就是说,每个客户都有它自己对应的服务器。如果操作系统允许多任务,那么就可以同时为多个客户服务。

一般来说,TCP服务器是并发的,而UDP服务器是重复的,但也存在一些例外。

1.8 端口号

服务器一般都是通过知名端口号来识别的。

对于每个TCP/IP实现来说,FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69。任何TCP/IP实现所提供的服务都用知名的1~1023之间的端口号。

第二章 链路层

2.1 引言

在TCP/IP协议族中,链路层主要有三个目的:

(1)为IP模块发送和接收IP数据报;

(2)为ARP模块发送ARP请求和接收ARP应答;

(3)为RARP发送RARP请求和接收RARP应答。

2.2 以太网和IEEE 802封装

2.3 SLIP:串行线路IP

SLIP的全称是Serial Line IP。它是一种在串行线路上对IP数据报进行封装的简单形式。

SLIP协议定义的帧格式:

SLIP是一种简单的帧封装方法,还有一些值得一提的缺陷:

  1. 每一端必须知道对方的IP地址。没有办法把本端的IP地址通知给另一端。
  2. 数据帧中没有类型字段(类似于以太网中的类型字段)。如果一条串行线路用于SLIP,那么它不能同时使用其他协议。
  3. SLIP没有在数据帧中加上检验和(类似于以太网中的CRC字段)。如果SLIP传输的报文被线路噪声影响而发生错误,只能通过上层协议来发现(另一种方法是,新型的调制解调器可以检测并纠正错误报文)。这样,上层协议提供某种形式的CRC就显得很重要。

2.4 PPP:点对点协议

PPP包括以下三个部分:

  1. 在串行链路上封装IP数据报的方法。PPP既支持数据为8位和无奇偶检验的异步模式(如大多数计算机上都普遍存在的串行接口),还支持面向比特的同步链接。
  2. 建立、配置及测试数据链路的链路控制协议(LCP:Link Control Protocol)。它允许通信双方进行协商,以确定不同的选项。
  3. 针对不同网络层协议的网络控制协议(NCP:Network Control Protocol)体系。当前RFC定义的网络层有IP、OSI网络层、DECnet以及AppleTalk。例如,IP NCP允许双方商定是否对报文首部进行压缩,类似于CSLIP(缩写词NCP也可用在TCP的前面)。

每一帧都以标志字符0x7e开始和结束。紧接着是一个地址字节,值始终是0xff,然后是一个值为0x03的控制字节

接下来是协议字段,类似于以太网中类型字段的功能。当它的值为0x0021时,表示信息字段是一个IP数据报;值为0xc021时,表示信息字段是链路控制数据;值为0x8021时,表示信息字段是网络控制数据。

CRC字段(或FCS,帧检验序列)是一个循环冗余检验码,以检测数据帧中的错误。

  1. 当遇到字符0x7e时,需连续传送两个字符:0x7d和0x5e,以实现标志字符的转义。
  2. 当遇到转义字符0x7d时,需连续传送两个字符:0x7d和0x5d,以实现转义字符的转义。
  3. 默认情况下,如果字符的值小于0x20(比如,一个ASCII控制字符),一般都要进行转义。例如,遇到字符0x01时需连续传送0x7d和0x21两个字符(这时,第6个比特取补码后变为1,而前面两种情况均把它变为0)。

PPP比SLIP具有下面这些优点:

(1)PPP支持在单根串行线路上运行多种协议,不只是IP协议;

(2)每一帧都有循环冗余检验;

(3)通信双方可以进行IP地址的动态协商(使用IP网络控制协议);

(4)与CSLIP类似,对TCP和IP报文首部进行压缩;

(5)链路控制协议可以对多个数据链路选项进行设置。为这些优点付出的代价是在每一帧的首部增加3个字节,当建立链路时要发送几帧协商数据,以及更为复杂的实现。

2.5 环回接口

允许运行在同一台主机上的客户程序和服务器程序通过TCP/IP进行通信。

  1. 传给环回地址(一般是127.0.0.1)的任何数据均作为IP输入。
  2. 传给广播地址或多播地址的数据报复制一份传给环回接口,然后送到以太网上。这是因为广播传送和多播传送的定义(第12章)包含主机本身。
  3. 任何传给该主机IP地址的数据均送到环回接口。

2.6最大传输单元MTU

第三章 IP:网际协议

3.1 引言

IP提供不可靠、无连接的数据报传送服务

不可靠(unreliable)的意思是它不能保证IP数据报能成功地到达目的地。IP仅提供最好的传输服务。如果发生某种错误时,如某个路由器暂时用完了缓冲区,IP有一个简单的错误处理算法:丢弃该数据报,然后发送ICMP消息报给信源端。任何要求的可靠性必须由上层来提供(如TCP)。

无连接(connectionless)这个术语的意思是IP并不维护任何关于后续数据报的状态信息。每个数据报的处理是相互独立的。这也说明,IP数据报可以不按发送顺序接收。如果一信源向相同的信宿发送两个连续的数据报(先是A,然后是B),每个数据报都是独立地进行路由选择,可能选择不同的路线,因此B可能在A到达之前先到达。

3.1 IP首部

最高位在左边,记为0bit;最低位在右边,记为31 bit。

4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15 bit,然后16~23 bit,最后是24~31 bit。这种传输次序称作big endian字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序

以其他形式存储二进制整数的机器,如little endian格式,则必须在传输数据之前把首部转换成网络字节序

目前的协议版本号是4,因此IP有时也称作IPv4

服务类型(TOS)字段包括一个3bit的优先权子字段(现在已被忽略),4bit的TOS子字段1bit未用位但必须置0。4bit的TO S分别代表:最小时延、最大吞吐量、最高可靠性和最小费用。4bit中只能置其中1bit。如果所有4bit均为0,那么就意味着是一般服务。

Telnet和Rlogin这两个交互应用要求最小的传输时延,因为人们主要用它们来传输少量的交互数据。

另一方面,FTP文件传输则要求有最大的吞吐量

最高可靠性被指明给网络管理(SNMP)和路由选择协议。

用户网络新闻(Usenet news, NNTP)是唯一要求最小费用的应用。

总长度字段是指整个IP数据报的长度,以字节为单位。利用首部长度字段和总长度字段,就可以知道IP数据报中数据内容的起始位置和长度。

标识字段唯一地标识主机发送的每一份数据报。通常每发送一份报文它的值就会加1。

TTL(time-to-live)生存时间字段设置了数据报可以经过的最多路由器数。它指定了数据报的生存时间。TTL的初始值由源主机设置(通常为32或64),一旦经过一个处理它的路由器,它的值就减去1。当该字段的值为0时,数据报就被丢弃,并发送ICMP报文通知源主机。

首部检验和字段是根据IP首部计算的检验和码。它不对首部后面的数据进行计算。ICMP、IGMP、UDP和TCP在它们各自的首部中均含有同时覆盖首部和数据检验和码。

计算一份数据报的IP检验和:

首先把检验和字段置为0。然后,对首部中每个16 bit进行二进制反码求和(整个首部看成是由一串16 bit的字组成),结果存在检验和字段中

当收到一份IP数据报后,同样对首部中每个16 bit进行二进制反码的求和。由于接收方在计算过程中包含了发送方存在首部中的检验和,因此,如果首部在传输过程中没有发生任何差错,那么接收方计算的结果应该为全1。如果结果不是全1(即检验和错误),那么IP就丢弃收到的数据报。但是不生成差错报文,由上层去发现丢失的数据报并进行重传。

每一份IP数据报都包含源IP地址目的IP地址

3.3 IP路由选择

IP路由选择主要完成以下这些功能:

  1. 搜索路由表,寻找能与目的IP地址完全匹配的表目(网络号和主机号都要匹配)。如果找到,则把报文发送给该表目指定的下一站路由器或直接连接的网络接口(取决于标志字段的值)。
  2. 搜索路由表,寻找能与目的网络号相匹配的表目。如果找到,则把报文发送给该表目指定的下一站路由器或直接连接的网络接口(取决于标志字段的值)。目的网络上的所有主机都可以通过这个表目来处置。例如,一个以太网上的所有主机都是通过这种表目进行寻径的。这种搜索网络的匹配方法必须考虑可能的子网掩码。关于这一点我们在下一节中进行讨论。
  3. 搜索路由表,寻找标为“默认(default)”的表目。如果找到,则把报文发送给该表目指定的下一站路由器。如果上面这些步骤都没有成功,那么该数据报就不能被传送。

3.4 子网寻址

把IP地址看成由单纯的一个网络号、一个子网号和一个主机号。

3.5 子网掩码

除了IP地址以外,主机还需要知道有多少比特用于子网号多少比特用于主机号。这是在引导过程中通过子网掩码来确定的。这个掩码是一个32 bit的值,其中值为1的比特留给网络号和子网号,为0的比特留给主机号。

子网掩码经常用十六进制来表示。

给定IP地址和子网掩码以后,主机就可以确定IP数据报的目的是:(1)本子网上的主机;(2)本网络中其他子网中的主机;(3)其他网络上的主机。如果知道本机的IP地址,那么就知道它是否为A类、B类或C类地址(从IP地址的高位可以得知),也就知道网络号和子网号之间的分界线。而根据子网掩码就可知道子网号与主机号之间的分界线

3.6 特殊情况的IP地址

0表示所有的比特位全为0;

-1表示所有的比特位全为1;

netid、subnetid和hostid分别表示不为全0或全1的对应字段。

子网号栏为空表示该地址没有进行子网划分。

表的头两项是特殊的源地址,中间项是特殊的环回地址,最后四项是广播地址。

3.7 一个子网的例子

3.8 ifconfig命令

命令一般在引导时运行,以配置主机上的每个接口。

3.9 netstat命令

3.10 IP的未来

第4章 ARP:地址解析协议

4.1 引言

ARP为IP地址到对应的硬件地址之间提供动态映射。一般应用程序用户或系统管理员不必关心。

RARP是被那些没有磁盘驱动器的系统使用(一般是无盘工作站或X终端),它需要系统管理员进行手工设置。

4.2 一个例子

4.3 ARP高速缓存

ARP高效运行的关键是由于每个主机上都有一个ARP高速缓存。这个高速缓存存放了最近Internet地址到硬件地址之间的映射记录。高速缓存中每一项的生存时间一般为20分钟,起始时间从被创建时开始算起。

4.4 ARP的分组格式

以太网报头中的前两个字段是以太网的源地址和目的地址。目的地址为全1的特殊地址是广播地址。电缆上的所有以太网接口都要接收广播的数据帧。

两个字节长的以太网帧类型表示后面数据的类型。对于ARP请求或应答来说,该字段的值为0x0806。

硬件类型字段表示硬件地址的类型。它的值为1即表示以太网地址。协议类型字段表示要映射的协议地址类型。它的值为0x0800即表示IP地址。它的值与包含IP数据报的以太网数据帧中的类型字段的值相同。

硬件地址长度和协议地址长度分别指出硬件地址和协议地址的长度,以字节为单位。对于以太网上IP地址的ARP请求或应答来说,它们的值分别为6和4。

操作字段指出四种操作类型,它们是ARP请求(值为1)、ARP应答(值为2)、RARP请求(值为3)和RARP应答(值为4)。这个字段必需的,因为ARP请求和ARP应答的帧类型字段值是相同的

4.5 ARP举例

4.5.1 一般的例子

4.5.2 对不存在主机的ARP请求

4.5.3 ARP高速缓存超时设置

4.6 ARP代理

如果ARP请求是从一个网络的主机发往另一个网络上的主机,那么连接这两个网络的路由器就可以回答该请求,这个过程称作委托ARP或ARP代理(Proxy ARP)。

4.7 免费ARP

免费ARP可以有两个方面的作用:

  1. 一个主机可以通过它来确定另一个主机是否设置了相同的IP地址。主机bsdi并不希望对此请求有一个回答。但是,如果收到一个回答,那么就会在终端日志上产生一个错误消息“以太网地址:a:b:c:d:e:f发送来重复的IP地址”。这样就可以警告系统管理员,某个系统有不正确的设置。
  2. 如果发送免费ARP的主机正好改变了硬件地址(很可能是主机关机了,并换了一块接口卡,然后重新启动),那么这个分组就可以使其他主机高速缓存中旧的硬件地址进行相应的更新。一个比较著名的ARP协议事实[Plummer 1982]是,如果主机收到某个IP地址的ARP请求,而且它已经在接收者的高速缓存中,那么就要用ARP请求中的发送端硬件地址(如以太网地址)对高速缓存中相应的内容进行更新。主机接收到任何ARP请求都要完成这个操作(ARP请求是在网上广播的,因此每次发送ARP请求时网络上的所有主机都要这样做)。

4.8 arp命令

参数-a来显示ARP高速缓存中的所有内容。

超级用户可以用选项-d来删除ARP高速缓存中的某一项内容。

选项-s来增加高速缓存中的内容。

位于命令行末尾的关键字pub和-s选项一起,可以使系统起着主机ARP代理的作用。

第5章 RARP:逆地址解析协议

5.1引言

5.2 RARP的分组格式

RARP分组的格式与ARP分组基本一致(见图4-3)

它们之间主要的差别是RARP请求或应答的帧类型代码为0x8035,而且RARP请求的操作代码为3,应答操作代码为4

5.3 RARP举例

RARP请求是广播方式(第1行),而第2行的RARP应答是单播方式

TFTP表示简单文件传送协议。

5.4 RARP服务器的设计

5.4.1 作为用户进程的RARP服务器

RARP服务器的复杂性在于,服务器一般要为多个主机(网络上所有的无盘系统)提供硬件地址到IP地址的映射。该映射包含在一个磁盘文件中(在Unix系统中一般位于/etc/ethers目录中)。由于内核一般不读取和分析磁盘文件,因此RARP服务器的功能就由用户进程来提供,而不是作为内核的TCP/IP实现的一部分。

更为复杂的是,RARP请求是作为一个特殊类型的以太网数据帧来传送的(帧类型字段值为0x8035,如图2-1所示)。这说明RARP服务器必须能够发送和接收这种类型的以太网数据帧

5.4.2 每个网络有多个RARP服务器

RARP服务器实现的一个复杂因素是RARP请求是在硬件层上进行广播的。这意味着它们不经过路由器进行转发。为了让无盘系统在RARP服务器关机的状态下也能引导,通常在一个网络上(例如一根电缆)要提供多个RARP服务器。

当服务器的数目增加时(以提供冗余备份),网络流量也随之增加,因为每个服务器对每个RARP请求都要发送RARP应答。发送RARP请求的无盘系统一般采用最先收到的RARP应答对于ARP,我们从来没有遇到这种情况,因为只有一台主机发送ARP应答)。另外,还有一种可能发生的情况是每个RARP服务器同时应答,这样会增加以太网发生冲突的概率。

第6章 ICMP:Internet控制报文协议

6.1 引言

6.2 ICMP报文的类型

下面各种情况都不会导致产生ICMP差错报文:

  1. ICMP差错报文(但是,ICMP查询报文可能会产生ICMP差错报文)。
  2. 目的地址是广播地址(见图3-9)或多播地址(D类地址,见图1-5)的IP数据报。
  3. 作为链路层广播的数据报。
  4. 不是IP分片的第一片(将在11.5节介绍分片)。
  5. 源地址不是单个主机的数据报。这就是说,源地址不能为零地址、环回地址、广播地址或多播地址。

这些规则是为了防止过去允许ICMP差错报文对广播分组响应所带来的广播风暴

6.3 ICMP地址掩码请求与应答

ICMP报文中的标识符和序列号字段由发送端任意选择设定,这些值在应答中将被返回。这样,发送端就可以把应答与请求进行匹配。

6.4 ICMP时间戳请求与应答

ICMP时间戳请求允许系统向另一个系统查询当前的时间。返回的建议值是自午夜开始计算的毫秒数,协调的统一时间(Coordinated Universal Time,UTC)(早期的参考手册认为UTC是格林尼治时间)。这种ICMP报文的好处是它提供了毫秒级的分辨率,而利用其他方法从别的主机获取的时间(如某些Unix系统提供的rdate命令)只能提供秒级的分辨率。

由于返回的时间是从午夜开始计算的,因此调用者必须通过其他方法获知当时的日期,这是它的一个缺陷。

请求端填写发起时间戳,然后发送报文。应答系统收到请求报文时填写接收时间戳,在发送应答时填写发送时间戳。

但是,实际上,大多数的实现把后面两个字段都设成相同的值(提供三个字段的原因是可以让发送方分别计算发送请求的时间和发送应答的时间)。

发起时间戳(orig)、接收时间戳(recv)以及发送时间戳(xmit)。

往返时间(rtt):收到应答时的时间值减去发送请求时的时间值。

difference:接收时间戳值减去发起时间戳值。

6.5 ICMP端口不可达差错

6.6 ICMP报文的4.4BSD处理

如果最后一列标明是“内核”,那么ICMP就由内核来处理。

如果最后一列指明是“用户进程”,那么报文就被传送到所有在内核中登记的用户进程,以读取收到的ICMP报文。

第7章 Ping程序

7.1 引言

7.2 Ping程序

7.2.1 LAN输出

7.2.2 WAN输出

7.2.3 线路SLIP链接

7.2.4 拨号SLIP链路

7.3 IP记录路由选项

code是一个字节,指明IP选项的类型。

len是RR选项总字节长度,在这种情况下为39(尽管可以为RR选项设置比最大长度小的长度,但是ping程序总是提供39字节的选项字段,最多可以记录9个IP地址。由于IP首部中留给选项的空间有限,它一般情况都设置成最大长度)。

ptr称作指针字段。它是一个基于1的指针,指向存放下一个IP地址的位置。它的最小值为4,指向存放第一个IP地址的位置。

7.3.1 通常的例子

7.3.2 异常的输出

7.4 IP时间戳选项

OF表示溢出字段,FL表示标志字段。

第8章 Traceroute程序

8.1 引言

8.2 Traceroute程序的操作

8.3 局域网输出

8.4 广域网输出

8.5 IP源站选路选项

源站选路(source routing)的思想是由发送者指定路由。它可以采用以下两种形式:

  1. 严格的源路由选择。发送端指明IP数据报所必须采用的确切路由。如果一个路由器发现源路由所指定的下一个路由器不在其直接连接的网络上,那么它就返回一个“源站路由失败”的ICMP差错报文。
  2. 宽松的源站选路。发送端指明了一个数据报经过的IP地址清单,但是数据报在清单上指明的任意两个地址之间可以通过其他路由器。

源站路由选项的实际称呼为“源站及记录路由”(对于宽松的源站选路和严格的源站选路,分别用LSRR和SSRR表示),这是因为在数据报沿路由发送过程中,对IP地址清单进行了更新。下面是其运行过程:

  1. 发送主机从应用程序接收源站路由清单,将第1个表项去掉(它是数据报的最终目的地址),将剩余的项移到1个项中(如图8-6所示),并将原来的目的地址作为清单的最后一项。指针仍然指向清单的第1项(即,指针的值为4)。
  2. 每个处理数据报的路由器检查其是否为数据报的最终地址。如果不是,则正常转发数据报(在这种情况下,必须指明宽松源站选路,否则就不能接收到该数据报)。
  3. 如果该路由器是最终目的,且指针不大于路径的长度,那么(1)由ptr所指定的清单中的下一个地址就是数据报的最终目的地址;(2)由外出接口(outgoing interface)相对应的IP地址取代刚才使用的源地址;(3)指针加4。

8.5.1 宽松的源站选路的 traceroute 程序示例

8.5.2 严格的源站选路的 traceroute 程序示例

8.5.3 宽松的源站选路traceroute程序的往返路由

第9章 IP选路

9.1 引言

9.2 选路的原理

IP搜索路由表的几个步骤:

  1. 搜索匹配的主机地址;
  2. 搜索匹配的网络地址;
  3. 搜索默认表项(默认表项一般在路由表中被指定为一个网络表项,其网络号为0)。

9.2.1 简单路由表

对于一个给定的路由器,可以打印出五种不同的标志(flag):

  1. U 该路由可以使用。
  2. G 该路由是到一个网关(路由器)。如果没有设置该标志,说明目的地是直接相连的。
  3. H 该路由是到一个主机,也就是说,目的地址是一个完整的主机地址。如果没有设置该标志,说明该路由是到一个网络,而目的地址是一个网络地址:一个网络号,或者网络号与子网号的组合。
  4. D 该路由是由重定向报文创建的(9.5节)。
  5. M 该路由已被重定向报文修改(9.5节)。

标志G区分了间接路由和直接路由(对于直接路由来说是不设置标志G的)。

标志H表明,目的地址(netstat命令输出第一行)是一个完整的主机地址。没有设置H标志说明目的地址是一个网络地址(主机号部分为0)。

主机路由表的复杂性取决于主机所在网络的拓扑结构。

  1. 最简单的(也是最不令人感兴趣的)情况是主机根本没有与任何网络相连。TCP/IP协议仍然能用于这样的主机,但是只能与自己本身通信!这种情况下的路由表只包含环回接口一项。
  2. 接下来的情况是主机连在一个局域网上,只能访问局域网上的主机。这时路由表包含两项:一项是环回接口,另一项是局域网(如以太网)。
  3. 如果主机能够通过单个路由器访问其他网络(如Internet)时,那么就要进行下一步。一般情况下增加一个默认表项指向该路由器。
  4. 如果要新增其他的特定主机或网络路由,那么就要进行最后一步。在我们的例子中,到主机slip的路由要通过路由器bsdi就是这样的例子。

9.2.2 初始化路由表

运行下面两个命令来添加路由表中的表项:

route add default sun 1

route add slip bsdi 1

第3个参数(default和slip)代表目的端

第4个参数代表网关(路由器)

最后一个参数代表路由的度量(metric)。route命令在度量值大于0时要为该路由设置G标志,否则,当耗费值为0时就不设置G标志。

9.2.3 较复杂的路由表

9.2.4 没有到达目的地的路由

9.3 ICMP主机与网络不可达差错

9.4 转发或不转发

9.5 ICMP重定向差错

  1. 我们假定主机发送一份IP数据报给R1。这种选路决策经常发生,因为R1是该主机的默认路由。
  2. R1收到数据报并且检查它的路由表,发现R2是发送该数据报的下一站。当它把数据报发送给R2时,R1检测到它正在发送的接口与数据报到达接口是相同的(即主机和两个路由器所在的LAN)。这样就给路由器发送重定向报文给原始发送端提供了线索。
  3. R1发送一份ICMP重定向报文给主机,告诉它以后把数据报发送给R2而不是R1。

9.5.1 一个例子

9.5.2 更多的细节

ICMP重定向报文的接收者必须查看三个IP地址:

(1)导致重定向的IP地址(即ICMP重定向报文的数据网络重定向主机重定向位于IP数据报的首部);

(2)发送重定向报文的路由器的IP地址(包含重定向信息的IP数据报中的源地址;

(3)应该采用的路由器IP地址(在ICMP报文中的4~7字节)。

关于ICMP重定向报文有很多规则。

首先,重定向报文只能由路由器生成,而不能由主机生成。

另外,重定向报文是为主机而不是为路由器使用的。

在4.4BSD系统中,当主机作为路由器使用时,要进行下列检查。在生成ICMP重定向报文之前这些条件都要满足。

  1. 出接口必须等于入接口。
  2. 用于向外传送数据报的路由不能被ICMP重定向报文创建或修改过,而且不能是路由器的默认路由。
  3. 数据报不能用源站选路来转发。
  4. 内核必须配置成可以发送重定向报文。

一台4.4BSD主机收到ICMP重定向报文后,在修改路由表之前要作一些检查。这是为了防止路由器或主机的误操作,以及恶意用户的破坏,导致错误地修改系统路由表。

  1. 新的路由器必须直接与网络相连接。
  2. 重定向报文必须来自当前到目的地所选择的路由器。
  3. 重定向报文不能让主机本身作为路由器。
  4. 被修改的路由必须是一个间接路由。

9.6 ICMP路由器发现报文

初始化路由表的方法,即在配置文件中指定静态路由。这种方法经常用来设置默认路由。

另一种新的方法是利用ICMP路由器通告和请求报文

9.6.1 路由器操作

9.6.2 主机操作

9.6.3 实现

第10章 动态选路协议

10.1 引言

静态选路。在配置接口时,以默认方式生成路由表项(对于直接连接的接口),并通过route命令增加表项(通常从系统自引导程序文件),或是通过ICMP重定向生成表项(通常是在默认方式出错的情况下)。

网络很小,且与其他网络只有单个连接点没有多余路由时(若主路由失败,可以使用备用路由)采用静态选路。

其他情况使用动态选路。

10.2 动态选路

每个自治系统可以选择该自治系统中各个路由器之间的选路协议。这种协议我们称之为内部网关协议IGP(Interior Gateway Protocol)或域内选路协议(intradomain routing protocol)。最常用的IGP是选路信息协议RIP。一种新的IGP是开放最短路径优先OSPF(Open Shortest Path First)协议。它意在取代RIP。

外部网关协议EGP(Exterier Gateway Protocol)或域内选路协议的分隔选路协议用于不同自治系统之间的路由器。

10.3 Unix选路守护程序

10.4 RIP:选路信息协议

10.4.1 报文格式

命令字段为1表示请求,2表示应答。还有两个舍弃不用的命令(3和4),两个非正式的命令:轮询(5)和轮询表项(6)。请求表示要求其他系统发送其全部或部分路由表。应答则包含发送者全部或部分路由表。

10.4.2 正常运行

RIP常用的UDP端口号是520。

  1. 初始化:在启动一个路由守护程序时,它先判断启动了哪些接口,并在每个接口上发送一个请求报文,要求其他路由器发送完整路由表。在点对点链路中,该请求是发送给其他终点的。如果网络支持广播的话,这种请求是以广播形式发送的。目的UDP端口号是520(这是其他路由器的路由守护程序端口号)。 这种请求报文的命令字段为1,但地址系列字段设置为0,而度量字段设置为16。这是一种要求另一端完整路由表的特殊请求报文。
  2. 接收到请求。如果这个请求是刚才提到的特殊请求,那么路由器就将完整的路由表发送给请求者。否则,就处理请求中的每一个表项:如果有连接到指明地址的路由,则将度量设置成我们的值,否则将度量置为16(度量为16是一种称为“无穷大”的特殊值,它意味着没有到达目的的路由)。然后发回响应。
  3. 接收到响应。使响应生效,可能会更新路由表。可能会增加新表项,对已有的表项进行修改,或是将已有表项删除。
  4. 定期选路更新。每过30秒,所有或部分路由器会将其完整路由表发送给相邻路由器。发送路由表可以是广播形式的(如在以太网上),或是发送给点对点链路的其他终点的。
  5. 触发更新。每当一条路由的度量发生变化时,就对它进行更新。不需要发送完整路由表,而只需要发送那些发生变化的表项。

10.4.3 度量

RIP所使用的度量是以跳(hop)计算的。所有直接连接接口的跳数为1。

跳数的最大值是15,这意味着RIP只能用在主机间最大跳数值为15的AS内。度量为16表示到无路由到达该IP地址。

10.4.4 问题

RIP没有子网地址的概念。

在路由器或链路发生故障后,需要很长的一段时间才能稳定下来。这段时间通常需要几分钟。在这段建立时间里,可能会发生路由环路。在实现RIP时,必须采用很多微妙的措施来防止路由环路的出现,并使其尽快建立。

采用跳数作为路由度量忽略了其他一些应该考虑的因素。同时,度量最大值为15则限制了可以使用RIP的网络的大小。

10.4.5 举例

10.4.6 另一个例子

10.5 RIP版本2

选路域(routing domain)是一个选路守护程序的标识符,它指出了这个数据报的所有者。在一个Unix实现中,它可以是选路守护程序的进程号。该域允许管理者在单个路由器上运行多个RIP实例,每个实例在一个选路域内运行。

选路标记(routing tag)是为了支持外部网关协议而存在的。它携带着一个EGP和BGP的自治系统号。

10.6 OSPF:开放最短路径优先

与采用距离向量的RIP协议不同的是,OSPF是一个链路状态协议。距离向量的意思是,RIP发送的报文包含一个距离向量(跳数)。每个路由器都根据它所接收到邻站的这些距离向量来更新自己的路由表。

采用的是每个路由器主动地测试与其邻站相连链路的状态,将这些信息发送给它的其他邻站,而邻站将这些信息在自治系统中传播出去。每个路由器接收这些链路状态信息,并建立起完整的路由表。

不同点是链路状态协议总是比距离向量协议收敛更快。收敛的意思是在路由发生变化后,例如在路由器关闭或链路出故障后,可以稳定下来。

OSPF与RIP(以及其他选路协议)的不同点在于,OSPF直接使用IP。也就是说,它并不使用UDP或TCP。对于IP首部的protocol字段,OSPF有其自己的值

作为一种链路状态协议而不是距离向量协议,OSPF还有着一些优于RIP的特点

  1. OSPF可以对每个IP服务类型(图3-2)计算各自的路由集。这意味着对于任何目的,可以有多个路由表表项,每个表项对应着一个IP服务类型。
  2. 给每个接口指派一个无维数的费用。可以通过吞吐率、往返时间、可靠性或其他性能来进行指派。可以给每个IP服务类型指派一个单独的费用。
  3. 当对同一个目的地址存在着多个相同费用的路由时,OSPF在这些路由上平均分配流量。我们称之为流量平衡。
  4. OSPF支持子网:子网掩码与每个通告路由相连。这样就允许将一个任何类型的IP地址分割成多个不同大小的子网(我们在3.7节中给出了这样的一个例子,称之为变长度子网)。到一个主机的路由是通过全1子网掩码进行通告的。默认路由是以IP地址为0.0.0.0、网络掩码为全0进行通告的。
  5. 路由器之间的点对点链路不需要每端都有一个IP地址,我们称之为无编号网络。这样可以节省IP地址—现在非常紧缺的一种资源。
  6. 采用了一种简单鉴别机制。可以采用类似于RIP-2机制(10.5节)的方法指定一个明文口令。
  7. OSPF采用多播(第12章),而不是广播形式,以减少不参与OSPF的系统负载。随着大部分厂商支持OSPF,在很多网络中OSPF将逐步取代RIP。

10.7 BGP:边界网关协议

可以将自治系统分为以下几种类型:

  1. 残桩自治系统(stub AS),它与其他自治系统只有单个连接。stub AS只有本地流量。
  2. 多接口自治系统(multihomed AS),它与其他自治系统有多个连接,但拒绝传送通过流量。
  3. 转送自治系统(transit AS),它与其他自治系统有多个连接,在一些策略准则之下,它可以传送本地流量和通过流量。

BGP与RIP和OSPF的不同之处在于:BGP使用TCP作为其传输层协议。两个运行BGP的系统之间建立一条TCP连接,然后交换整个BGP路由表。从这个时候开始,在路由表发生变化时,再发送更新信号。

10.8 CIDR:无类型域间选路

无类型域间选路(CIDR)是一个防止Internet路由表膨胀的方法,它也称为超网(supernetting)。

CIDR的基本观点是采用一种分配多个IP地址的方式,使其能够将路由表中的许多表项总和(summarization)成更少的数目。

要使用这种总和,必须满足以下三种特性:

  1. 为进行选路要对多个IP地址进行总和时,这些IP地址必须具有相同的高位地址比特。
  2. 路由表和选路算法必须扩展成根据32 bit IP地址和32 bit掩码做出选路决策。
  3. 必须扩展选路协议使其除了32 bit地址外,还要有32 bit掩码。OSPF(10.6节)和RIP-2(10.5节)都能够携带第4版BGP所提出的32 bit掩码。

CIDR同时还使用一种技术,使最佳匹配总是最长的匹配:即在32 bit掩码中,它具有最大值。

第11章 UDP:用户数据报协议

11.1 引言

UDP是一个简单的面向数据报的运输层协议:进程的每个输出操作都正好产生一个UDP数据报,并组装成一份待发送的IP数据报。这与面向流字符的协议不同,如TCP,应用程序产生的全体数据与真正发送的单个IP数据报可能没有什么联系。

UDP不提供可靠性:它把应用程序传给IP层的数据发送出去,但是并不保证它们能到达目的地。

11.2 UDP首部

端口号表示发送进程和接收进程。

UDP长度字段指的是UDP首部和UDP数据的字节长度。

11.3 UDP检验和

UDP检验和覆盖UDP首部和UDP数据。

UDP和TCP在首部中都有覆盖它们首部和数据的检验和。UDP的检验和是可选的,而TCP的检验和是必需的。

11.3.1 tcpdump输出

11.3.2 一些统计结果

11.4 一个简单的例子

11.5 IP分片

IP把MTU与数据报长度进行比较,如果需要则进行分片。分片可以发生在原始发送端主机上,也可以发生在中间路由器上。

重新组装由目的端的IP层来完成,其目的是使分片和重新组装过程对运输层(TCP和UDP)是透明的,除了某些可能的越级操作外。已经分片过的数据报有可能会再次进行分片(可能不止一次)。IP首部中包含的数据为分片和重新组装提供了足够的信息。

IP数据报是指IP层端到端的传输单元(在分片之前和重新组装之后),分组是指在IP层和链路层之间传送的数据单元。一个分组可以是一个完整的IP数据报,也可以是IP数据报的一个分片。

11.6 ICMP不可达差错(需要分片)

11.7 用Traceroute确定路径MTU

11.8 采用UDP的路径MTU发现

11.9 UDP和ARP之间的交互作用

ARP洪泛(ARP flooding,即以高速率重复发送到同一个IP地址的ARP请求)。建议最高速率是每秒一次。

11.10 最大UDP数据报长度

UDP数据报中用户数据的最长长度为65507字节。但是,大多数实现所提供的长度比这个最大值小。

  • 应用程序可能会受到其程序接口的限制。
  • TCP/IP的内核实现。

11.11 ICMP源站抑制差错

11.12 UDP服务器的设计

11.12.1 客户IP地址及端口号

来自客户的是UDP数据报。IP首部包含源端和目的端IP地址,UDP首部包含了源端和目的端的UDP端口号。当一个应用程序接收到UDP数据报时,操作系统必须告诉它是谁发送了这份消息,即源IP地址和端口号。

11.12.2 目的IP地址

一些应用程序需要知道数据报是发送给谁的,即目的IP地址。

11.12.3 UDP输入队列

来自不同客户的差不多同时到达的请求将由UDP自动排队。接收到的UDP数据报以其接收顺序交给应用程序(在应用程序要求交送下一个数据报时)。

11.12.4 限制本地IP地址

11.12.5 限制远端IP地址

11.12.6 每个端口有多个接收者

第12章 广播和多播

有三种IP地址:单播地址、广播地址和多播地址。

广播和多播仅应用于UDP,它们对需将报文同时传往多个接收者的应用来说十分重要。

TCP是一个面向连接的协议,它意味着分别运行于两主机(由IP地址确定)内的两进程(由端口号确定)间存在一条连接。

通常每个以太网帧仅发往单个目的主机,目的地址指明单个接收接口,因而称为单播(unicast)。在这种方式下,任意两个主机的通信不会干扰网内其他主机(可能引起争夺共享信道的情况除外)。

有时一个主机要向网上的所有其他主机发送帧,这就是广播

多播(multicast)处于单播和广播之间:帧仅传送给属于多播组的多个主机。

12.2 广播

12.2.1 受限的广播

受限的广播地址是255.255.255.255。该地址用于主机配置过程中IP数据报的目的地址,此时,主机可能还不知道它所在网络的网络掩码,甚至连它的IP地址也不知道。

12.2.2 指向网络的广播

指向网络的广播地址是主机号为全1的地址。A类网络广播地址为netid.255.255.255,其中netid为A类网络的网络号。

一个路由器必须转发指向网络的广播,但它也必须有一个不进行转发的选择。

12.2.3 指向子网的广播

指向子网的广播地址为主机号为全1且有特定子网号的地址。

12.2.4 指向所有子网的广播

指向所有子网的广播也需要了解目的网络的子网掩码,以便与指向网络的广播地址区分开。指向所有子网的广播地址的子网号及主机号为全1

12.3 广播的例子

12.4 多播

IP多播提供两类服务:

  1. 向多个目的地址传送数据。有许多向多个接收者传送信息的应用:例如交互式会议系统和向多个接收者分发邮件或新闻。如果不采用多播,目前这些应用大多采用TCP来完成(向每个目的地址传送一个单独的数据复制)。然而,即使使用多播,某些应用可能继续采用TCP来保证它的可靠性。
  2. 客户对服务器的请求。例如,无盘工作站需要确定启动引导服务器。目前,这项服务是通过广播来提供的(正如第16章的BOOTP),但是使用多播可降低不提供这项服务主机的负担。

12.4.1 多播组地址

多播组地址包括为111 0的最高4bit和多播组号。它们通常可表示为点分十进制数,范围从224.0.0.0到239.255.255.255。

能够接收发往一个特定多播组地址数据的主机集合称为主机组(host group)。

12.4.2 多播组地址到以太网地址的转换

IANA拥有一个以太网地址块,即高位24 bit为00:00:5e(十六进制表示),这意味着该地址块所拥有的地址范围从00:00:5e:00:00:00到00:00:5e:ff:ff:ff。IANA将其中的一半分配为多播地址。为了指明一个多播地址,任何一个以太网地址的首字节必须是01,这意味着与IP多播相对应的以太网地址范围从01:00:5e:00:00:00到01:00:5e:7f:ff:ff。

12.4.3 FDDI和令牌环网络中的多播

第13章 IGMP:Internet组管理协议

13.1 引言

用于支持主机和路由器进行多播的Internet组管理协议(IGMP)。它让一个物理网络上的所有系统知道主机当前所在的多播组。多播路由器需要这些信息以便知道多播数据报应该向哪些接口转发。

13.2 IGMP报文

IGMP类型为1说明是由多播路由器发出的查询报文,为2说明是主机发出的报告报文。检验和的计算和ICMP协议相同。

13.3 IGMP协议

13.3.1 加入一个多播组

13.3.2 IGMP报告和查询

多播路由器使用IGMP报文来记录与该路由器相连网络中组成员的变化情况。使用规则如下:

  1. 当第一个进程加入一个组时,主机就发送一个IGMP报告。如果一个主机的多个进程加入同一组,只发送一个IGMP报告。这个报告被发送到进程加入组所在的同一接口上。
  2. 进程离开一个组时,主机不发送IGMP报告,即便是组中的最后一个进程离开。主机知道在确定的组中已不再有组成员后,在随后收到的IGMP查询中就不再发送报告报文。
  3. 多播路由器定时发送IGMP查询来了解是否还有任何主机包含有属于多播组的进程。多播路由器必须向每个接口发送一个IGMP查询。因为路由器希望主机对它加入的每个多播组均发回一个报告,因此IGMP查询报文中的组地址被设置为0。
  4. 主机通过发送IGMP报告来响应一个IGMP查询,对每个至少还包含一个进程的组均要发回IGMP报告。

13.3.3 实现细节

13.3.4 生存时间字段

13.3.5 所有主机组

13.4 一个例子

第14章 DNS:域名系统

14.1 引言

域名系统(DNS)是一种用于TCP/IP应用程序的分布式数据库,它提供主机名字和IP地址之间的转换及有关电子邮件的选路信息。

14.2 DNS基础

顶级域名被分为三个部分:

  1. arpa是一个用作地址到名字转换的特殊域(我们将在14.5节介绍)。
  2. 7个3字符长的普通域。有些书也将这些域称为组织域。
  3. 所有2字符长的域均是基于ISO3166中定义的国家代码,这些域被称为国家域,或地理域。

主、辅名字服务器的主要区别在于主名字服务器从磁盘文件中调入该区域的所有信息,而辅名字服务器则从主服务器调入所有信息。我们将辅名字服务器从主服务器调入信息称为区域传送。

14.3 DNS的报文格式

  • QR是1bit字段:0表示查询报文,1表示响应报文。
  • opcode是一个4bit字段:通常值为0(标准查询),其他值为1(反向查询)和2(服务器状态请求)。
  • AA是1bit标志,表示“授权回答(authoritative answer)”。该名字服务器是授权于该域的。
  • TC是1bit字段,表示“可截断的(truncated)”。使用UDP时,它表示当应答的总长度超过512字节时,只返回前512个字节。
  • RD是1bit字段表示“期望递归(recursion desired)”。该比特能在一个查询中设置,并在响应中返回。这个标志告诉名字服务器必须处理这个查询,也称为一个递归查询。如果该位为0,且被请求的名字服务器没有一个授权回答,它就返回一个能解答该查询的其他名字服务器列表,这称为迭代查询。在后面的例子中,我们将看到这两种类型查询的例子。
  • RA是1bit字段,表示“可用递归”。如果名字服务器支持递归查询,则在响应中将该比特设置为1。在后面的例子中可看到大多数名字服务器都提供递归查询,除了某些根服务器。
  • 随后的3bit字段必须为0。
  • rcode是一个4bit的返回码字段。通常的值为0(没有差错)和3(名字差错)。名字差错只有从一个授权名字服务器上返回,它表示在查询中制定的域名不存在。

14.3.1 DNS查询报文中的问题部分

查询名是要查找的名字,它是一个或多个标识符的序列。

每个标识符以首字节的计数值来说明随后标识符的字节长度,每个名字以最后字节为0结束,长度为0的标识符是根标识符。

计数字节的值必须是0~63的数,因为标识符的最大长度仅为63(在本节的后面我们将看到计数字节的最高两比特为1,即值192~255,将用于压缩格式)。

不像我们已经看到的许多其他报文格式,该字段无需以整32 bit边界结束,即无需填充字节。

14.3.2 DNS响应报文中的资源记录部分

DNS报文中最后的三个字段,回答字段、授权字段和附加信息字段,均采用一种称为资源记录RR(Resource Record)的相同格式。

域名是记录中资源数据对应的名字。它的格式和前面介绍的查询名字段格式(图14-6)相同。

类型说明RR的类型码。它的值和前面介绍的查询类型值是一样的。类通常为1,指Internet数据。

生存时间字段是客户程序保留该资源记录的秒数。资源记录通常的生存时间值为2天。

资源数据长度说明资源数据的数量。该数据的格式依赖于类型字段的值。对于类型1(A记录)资源数据是4字节的IP地址。

14.4 一个简单的例子

14.5 指针查询

指针查询方式:给定一个IP地址,返回与该地址对应的域名。

A类地址是第一字节,B类地址是第一、二字节,C类地址则是第一、二、三字节。

14.5.1 举例

14.5.2 主机名检查

14.6 资源记录

14.7 高速缓存

14.8 用UDP还是用TCP

DNS名字服务器使用的熟知端口号无论对UDP还是TCP都是53。

14.9 另一个例子

第15章 TFTP:简单文件传送协议

15.1 引言

TFTP(Trivial File Transfer Protocol)即简单文件传送协议,最初打算用于引导无盘系统(通常是工作站或X终端)。和将在第27章介绍的使用TCP的文件传送协议(FTP)不同,为了保持简单和短小,TFTP将使用UDP。TFTP的代码(和它所需要的UDP、IP和设备驱动程序)都能适合只读存储器。

15.2 协议

15.3 一个例子

15.4 安全性

TFTP分组中并不提供用户名和口令。这是TFTP的一个特征(即“安全漏洞”)。由于TFTP是设计用于系统引导进程,它不可能提供用户名和口令。

第16章 BOOTP:引导程序协议

16.1 引言

用于无盘系统进行系统引导的替代方法,又称为引导程序协议,或BOOTP。

BOOTP使用UDP,且通常需与TFTP协同工作。

16.2 BOOTP的分组格式

端口号

BOOTP有两个熟知端口:BOOTP服务器为67BOOTP客户为68

选择两个端口而不是仅选择一个端口为BOOTP服务器用的原因是:服务器的应答可以进行广播(但通常是不用广播的)。

16.3 一个例子

16.4 BOOTP服务器的设计

BOOTP客户通常固化在无盘系统只读存储器中。

TFTP服务器如何能将一个响应直接送回BOOTP客户?

(这个响应是一个UDP数据报,而服务器知道该客户的IP地址(可能通过读取服务器上的配置文件)。但如果这个客户向那个IP地址发送一个UDP数据报(正常情况下会处理UDP的输出),BOOTP服务器的主机就可能向那个IP地址发送一个ARP请求。但这个客户不能响应这个ARP请求,因为它还不知道它自己的IP地址!)

有两种解决办法:第一种,通常被Unix服务器采用,是服务器发一个ioctl(2)请求给内核,为该客户在ARP高速缓存中设置一个条目(这就是命令arp-s所做的工作,见4.8节)。服务器能一直这么做直到它知道客户的硬件地址和IP地址。这意味着当服务器发送UDP数据报(即BOOTP应答)时,服务器的ARP将在ARP高速缓存中找到该客户的IP地址。

另一种可选的解决办法是服务器广播这个BOOTP应答而不直接将应答发回该客户。既然通常期望网络广播越少越好,因此这种解决方案应该只在服务器无法在它的ARP高速缓存设置一个条目的情况下使用。通常只有拥有超级用户权限才能在ARP高速缓存设置一个条目,如果没有这种权限就只能广播BOOTP应答。

16.5 BOOTP穿越路由器

16.6 特定厂商信息

第17章 TCP:传输控制协议

17.1 引言

17.2 TCP的服务

TCP提供一种面向连接的、可靠的字节流服务。

面向连接意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。

TCP通过下列方式来提供可靠性:

  • 应用数据被分割成TCP认为最适合发送的数据块。这和UDP完全不同,应用程序产生的数据报长度将保持不变。由TCP传递给IP的信息单位称为报文段或段(segment)(参见图1-7)。在18.4节我们将看到TCP如何确定报文段的长度。
  • 当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。在第21章我们将了解TCP协议中自适应的超时及重传策略。
  • 当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒,这将在19.3节讨论。
  • TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)。
  • 既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。如果必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
  • 既然IP数据报会发生重复,TCP的接收端必须丢弃重复的数据。
  • TCP还能提供流量控制。TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。

17.3 TCP的首部

每个TCP段都包含源端和目的端的端口号,用于寻找发端和收端应用进程。这两个值加上IP首部中的源端IP地址和目的端IP地址唯一确定一个TCP连接。

第18章 TCP连接的建立与终止

18.1 引言

TCP是一个面向连接的协议。无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。

18.2 连接的建立与终止

18.2.1tcpdump的输出

对于TCP段,每个输出行开始按如下格式显示:

源>目的:标志

tcpdump显示这个字段的格式是开始的序号、一个冒号、隐含的结尾序号及圆括号内的数据字节数。显示序号和隐含结尾序号的优点是便于了解数据字节数大于0时的隐含结尾序号。这个字段只有在满足条件(1)报文段中至少包含一个数据字节;或者(2)SYN、FIN或RST被设置为1时才显示。

18.2.2 时间系列

18.2.3 建立连接协议

为了建立一条TCP连接:

  1. 请求端(通常称为客户)发送一个SYN段指明客户打算连接的服务器的端口,以及初始序号(ISN,在这个例子中为1415531521)。这个SYN段为报文段1。
  2. 服务器发回包含服务器的初始序号的SYN报文段(报文段2)作为应答。同时,将确认序号设置为客户的ISN加1以对客户的SYN报文段进行确认。一个SYN将占用一个序号。
  3. 客户必须将确认序号设置为服务器的ISN加1以对服务器的SYN报文段进行确认(报文段3)。

这三个报文段完成连接的建立。这个过程也称为三次握手(three-way handshake)

18.2.4 连接终止协议

建立一个连接需要三次握手,而终止一个连接要经过4次握手。这由TCP的半关闭(halfclose)造成的。

既然一个TCP连接是全双工(即数据在两个方向上能同时传递),因此每个方向必须单独地进行关闭。这原则就是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向连接。当一端收到一个FIN,它必须通知应用层另一端几经终止了那个方向的数据传送。发送FIN通常是应用层进行关闭的结果。

18.2.5 正常的tcpdump输出

18.3 连接建立的超时

有很多情况导致无法建立连接。一种情况是服务器主机没有处于正常状态。

18.3.1 第一次超时时间

18.3.2 服务类型字段

18.4 最大报文段长度

18.5 TCP的半关闭

18.6 TCP的状态变迁图

用粗的实线箭头表示正常的客户端状态变迁。

用粗的虚线箭头表示正常的服务器状态变迁。

18.6.1 2MSL等待状态

TIME_WAIT状态也称为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime)。

对一个具体实现所给定的MSL值,处理的原则是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的FIN)。

18.6.2 平静时间的概念

为了防止这种情况,RFC 793指出TCP在重启动后的MSL秒内不能建立任何连接。这就称为平静时间(quiet time)。

18.6.3 FIN_WAIT_2状态

18.7 复位报文段

18.7.1 到不存在的端口的连接请求

产生复位的一种常见情况是当连接请求到达时,目的端口没有进程正在听。

对于UDP,我们在6.5节看到这种情况,当一个数据报到达目的端口时,该端口没在使用,它将产生一个ICMP端口不可达的信息。而TCP则使用复位。

18.7.2 异常终止一个连接

我们在18.2节中看到终止一个连接的正常方式是一方发送FIN。有时这也称为有序释放(orderly release),因为在所有排队数据都已发送之后才发送FIN,正常情况下没有任何数据丢失。

但也有可能发送一个复位报文段而不是FIN来中途释放一个连接。有时称这为异常释放(abortive release)

异常终止一个连接对应用程序来说有两个优点:

(1)丢弃任何待发数据并立即发送复位报文段;

(2)RST的接收方会区分另一端执行的是异常关闭还是正常关闭。应用程序使用的API必须提供产生异常关闭而不是正常关闭的手段。

18.7.3 检测半打开连接

如果一方已经关闭或异常终止连接而另一方却还不知道,我们将这样的TCP连接称为半打开(Half-Open)的。

任何一端的主机异常都可能导致发生这种情况。

只要不打算在半打开连接上传输数据,仍处于连接状态的一方就不会检测另一方已经出现异常。

半打开连接的另一个常见原因是当客户主机突然掉电而不是正常的结束客户应用程序后再关机。

18.8 同时打开

18.9 同时关闭

18.10 TCP选项

18.11 TCP服务器的设计

18.11.1 TCP服务器端口号

18.11.2 限定的本地IP地址

18.11.3 限定的远端IP地址

在三种情况中,lport是服务器的熟知端口,而localIP必须是一个本地接口的IP地址。表中行的顺序正是TCP模块在收到一个连接请求时确定本地地址的顺序。最常使用的绑定(第1行,如果支持的话)将最先尝试,最不常用的(最后一行两端的IP地址都没有制定)将最后尝试。

18.11.4 呼入连接请求队列

在伯克利的TCP实现中采用以下规则:

1.正等待连接请求的一端有一个固定长度的连接队列,该队列中的连接已被TCP接受(即三次握手已经完成),但还没有被应用层所接受。
注意区分TCP接受一个连接是将其放入这个队列,而应用层接受连接是将其从该队列中移出。

2.应用层将指明该队列的最大长度,这个值通常称为积压值(backlog)。它的取值范围是0~5之间的整数,包括0和5(大多数的应用程序都将这个值说明为5)。

3.当一个连接请求(即SYN)到达时,TCP使用一个算法,根据当前连接队列中的连接数来确定是否接收这个连接。我们期望应用层说明的积压值为这一端点所能允许接受连接的最大数目,但情况不是那么简单。图18-23显示了积压值与传统的伯克利系统和Solaris2.2所能允许的最大接受连接数之间的关系。注意,积压值说明的是TCP监听的端点已被TCP接受而等待应用层接受的最大连接数。这个积压值对系统所允许的最大连接数,或者并发服务器所能并发处理的客户数,并无影响。在这个图中,Solaris系统规定的值正如我们所期望的。而传统的BSD系统,将这个值(由于某些原因)设置为积压值乘3除以2,再加1。

4.如果对于新的连接请求,该TCP监听的端点的连接队列中还有空间(基于图18-23),TCP模块将对SYN进行确认并完成连接的建立。但应用层只有在三次握手中的第三个报文段收到后才会知道这个新连接时。另外,当客户进程的主动打开成功但服务器的应用层还不知道这个新的连接时,它可能会认为服务器进程已经准备好接收数据了(如果发生这种情况,服务器的TCP仅将接收的数据放入缓冲队列)。

5.如果对于新的连接请求,连接队列中已没有空间,TCP将不理会收到的SYN。也不发回任何报文段(即不发回RST)。如果应用层不能及时接受已被TCP接受的连接,这些连接可能占满整个连接队列,客户的主动打开最终将超时。

第19章 TCP的交互数据流

19.1 引言

19.2 交互式输入

(1)来自客户的交互按键;(2)来自服务器的按键确认;(3)来自服务器的按键回显;(4)来自客户的按键回显确认。

19.3 经受时延的确认

19.4 Nagle算法

19.4.1 关闭Nagle算法

19.4.2 一个例子

19.5 窗口大小通告

第20章 TCP的成块数据流

20.1 引言

20.2 正常数据流

20.3 滑动窗口

接收方通告的窗口称为提出的窗口。

  1. 称窗口左边沿向右边沿靠近为窗口合拢。这种现象发生在数据被发送和确认时。
  2. 当窗口右边沿向右移动时将允许发送更多的数据,我们称之为窗口张开。这种现象发生在另一端的接收进程读取已经确认的数据并释放了TCP的接收缓存时。
  3. 当右边沿向左移动时,我们称之为窗口收缩。Host Requirements RFC强烈建议不要使用这种方式。但TCP必须能够在某一端产生这种情况时进行处理。第22.3节给出了这样的一个例子,一端希望向左移动右边沿来收缩窗口,但没能够这样做。

因为窗口的左边沿受另一端发送的确认序号的控制,因此不可能向左边移动。如果接收到一个指示窗口左边沿向左移动的ACK,则它被认为是一个重复ACK。

  1. 发送方不必发送一个全窗口大小的数据。
  2. 来自接收方的一个报文段确认数据并把窗口向右边滑动。这是因为窗口的大小是相对于确认序号的。
  3. 正如从报文段7到报文段8中变化的那样,窗口的大小可以减小,但是窗口的右边沿却不能够向左移动。
  4. 接收方在发送一个ACK前不必等待窗口被填满。在前面我们看到许多实现每收到两个报文段就会发送一个ACK。

20.4 窗口大小

20.5 PUSH标志

20.6 慢启动

通过观察到新分组进入网络的速率应该与另一端返回确认的速率相同而进行工作。

慢启动为发送方的TCP增加了另一个窗口:拥塞窗口(congestion window),记为cwnd。

当与另一个网络的主机建立TCP连接时,拥塞窗口被初始化为1个报文段(即另一端通告的报文段大小)。

每收到一个ACK,拥塞窗口就增加一个报文段(cwnd以字节为单位,但是慢启动以报文段大小为单位进行增加)。

发送方取拥塞窗口与通告窗口中的最小值作为发送上限。

拥塞窗口是发送方使用的流量控制,而通告窗口则是接收方使用的流量控制。

20.7 成块数据的吞吐量

左边的发送方和右边的接收方之间的一个TCP连接上的时间系列,共显示了16个时间单元。

每个粗箭头线的上半部分显示的是从左到右的携带数据的报文段,标记为1,2,3,等等。

在粗线箭头下面表示的是反向传输的ACK。我们把ACK用细箭头线表示,并标注了被确认的报文段号。

20.7.1 带宽时延乘积

可以计算通道的容量为:

capacity (bit) = bandwidth (b/s) × round-trip time (s)

一般称之为带宽时延乘积。这个值依赖于网络速度和两端的RT T。

20.7.2 拥塞

20.8 紧急方式

使一端可以告诉另一端有些具有某种方式的“紧急数据”已经放置在普通的数据流中。另一端被通知这个紧急数据已被放置在普通数据流中,由接收方决定如何处理。

第21章 TCP的超时与重传

21.1 引言

TCP提供可靠的运输层。它使用的方法之一就是确认从另一端收到的数据。但数据和确认都有可能会丢失。TCP通过在发送时设置一个定时器来解决这种问题。如果当定时器溢出时还没有收到确认,它就重传该数据。

对每个连接,TCP管理4个不同的定时器。

  1. 重传定时器使用于当希望收到另一端的确认。在本章我们将详细讨论这个定时器以及一些相关的问题,如拥塞避免。
  2. 坚持(persist)定时器使窗口大小信息保持不断流动,即使另一端关闭了其接收窗口。第22章将讨论这个问题。
  3. 保活(keepalive)定时器可检测到一个空闲连接的另一端何时崩溃或重启。第23章将描述这个定时器。
  4. 2MSL定时器测量一个连接处于TIME_WA IT状态的时间。我们在18.6节对该状态进行了介绍。

21.2 超时与重传的简单例子

1、3、6、12、24、48、64,指数退避(exponential backoff)

21.3 往返时间测量

最初的TCP规范使TCP使用低通过滤器来更新一个被平滑的RT T估计器(记为O)。

第20章 TCP的成块数据流_即时通讯网(52im.net)

这里的α是一个推荐值为0.9的平滑因子。每次进行新测量的时候,这个被平滑的RTT将得到更新。每个新估计的90%来自前一个估计,而10%则取自新的测量。

该算法在给定这个随RT T的变化而变化的平滑因子的条件下,RFC 793推荐的重传超时时间RTO(Retransmission TimeOut)的值应该设置为

第21章 TCP的超时与重传_TCP/IP详解卷1 协议_即时通讯网(52im.net)

这里的β是一个推荐值为2的时延离散因子。

跟踪RTT方差

第20章 TCP的成块数据流_即时通讯网(52im.net)

这里的A是被平滑的RTT(均值的估计器)而D则是被平滑的均值偏差。

Err是刚得到的测量结果与当前的RTT估计器之差。

AD均被用于计算下一个重传时间(RTO)。

增量g起平均作用,取为1/8(0.125)。

偏差的增益是h,取值为0.25。当RTT变化时,较大的偏差增益将使RTO快速上升。

Karn算法

规定,当一个超时和重传发生时,在重传数据的确认最后到达之前,不能更新RT T估计器,因为我们并不知道ACK对应哪次传输(也许第一次传输被延迟而并没有被丢弃,也有可能第一次传输的ACK被延迟)。并且,由于数据被重传,RTO已经得到了一个指数退避,我们在下一次传输时使用这个退避后的RTO。对一个没有被重传的报文段而言,除非收到了一个确认,否则不要计算新的RTO

21.4 往返时间RTT的例子

21.4.1 往返时间RTT的测量

21.4.2 RTT估计器的计算

变量AD分别被初始化为0和3秒。初始的重传超时使用下面的公式进行计算

RTO = A + 2D = 0 + 2 × 3 = 6s

(因子2D只在这个初始化计算中使用。正如前面提到的,以后使用4DA相加来计算RTO)。这就是传输初始SYN所使用的RTO

21.4.3 慢启动

连接上最初只允许传输一个报文段,然后在发送下一个报文段之前必须等待接收它的确认。当报文段2被接收后,就可以再发送两个报文段。

21.5 拥塞举例

21.6 拥塞避免算法

拥塞避免算法和慢启动算法需要对每个连接维持两个变量:一个拥塞窗口cwnd和一个慢启动门限ssthresh。这样得到的算法的工作过程如下:

  1. 对一个给定的连接,初始化cwnd为1个报文段,ssthresh为65535个字节。
  2. TCP输出例程的输出不能超过cwnd和接收方通告窗口的大小。拥塞避免是发送方使用的流量控制,而通告窗口则是接收方进行的流量控制。前者是发送方感受到的网络拥塞的估计,而后者则与接收方在该连接上的可用缓存大小有关。
  3. 当拥塞发生时(超时或收到重复确认),ssthresh被设置为当前窗口大小的一半(cwnd和接收方通告窗口大小的最小值,但最少为2个报文段)。此外,如果是超时引起了拥塞,则cwnd被设置为1个报文段(这就是慢启动)。
  4. 当新的数据被对方确认时,就增加cwnd,但增加的方法依赖于我们是否正在进行慢启动或拥塞避免。如果cwnd小于或等于ssthresh,则正在进行慢启动,否则正在进行拥塞避免。慢启动一直持续到我们回到当拥塞发生时所处位置的半时候才停止(因为我们记录了在步骤2中给我们制造麻烦的窗口大小的一半),然后转为执行拥塞避免。

拥塞避免算法要求每次收到一个确认时将cwnd增加1/cwnd

21.7 快速重传与快速恢复算法

重传丢失的数据报文段,而无需等待超时定时器溢出。这就是快速重传算法。

算法通常按如下过程进行实现:

  1. 当收到第3个重复的ACK时,将ssthresh设置为当前拥塞窗口cwnd的一半。重传丢失的报文段。设置cwndssthresh加上3倍的报文段大小。
  2. 每次收到另一个重复的ACK时,cwnd增加1个报文段大小并发送1个分组(如果新的cwnd允许发送)。
  3. 当下一个确认新数据的ACK到达时,设置cwndssthresh(在第1步中设置的值)。这个ACK应该是在进行重传后的一个往返时间内对步骤1中重传的确认。另外,这个ACK也应该是对丢失的分组和收到的第1个重复的ACK之间的所有中间报文段的确认。这一步采用的是拥塞避免,因为当分组丢失时我们将当前的速率减半。

21.8 拥塞举例(续)

21.9 按每条路由进行度量

21.10 ICMP的差错

21.11 重新分组

第22章 TCP的坚持定时器

22.1 引言

如果一个确认丢失了,则双方就有可能因为等待对方而使连接终止:接收方等待接收数据(因为它已经向发送方通告了一个非0的窗口),而发送方在等待允许它继续发送数据的窗口更新。为防止这种死锁情况的发生,发送方使用一个坚持定时器(persist timer)来周期性地向接收方查询,以便发现窗口是否已增大。这些从发送方发出的报文段称为窗口探查(window probe)。

22.2 一个例子

22.3 糊涂窗口综合症

该现象可发生在两端中的任何一端:接收方可以通告一个小的窗口(而不是一直等到有大的窗口时才通告),而发送方也可以发送少量的数据(而不是等待其他的数据以便发送一个大的报文段)。可以在任何一端采取措施避免出现糊涂窗口综合症的现象。

  1. 接收方不通告小窗口。通常的算法是接收方不通告一个比当前窗口大的窗口(可以为0),除非窗口可以增加一个报文段大小(也就是将要接收的MSS)或者可以增加接收方缓存空间的一半,不论实际有多少。
  2. 发送方避免出现糊涂窗口综合症的措施是只有以下条件之一满足时才发送数据:

(a)可以发送一个满长度的报文段;

(b)可以发送至少是接收方通告窗口大小一半的报文段;

(c)可以发送任何数据并且不希望接收ACK(也就是说,我们没有还未被确认的数据)或者该连接上不能使用Nagle算法(见第19.4节)。

条件(b)主要对付那些总是通告小窗口(也许比1个报文段还小)的主机。

条件(c)使我们在有尚未被确认的数据(正在等待被确认)以及在不能使用Nagle算法的情况下,避免发送小的报文段。如果应用进程在进行小数据的写操作(例如比该报文段还小),条件(c)可以避免出现糊涂窗口综合症。

第23章 TCP的保活定时器

23.1 引言

23.2 描述

如果一个给定的连接在两个小时之内没有任何动作,则服务器就向客户发送一个探查报文段,客户主机必须处于以下4个状态之一。

  1. 客户主机依然正常运行,并从服务器可达。客户的TCP响应正常,而服务器也知道对方是正常工作的。服务器在两小时以后将保活定时器复位。如果在两个小时定时器到时间之前有应用程序的通信量通过此连接,则定时器在交换数据后的未来2小时再复位。
  2. 客户主机已经崩溃,并且关闭或者正在重新启动。在任何一种情况下,客户的TCP都没有响应。服务器将不能够收到对探查的响应,并在75秒后超时。服务器总共发送10个这样的探查,每个间隔75秒。如果服务器没有收到一个响应,它就认为客户主机已经关闭并终止连接。
  3. 客户主机崩溃并已经重新启动。这时服务器将收到一个对其保活探查的响应,但是这个响应是一个复位,使得服务器终止这个连接。
  4. 客户主机正常运行,但是从服务器不可达。这与状态2相同,因为TCP不能够区分状态4与状态2之间的区别,它所能发现的就是没有收到探查的响应。

23.3 保活举例

23.3.1 另一端崩溃

为模拟这种情况,我们采用如下步骤:

  1. 在客户(主机bsdi上运行的sock程序)和主机svr4上的标准回显服务器之间建立一个连接。客户使用-K选项使能保活功能。
  2. 验证数据可以通过该连接。
  3. 观察客户TCP每隔2小时发送保活分组,并观察被服务器的TCP确认。
  4. 将以太网电缆从服务器上拔掉直到这个例子完成,这会使客户认为服务器主机已经崩溃。
  5. 我们预期服务器在断定连接已中断前发送10个间隔为75秒的保活探查。

23.3.2 另一端崩溃并重新启动

23.3.3 另一端不可达

第24章 TCP的未来和性能

24.1 引言

24.2 路径MTU发现

TCP的路径MTU发现按如下方式进行:在连接建立时,TCP使用输出接口或对端声明的MSS中的最小MTU作为起始的报文段大小。路径MTU发现不允许TCP超过对端声明的MSS。如果对端没有指定一个MSS,则默认为536。一个实现也可以按21.9节中讲的那样为每个路由单独保存路径MTU信息。

24.2.1 一个例子

24.2.2 大分组还是小分组

24.3 长肥管道

capacity(b) = bandwidth(b/s) × round - triptime(s)

具有大的带宽时延乘积的网络被称为长肥网络(Long Fat Network,即LFN,发音为“elefan(t)s”),一个运行在LFN上的TCP连接被称为长肥管道。

管道可以被水平拉长(一个长的RT T),或被垂直拉高(较高的带宽),或向两个方向拉伸。

使用长肥管道会遇到多种问题。

千兆比网络

24.4 窗口扩大选项

24.5 时间戳选项

时间戳选项使发送方在每个报文段中放置一个时间戳值。接收方在确认中返回这个数值,从而允许发送方为每一个收到的ACK计算RTT(我们必须说“每一个收到的ACK”而不是“每一个报文段”,是因为TCP通常用一个ACK来确认多个报文段)。

为了减少任一端所维持的状态数量,对于每个连接只保持一个时间戳的数值。选择何时更新这个数值的算法非常简单:

  1. TCP跟踪下一个ACK中将要发送的时间戳的值(一个名为tsrecent的变量)以及最后发送的ACK中的确认序号(一个名为lastack的变量)。这个序号就是接收方期望的序号。
  2. 当一个包含有字节号lastack的报文段到达时,则该报文段中的时间戳被保存在tsrecent中。
  3. 无论何时发送一个时间戳选项,tsrecent就作为时间戳回显应答字段被发送,而序号字段被保存在lastack中。

24.6 PAWS:防止回绕的序号

24.7 T/TCP:为事务用的TCP扩展

TCP提供的是一种虚电路方式的运输服务。一个连接的生存时间包括三个不同的阶段:建立、数据传输和终止。这种虚电路服务非常适合诸如远程注册和文件传输之类的应用。

一个事务(transaction)就是符合下面这些特征的一个客户请求及其随后的服务器响应。

  1. 应该避免连接建立和连接终止的开销,在可能的时候,发送一个请求分组并接收一个应答分组。
  2. 等待时间应当减少到等于RTT与SPT之和。其中RTT(Round-Trip Time)为往返时间,而SPT(Server Processing Time)则是服务器处理请求的时间。
  3. 服务器应当能够检测出重复的请求,并且当收到一个重复的请求时不重新处理事务(避免重新处理意味着服务器不必再次处理请求,而是返回保存的、与该请求对应的应答)。

TCP为处理事务而需要进行的两个改动是避免三次握手和缩短WAIT_TIME状态。T/TCP通过使用加速打开来避免三次握手:

  1. 它为打开的连接指定一个32 bit的连接计数CC(Connection Count),无论主动打开还是被动打开。一个主机的CC值从一个全局计数器中获得,该计数器每次被使用时加1。
  2. 在两个使用T/TCP的主机之间的每一个报文段都包括一个新的TCP选项CC。这个选项的长度为6个字节,包含发送方在该连接上的32 bit的CC值。
  3. 一个主机维持一个缓存,该缓存保留每个主机上一次的CC值,这些值从来自这个主机的一个可接受的SYN报文段中获得。
  4. 当在一个开始的SYN中收到一个CC选项的时候,接收方比较收到的值与为该发送方缓存的CC值。如果接收到的CC比缓存的大,则该SYN是新的,报文段中的任何数据被传递给接收应用进程(服务器)。这个连接被称为半同步。如果接收的CC比缓存的小,或者接收主机上没有对应这个客户的缓存CC,则执行正常的TCP三次握手过程。
  5. 为响应一个开始的SYN,带有SYN和ACK的报文段在另一个被称为CCECHO的选项中回显所接收到的CC值。
  6. 在一个非SYN报文段中的CC值检测和拒绝来自同一个连接的前一个替身的任何重复的报文段。

最小的事务序列是交换三个报文段:

  1. 由一个主动打开引起的客户到服务器:客户的SYN、客户的数据(请求)、客户的FIN以及客户的CC。当被动的服务器TCP接收到这个报文段的时候,如果客户的CC比为这个客户缓存的CC要大,则客户的数据被传送给服务器应用程序进行处理。
  2. 服务器到客户:服务器的SYN、服务器的数据(应答)、服务器的FIN、对客户的FIN的ACK、服务器的CC以及客户的CC的CCECHO。由于TCP的确认是累积的,这个对客户的FIN的ACK也对客户的SYN、数据及FIN进行了确认。
    当客户TCP接收到这个报文段,就将其传送给客户应用进程。
  3. 客户到服务器:对服务器的FIN的ACK,它也确认了服务器的SYN、数据和FIN。客户对它的请求的响应时间为RTT与SPT的和。

关于实现这个TCP选项的很好的地方。我们在这里将它们归纳如下:

  1. 服务器的SYN和ACK(第2个报文段)必须被迟延,从而允许应答与它一起捎带发送(通常对SYN的ACK是不迟延的)。但它也不能迟延得太多,否则客户将超时并引起重传。
  2. 请求可以需要多个报文段,但是服务器必须对它们可能失序达到的情况进行处理(通常当数据在SYN之前到达时,该数据被丢弃并产生一个复位。通过使用T/TCP,这些失序的数据将放入队列中处理)。
  3. API必须使服务器进程用一个单一的操作来发送数据和关闭连接,从而允许第二个报文段中的FIN与应答一起捎带发送(通常应用进程先写应答,从而引起发送一个数据报文段,然后关闭连接,引起发送FIN)。
  4. 在收到来自服务器的MSS通告之前,客户在第1个报文段中正在发送数据。为避免限制客户的MSS为536,一个给定主机的MSS应该与它的CC值一起缓存。
  5. 客户在没有接收到来自服务器的窗口通告之前也可以向服务器发送数据。T/TCP建议默认的窗口为4096,并且也为服务器缓存拥塞门限。
  6. 使用最小3个报文段交换,在每个方向上只能计算一个RTT。加上包括了服务器处理时间的客户测量RT T。这意味着被平滑的RTT及其方差的值也必须为服务器缓存起来,这与我们在21.9节描述的类似。

24.8 TCP的性能

下面这些实际限制适用于任何的实际情况。

  1. 不能比最慢的链路运行得更快。
  2. 不能比最慢的机器的内存运行得更快。这假定实现是只使用一遍数据。如果不是这样(也就是说,实现使用一遍数据是将它从用户空间复制到内核中,而使用另一遍数据是计算TCP的检验和),那么将运行得更慢。[Dalton et al.1993]描述了将数据复制数目减少从而使一个标准伯克利源程序的性能得到改进。[Partridge and Pink 1993]将类似的“复制与检验和”的改变与其他性能改进措施一道应用于UDP,从而将UDP的性能提高了约30%。
  3. 不能够比由接收方提供的窗口大小除以往返时间所得结果运行得更快(这就是带宽时延乘积公式,使用窗口大小作为带宽时延乘积,并解出带宽)。如果使用24.4节的最大窗口扩大因子14,则窗口大小为1.073千兆字节,所以这除以RTT的结果就是带宽的极限。

所有这些数字的重要意义就是TCP的最高运行速率的真正上限是由TCP的窗口大小和光速决定的。

第25章 SNMP:简单网络管理协议

25.1 引言

基于TCP/IP的网络管理包含两个部分:网络管理站(也叫管理进程,manager)和被管的网络单元(也叫被管设备)。被管设备种类繁多,例如:路由器、X终端、终端服务器和打印机等。

被管设备端和管理相关的软件叫做代理程序(agent)或代理进程。

管理进程和代理进程之间的通信可以有两种方式。一种是管理进程向代理进程发出请求,询问一个具体的参数值(例如:你产生了多少个不可达的ICMP端口?)。另外一种方式是代理进程主动向管理进程报告有某些重要的事件发生(例如:一个连接口掉线了)。

基于TCP/IP的网络管理包含3个组成部分:

  1. 一个管理信息库MIB(Management Information Base)。管理信息库包含所有代理进程的所有可被查询和修改的参数。RFC 1213 [McCloghrie and Rose 1991]定义了第二版的MIB,叫做MIB-II。
  2. 关于MIB的一套公用的结构和表示符号。叫做管理信息结构SMI(Structure of Management Information)。这个在RFC 1155 [Rose and McCloghrie 1990]中定义。例如:SMI定义计数器是一个非负整数,它的计数范围是0~4294 967 295,当达到最大值时,又从0开始计数。
  3. 管理进程和代理进程之间的通信协议,叫做简单网络管理协议SNMP(Simple Network Management Protocol)。在RFC 1157 [Case et al.1990]中定义。SNMP包括数据报交换的格式等。尽管可以在运输层采用各种各样的协议,但是在SNMP中,用得最多的协议还是UDP。

25.2 协议

关于管理进程和代理进程之间的交互信息,SNMP定义了5种报文:

  1. get-request操作:从代理进程处提取一个或多个参数值。
  2. get-next-request操作:从代理进程处提取一个或多个参数的下一个参数值(关于“下一个(next)”的含义将在后面的章节中介绍)。
  3. set-request操作:设置代理进程的一个或多个参数值。
  4. get-response操作:返回的一个或多个参数值。这个操作是由代理进程发出的。它是前面3中操作的响应操作。
  5. trap操作:代理进程主动发出的报文,通知管理进程有某些事情发生。

前面的3个操作是由管理进程向代理进程发出的。后面两个是代理进程发给管理进程的(为简化起见,前面3个操作今后叫做get、get-next和set操作)。

在SNMP中往往使用UDP协议,所以可能发生管理进程和代理进程之间数据报丢失的情况。因此一定要有超时和重传机制。

管理进程发出的前面3种操作采用UDP的161端口。代理进程发出的Tr ap操作采用UDP的162端口。由于收发采用了不同的端口号,所以一个系统可以同时为管理进程和代理进程。

在图中,我们仅仅对IP和UDP的首部长度进行了标注。这是由于:SNMP报文的编码采用了ASN.1和BER,这就使得报文的长度取决于变量的类型和值。关于ASN.1和BER的内容将在后面介绍。在这里介绍各个字段的内容和作用。

版本字段是0。该字段的值是通过SNMP版本号减去1得到的。显然0代表SNMP v1。

共同体字段是一个字符串。这是管理进程和代理进程之间的口令,是明文格式。默认的值是public。

对于get、get-next和set操作,请求标识由管理进程设置,然后由代理进程在getresponse中返回。

这个字段的作用是使客户进程(在目前情况下是管理进程)能够将服务器进程(即代理进程)发出的响应和客户进程发出的查询进行匹配。这个字段允许管理进程对一个或多个代理进程发出多个请求,并且从返回的众多应答中进行分类。

差错状态字段是一个整数,它是由代理进程标注的,PDU类型名称指明有差错发生。

差错索引字段是一个整数偏移量,指明当有差错发生时,差错发生在哪个参数。它是由代理进程标注的,并且只有在发生noSuchName、readOnly和badValue差错时才进行标注。

在get、get-next和set的请求数据报中,包含变量名称和变量值的一张表。对于get和get-next操作,变量值部分被忽略,也就是不需要填写。

25.3 管理信息结构

数据类型

  • INTEGER。一个变量虽然定义为整型,但也有多种形式。有些整型变量没有范围限制,有些整型变量定义为特定的数值(例如,IP的转发标志就只有允许转发时的1或者不允许转发时的2这两种),有些整型变量定义为一个特定的范围(例如,UDP和TCP的端口号就从0到65535)。
  • OCTERSTRING。0或多个8bit字节,每个字节值在0~255之间。对于这种数据类型和下一种数据类型的BER编码,字符串的字节个数要超过字符串本身的长度。这些字符串不是以NULL结尾的字符串。
  • DisplayString。0或多个8bit字节,但是每个字节必须是ASCII码(26.4中有ASCII字符集)。在MIB-II中,所有该类型的变量不能超过255个字符(0个字符是可以的)。
  • OBJECTIDENTIFIER 。将在下一节中介绍。
  • NULL。代表相关的变量没有值。例如,在get或get-next操作中,变量的值就是NULL,因为这些值还有待到代理进程处去取。
  • IpAddress。4字节长度的OCTER STRING,以网络序表示的IP地址。每个字节代表IP地址的一个字段。
  • PhysAddress。OCTER STRING类型,代表物理地址(例如以太网物理地址为6个字节长度)。
  • Counter。非负的整数,可从0递增到232-1(4294 976 295)。达到最大值后归0。
  • Gauge。非负的整数,取值范围为从0到4294 976 295(或增或减)。达到最大值后锁定,直到复位。例如,MIB中的tcpCurrEstab就是这种类型的变量的一个例子,它代表目前在ESTA BLISHED或CLOSE_WA IT状态的TCP连接数。
  • TimeTicks。时间计数器,以0.01秒为单位递增,但是不同的变量可以有不同的递增幅度。所以在定义这种类型的变量的时候,必须指定递增幅度。例如,MIB中的sysUpTime变量就是这种类型的变量,代表代理进程从启动开始的时间长度,以多少个百分之一秒的数目来表示。
  • SEQUENCE。这一数据类型与C程序设计语言中的“structure”类似。一个SEQUENCE包括0个或多个元素,每一个元素又是另一个ASN.1数据类型。例如,MIB中的UdpEntry就是这种类型的变量。它代表在代理进程侧目前“激活”的UDP数量(“激活”表示目前被应用程序所用)。在这个变量中包含两个元素:
    1. 1)IpAddress类型中的udpLocalAddress,表示IP地址。
    2. 2)INTEGER类型中的udpLocalPort,从0到65535,表示端口号。
  • SEQUENDEOF。这是一个向量的定义,其所有元素具有相同的类型。如果每一个元素都具有简单的数据类型,例如是整数类型,那么我们就得到一个简单的向量(一个一维向量)。但是我们将看到,SNMP在使用这个数据类型时,其向量中的每一个元素是一个SEQUENCE(结构)。因而可以将它看成为一个二维数组或表。

25.4 对象标识符

对象标识是一种数据类型,它指明一种“授权”命名的对象。“授权”的意思就是这些标识不是随便分配的,它是由一些权威机构进行管理和分配的。

对象标识是一个整数序列,以点(“.”)分隔。这些整数构成一个树型结构,类似于DNS(图14-1)或Unix的文件系统。对象标识从树的顶部开始,顶部没有标识,以root表示(这和Unix中文件系统的树遍历方向非常类似)。

所有的MIB变量都从1.3.6.1.2.1这个标识开始。

25.5 管理信息库介绍

所谓管理信息库,或者MIB,就是所有代理进程包含的、并且能够被管理进程进行查询和设置的信息的集合。

Case图

25.6 实例标识

当对MIB变量进行操作,如查询和设置变量的值时,必须对MIB的每个变量进行标识。首先,只有叶子结点是可操作的。SNMP没法处理表格的一整行或一整列。

25.6.1 简单变量

对于简单变量的处理方法是通过在其对象标识后面添加“.0”来处理的。

25.6.2 表格

每个MIB中的表格都指明一个以上的索引。对于UDP监听表来说,MIB定义了包含两个变量的联合索引,这两个变量是:udpLocalAddress,它是一个IP地址;udpLocalPort,它是一个整数(在图25-9中的第1行就显示了这个索引)。

假设在UDP监听表中有3行具体成员:第1行的IP地址是0.0.0.0,端口号是67;第2行的IP地址是0.0.0.0,端口号是161;第3行的IP地址是0.0.0.0,端口号是520。

这意味着系统将从端口67(BOOTP服务器)、端口161(SNMP)和端口520(RIP)接受来自任何接口的UDP数据报。

25.6.3 字典式排序

MIB中按照对象标识进行排序时有一个隐含的排序规则。MIB表格是根据其对象标识按照字典的顺序进行排序的。

1)在表格中,一个给定变量(在这里指udpLocalAddress)的所有实例都在下个变量(这里指udpLocalPort)的所有实例之前显示。这暗示表格的操作顺序是“先列后行”的次序。这是由于对对象标识进行字典式排序所得到的,而不是按照人们的阅读习惯而排列的。

2)表格中对行的排序和表格中索引的值有关。在图2513中,67的字典序小于161,同样161的字典序小于520。

25.7.1 简单变量

25.7.2 get-next操作

get-next操作是基于MIB的字典式排序的。

25.7.3 表格的访问

对于“先列后行”次序的UDP监听表,只要采用前面的简单查询程序一步一步地进行操作,就可以遍历整个表格。只要从询问代理进程udpTable的下一个变量开始就可以了。由于udpTable不是叶子对象,我们不能指定一个实例,但是get-next操作依然能够返回表格中的下一个对象。然后就可以以返回的结果为基础进行下一步的操作,代理进程也会以“先列后行”的次序返回下一个变量,这样就可以遍历整个表格。

25.8 管理信息库(续)

MIB组:system(系统标识)、if(接口)、at(地址转换)、ip、icmp和tcp。

25.8.1 system组

system组非常简单,它包含7个简单变量(例如,没有表格)。

25.8.2 interface组

25.8.3 at组

25.8.4 ip 组

25.8.5 icmp组

icmp组包含4个普通计数器变量(ICMP报文的输出和输入数量以及ICMP差错报文的输入和输出数量)和22个其他ICMP报文数量的计数器:11个是输出计数器,另外11个是输入计数器。

25.8.6 tcp组

25.9 其他一些例子

25.9.1 接口MTU

25.9.2 路由表

25.10 Trap

25.11 ASN.1和BER

25.12 SNMPv2

SNMPv1和SNMPv2之间的重要区别。

  1. 在SNMPv2中定义了一个新的分组类型get-bulk-request,它高效率地从代理进程读取大块数据。
  2. 另的一个新的分组类型是inform-request,它使一个管理进程可以向另一个管理进程发送信息。
  3. 定义了两个新的MIB,它们是:SNMPv2 MIB和SNMPv2-M2M MIB(管理进程到管理进程的MIB)。
  4. SNMPv2的安全性比SNMPv1大有提高。在SNMPv1中,从管理进程到代理进程的共同体名称是以明文方式传送的。而SNMPv2可以提供鉴别和加密。

第26章 Telnet和Rlogin:远程登录

26.1 引言

在TCP/IP网络上,有两种应用提供远程登录功能。

  1. Telnet是标准的提供远程登录功能的应用,几乎每个TCP/IP的实现都提供这个功能。它能够运行在不同操作系统的主机之间。Telnet通过客户进程和服务器进程之间的选项协商机制,从而确定通信双方可以提供的功能特性。
  2. Rlogin起源于伯克利Unix,开始它只能工作在Unix系统之间,现在已经可以在其他操作系统上运行。

远程登录采用客户-服务器模式。

在这张图中,有以下要点需要注意:

  1. Telnet客户进程同时和终端用户和TCP/IP协议模块进行交互。通常我们所键入的任何信息的传输是通过TCP连接,连接的任何返回信息都输出到终端上。
  2. Telnet服务器进程经常要和一种叫做“伪终端设备”(pseudo-terminal device)打交道,至少在Unix系统下是这样的。这就使得对于登录外壳(shell)进程来讲,它是被Te lnet服务器进程直接调用的,而且任何运行在登录外壳进程处的程序都感觉是直接和一个终端进行交互。对于像满屏编辑器这样的应用来讲,就像直接在和终端打交道一样。实际上,如何对服务器进程的登录外壳进程进行处理,使得它好像在直接和终端交互,往往是编写远程登录服务器进程程序中最困难的方面之一。
  3. 仅仅使用了一条TCP连接。由于客户进程必须多次和服务器进程进行通信(反之亦然),这就必然需要某些方法,来描绘在连接上传输的命令和用户数据。我们在后面的内容中会介绍Telnet和Rlogin是如何处理这个问题的。
  4. 注意在图26-1中,我们用虚线框把终端驱动进程和伪终端驱动进程框了起来。在TCP/IP实现中,虚线框的内容一般是操作系统内核的一部分。Telnet客户进程和服务器进程一般只是属于用户应用程序。
  5. 把服务器进程的登录外壳进程画出来的目的是为了说明:当我们想登录到系统的时候,必须要有一个帐号,Telnet和Rlogin都是如此。

26.2 Rlogin协议

26.2.1 应用进程的启动

Rlogin的客户进程和服务器进程使用一个TCP连接。当普通的TCP连接建立完毕之后,客户进程和服务器进程之间将发生下面所述的动作。

  1. 客户进程给服务器进程发送4个字符串:(a)一个字节的0;(b)用户登录进客户进程主机的登录名,以一个字节的0结束;(c)登录服务器进程端主机的登录名,以一个字节的0结束;(d)用户终端类型名,紧跟一个正斜杠“/”,然后是终端速率,以一个字节的0结束。在这里需要两个登录名字,这是因为用户登录客户和服务器的名称有可能不一样。由于大多满屏应用程序需要知道终端类型,所以终端类型也必须发送到服务器进程。发送终端速率的原因是因为有些应用随着速率的改变,它的操作也有所变化。例如vi编辑器,当速率比较小的时候,它的工作窗口也变小。所以它不能永远保持同样大小的窗口。
  2. 服务器进程返回一个字节的0。
  3. 服务器进程可以选择是否要求用户输入口令。这个步骤的数据交互没有什么特别的协议,而被当作是普通的数据进行传输。服务器进程给客户进程发送一个字符串(显示在客户进程的屏幕上),通常是password:。如果在一定的限定时间内(通常是60秒)客户进程没有输入口令,服务器进程将关闭该连接。
    通常可以在服务器进程的主目录(home directory)下生成一个文件(通常叫 .rhosts),该文件的某些行记录了一个主机名和用户名。如果从该文件中已经记录的主机上用已经记录的用户名进行登录,服务器进程将不提示我们输入口令。但是很多关于安全性的文献,如[Curry 1992],强烈建议不要采用这种方法,因为这存在安全漏洞。
    如果提示输入口令,那么我们输入的口令将以明文的形式发送到服务器进程。我们所键入的每个字符都是以明文的格式传输的。所以某人只要能够截取网络上的原始传输的分组,他就可以截获用户口令。针对这个问题,新版本的Rlogin客户程序,例如4.4BSD版本的客户程序,第一次采用了Kerberos安全模型。Kerberos安全模型可以避免用户口令以明文的形式在网络上传输。当然,这要求服务器进程也支持Kerberos([Curry 1992]详细描述了Kerberos安全模型)。
  4. 服务器进程通常要给客户进程发送请求,询问终端的窗口大小(将在后面解释)。

26.2.2 流量控制

26.2.3 客户的中断键

26.2.4 窗口大小的改变

对于远程登录这种情况,窗口大小的变化发生在客户端,而运行在服务器端的应用程序需要知道窗口大小变化。所以Rlogin的客户需要采用某些方法来通知服务器窗口大小变化的情况以及新窗口的大小。

26.2.5 服务器到客户的命令

采用TCP紧急方式发送这些命令的一个原因是第一个命令(“清仓输出(flush output)”)需要立即发送给客户,即使服务器到客户的数据流被窗口流量控制所终止。这种情况下,即服务器到客户的输出被流量控制所终止的情况是经常发生的,这是因为运行在服务器的进程的输出速率通常大于客户终端的显示速率。

另一方面,客户到服务器的数据流很少被流量控制所终止,因为这个方向的数据流仅仅包含用户所键入的字符。

26.2.6 客户到服务器的命令

26.2.7 客户的转义符

要和Rlogin客户进程直接通信。方法是在一行的开头键入代字符(tilde)“~”,紧跟着是下列4个字符之一:

  1. 以一个句号结束客户进程。
  2. 以文件结束符(通常是Control_D)结束客户进程。
  3. 以任务控制挂起符(通常是Control_Z)挂起客户进程。
  4. 以任务控制延迟挂起符(通常是Control_Y)来挂起仅仅是客户进程的输入。这时,不管客户运行什么程序,键入的任何信息将由该程序进行解释,但是从服务器发送到客户的信息还是输出到终端上。这非常适合当我们需要在服务器上运行一个长时间程序的场合,我们既想知道该程序的输出结果,同时还想在客户上运行其他程序。

只有当客户进程的Unix系统支持任务控制时,后两个命令才有效。

26.3 Rlogin的例子

26.3.1 初始的客户-服务器协议

26.3.2 客户中断键

下面这些要点是关于客户、服务器和连接的状态的概述:

  1. 键入Control_S以停止终端的输出。
  2. 用户终端的输出缓存很快被填满,所以Rlogin的客户向终端的写操作被阻塞。
  3. 此时客户也不能从网络连接上读取数据,所以客户的TCP接收缓存也将被填满。
  4. 当接收缓存已满时,客户进程的TCP会向服务器进程的TCP通告现在的接收窗口是0。
  5. 当服务器收到客户的窗口为0时,将停止向客户发送数据,这样,服务器的发送缓存也将被填满。
  6. 由于发送缓存已满,所以Rlogin服务器进程将停止。这样,Rlogin服务器将不能从服务器运行的应用程序(cat)处读取数据。
  7. 当cat程序的输出缓存也被填满时,cat也将停止。
  8. 然后我们用中断键来终止服务器上的cat程序。这个命令从客户的TCP传输到服务器的TCP,这是因为该方向的数据传输没有被流量控制所终止。
  9. cat应用程序收到中断命令并且终止。这使得它的输出缓存(也就是Rlogin服务器进程读取数据的地方)被清空,这将唤醒Rlogin服务器进程。然后Rlogin服务器进程进入紧急方式,向客户进程发送“清仓输出”命令(0x02)。

26.4 Telnet协议

26.4.1 NVT ASCII

术语NVT ASCII代表7比特的ASCII字符集,网间网协议族都使用NVT ASCII。每个7比特的字符都以8比特格式发送,最高位比特为0。

行结束符以两个字符CR(回车)和紧接着的LF(换行)这样的序列表示。以\r\n来表示。单独的一个CR也是以两个字符序列来表示,它们是CR和紧接着的NUL(字节0),以\r\0表示。

26.4.2 Telnet命令

26.4.3 选项协商

对于任何给定的选项,连接的任何一方都可以发送下面4种请求的任意一个请求。

  1. WILL:发送方本身将激活(enable)选项。
  2. DO:发送方想叫接收端激活选项。
  3. WONT:发送方本身想禁止选项。
  4. DON’T:发送方想让接收端去禁止选项。

26.4.4 子选项协商

首先连接的某一方(通常是客户进程)发送3个字节的字符序列来请求激活该选项。

这里的24(十进制)是终端类型选项的ID号。如果收端(通常是服务器进程)同意,那么响应数据是:

然后服务器进程再发送如下的字符串:

该字符串询问客户进程的终端类型。其中SB是子选项协商的起始命令标志。下一个字节的“24”代表这是终端类型选项的子选项(通常SB后面的选项值就是子选项所要提交的内容)。下一个字节的“1”表示“发送你的终端类型”。子选项协商的结束命令标志也是IAC,就像SB是起始命令标志一样。如果终端类型是ibmpc,客户进程的响应命令将是:

第4个字节“0”代表“我的终端类型是”(在Assigned Numbers RFC文档中有正式的关于终端类型的数值定义,但是最起码在Unix系统之间,终端类型可以用任何对方可理解的数据进行表示。只要这些数据在termcap或terminfo数据库中有定义)。在Te lnet子选项协商过程中,终端类型用大写表示,当服务器收到该字符串后会自动转换为小写字符。

26.4.5 半双工、一次一字符、一次一行或行方式

1. 半双工

这是Telnet的默认方式,但现在却很少使用。NVT默认是一个半双工设备,在接收用户输入之前,它必须从服务器进程获得GO AHEAD(GA)命令。用户的输入在本地回显,方向是从NVT键盘到NVT打印机,所以客户进程到服务器进程只能发送整行的数据。

虽然该方式适用于所有类型的终端设备,但是它不能充分发挥目前大量使用的支持全双工通信的终端功能。

2. 一次一个字符方式

所键入的每个字符都单独发送到服务器进程。服务器进程回显大多数的字符,除非服务器进程端的应用程序去掉了回显功能。

缺点:当网络速度很慢,而且网络流量比较大的时候,那么回显的速度也会很慢。虽然如此,但目前大多数Te lnet实现都把这种方式作为默认方式。

如果要进入这种方式,只要激活服务器进程的SUPPRESS GO AHEAD选项即可。这可以通过由客户进程发送DO SUPPRESS GO AHEAD(请求激活服务器进程的选项)请求完成,也可以通过服务器进程给客户进程发送WILL SUPPRESS GO AHEAD(服务器进程激活选项)请求来完成。服务器进程通常还会跟着发送WILL ECHO,以使回显功能有效。

3. 一次一行方式

准行方式

该RFC规定:如果要实现带远程回显的一次一个字符方式,ECHO选项和SUPPRESS GO AHEAD选项必须同时有效。准行方式采用这种方式来表示当两个选项的其中之一无效时,Telnet就是工作在一次一行方式。在下节中我们将介绍一个例子,可以看到如何协商进入该方式,并且当程序需要接收每个击键时如何使该方式失效。

4. 行方式

通过客户进程和服务器进程进行协商而确定的,它纠正了准行方式的所有缺陷。

“char”表示一次一个字符方式,“kludge”表示准行方式,“linemode”表示如RFC 1184定义的实行方式。

26.4.6 同步信号

Telnet以Data Mark命令(即图26-8中的DM)作为同步信号,该同步信号是以TCP紧急数据形式发送的。DM命令是随数据流传输的同步标志,它告诉收端回到正常的处理过程上来。Telnet的双方都可以发送该命令。

当一端收到对方已经进入了紧急方式的通知后,它将开始读数据流,一边读一边丢弃所读的数据,直到读到Telnet命令为止。紧急数据的最后一个字节就是DM字节。采用TCP紧急方式的原因就是:即使TCP数据流已经被TCP流量控制所终止,Telnet命令也可以在连接上传输。

26.4.7 客户的转义符

通常客户的转义字符是Control_](control键和右中括号键,通常以“^]”表示)。

26.5 Telnet举例

26.5.1 单字符方式(举例)

用户在终端输入的每个字符都将由终端发送到服务器进程,服务器进程的响应也将以字符方式回显到终端上。

26.5.2 行方式(举例)

26.5.3 一次一行方式(准行方式)

当客户进程不支持行方式时,BSD/386服务器进程如何协商进入该方式。

  1. 当客户进程不同意服务器进程激活行方式的请求时,服务器进程发送DO TIMING MARK选项。RFC 860 [Postel和Reynolds 1983f]定义了这个Telnet选项。它的作用是让收发双方同步,关于这个问题将在本节的后面讲到用户键入中断键时讨论。该选项只是用来判断客户进程是否支持准行方式。
  2. 客户响应WILL TIMING MARK,表明支持准行方式。
  3. 服务器发送WONT SUPPRESS GO AHEAD和WONT ECHO选项,告诉客户它希望禁止这两个选项。我们在前面已经强调:单个字符方式下是假定SUPPRESS GO AHEAD和ECHO选项同时有效的,所以禁止两个选项就进入了准行方式。
  4. 客户响应DONT SUPPRESS GO AHEAD和DONT ECHO命令。
  5. 服务器发送login:提示符,然后用户键入用户名。用户名是以整行的方式发送给服务器,回显由客户进程在本地处理。
  6. 服务器发送Password:提示符和WILL ECHO命令。这将使客户进程的回显失效,因为此时客户进程认为服务器进程将处理回显工作,所以用户键入的口令就不回显到屏幕上。客户响应DO ECHO命令。
  7. 我们键入口令。客户以整行方式发送到服务器。
  8. 服务器发送WONT ECHO命令,使得客户重新激活回显功能,客户响应DONT ECHO。从此以后的普通命令处理过程就和行方式相似了。客户进程负责所有的编辑和回显,并以整行的方式发送给服务器进程。

26.5.4 行方式:客户中断键

第27章 FTP:文件传送协议

27.1 引言

FTP是另一个常见的应用程序。它是用于文件传输的Internet标准。

我们必须分清文件传送(file transfer)和文件存取(file access)之间的区别,前者是FTP提供的,后者是如NFS(Sun的网络文件系统,第29章)等应用系统提供的。由FTP提供的文件传送是将一个完整的文件从一个系统复制到另一个系统中。要使用FTP,就需要有登录服务器的注册帐号,或者通过允许匿名FTP的服务器来使用。

27.2 FTP协议

FTP采用两个TCP连接来传输一个文件。

  1. 控制连接以通常的客户服务器方式建立。服务器以被动方式打开众所周知的用于FTP的端口(21),等待客户的连接。客户则以主动方式打开TCP端口21,来建立连接。控制连接始终等待客户与服务器之间的通信。该连接将命令从客户传给服务器,并传回服务器的应答。
    由于命令通常是由用户键入的,所以IP对控制连接的服务类型就是“最大限度地减小迟延”。
  2. 每当一个文件在客户与服务器之间传输时,就创建一个数据连接。(其他时间也可以创建,后面我们将说到)。
    由于该连接用于传输目的,所以IP对数据连接的服务特点就是“最大限度提高吞吐量”。

27.2.1 数据表示

1. 文件类型

  1. ASCII码文件类型(默认选择)文本文件以NVT ASCII码形式在数据连接中传输。这要求发方将本地文本文件转换成NVT ASCII码形式,而收方则将NVT ASCII码再还原成本地文本文件。其中,用NVT ASCII码传输的每行都带有一个回车,而后是一个换行。这意味着收方必须扫描每个字节,查找CR、LF对(我们在第15.2节见过的关于TFIP的ASCII码文件传输情况与此相同)。
  2. EBCDIC文件类型该文本文件传输方式要求两端都是EBCDIC系统。
  3. 图像文件类型(也称为二进制文件类型)数据发送呈现为一个连续的比特流。通常用于传输二进制文件。
  4. 本地文件类型该方式在具有不同字节大小的主机间传输二进制文件。每一字节的比特数由发方规定。对使用8bit字节的系统来说,本地文件以8bit字节传输就等同于图像文件传输。

2. 格式控制

该选项只对ASCII和EBCDIC文件类型有效。

  1. 非打印(默认选择)文件中不含有垂直格式信息。
  2. 远程登录格式控制文件含有向打印机解释的远程登录垂直格式控制。
  3. Fortran回车控制每行首字符是Fortran格式控制符。

3. 结构

  1. 文件结构(默认选择)文件被认为是一个连续的字节流。不存在内部的文件结构。
  2. 记录结构该结构只用于文本文件(ASCII或EBCDIC)。
  3. 页结构每页都带有页号发送,以便收方能随机地存储各页。该结构由TO PS-20操作系统提供(主机需求RFC不提倡采用该结构)。

4. 传输方式

它规定文件在数据连接中如何传输。

  1. 流方式(默认选择)文件以字节流的形式传输。对于文件结构,发方在文件尾提示关闭数据连接。对于记录结构,有专用的两字节序列码标志记录结束和文件结束。
  2. 块方式文件以一系列块来传输,每块前面都带有一个或多个首部字节。
  3. 压缩方式一个简单的全长编码压缩方法,压缩连续出现的相同字节。在文本文件中常用来压缩空白串,在二进制文件中常用来压缩0字节(这种方式很少使用,也不受支持。现在有一些更好的文件压缩方法来支持FTP)。

27.2.2 FTP命令

27.2.3 FTP应答

27.2.4 连接管理

数据连接有以下三大用途:

  1. 从客户向服务器发送一个文件。
  2. 从服务器向客户发送一个文件。
  3. 从服务器向客户发送文件或目录列表。

通用传输方式(Unix环境下唯一的传输方式)是流方式,并且文件结尾是以关闭数据连接为标志。这意味着对每一个文件传输或目录列表来说都要建立一个全新的数据连接。其一般过程如下:

  1. 正由于是客户发出命令要求建立数据连接,所以数据连接是在客户的控制下建立的。
  2. 客户通常在客户端主机上为所在数据连接端选择一个临时端口号。客户从该端口发布一个被动的打开。
  3. 客户使用PORT命令从控制连接上把端口号发向服务器。
  4. 服务器在控制连接上接收端口号,并向客户端主机上的端口发布一个主动的打开。服务器的数据连接端一直使用端口20。

27.3 FTP的例子

27.3.1 连接管理:临时数据端口

27.3.2 连接管理:默认数据端口

27.3.3 文本文件传输:NVT ASCII表示还是图像表示

新客户试图确定服务器是否是相同类型的系统,一旦相同,就可以用二进制码(图像文件类型)来传输文件,而不是ASCII码。这可以获得两个方面的好处:

  1. 发方和收方不必查看每一字节(很大的节约)。
  2. 如果主机操作系统使用比2字节的NVT ASCII码序列更少的字节来作行尾,就会传输更少的字节数(很小的节约)。

27.3.4 异常中止一个文件的传输:Telnet同步信号

27.3.5 匿名FTP

27.3.6 来自一个未知IP地址的匿名FTP

第28章 SMTP:简单邮件传送协议

28.1 引言

28.2 SMTP协议

28.2.1 简单例子

只有5个SMTP命令用于发送邮件:HELO,MAIL,RCPT,DATA和QUIT。

客户用HELO命令标识自己。参数必须是完全合格的的客户主机名。

MAIL命令标识出报文的发起人。

RCPT,标识接收方。如果有多个接收方,可以发多个RCPT命令。

邮件报文的内容由客户通过DATA命令发送。报文的末尾由客户指定,是只有一个句点的一行。最后的命令QUIT,结束邮件的交换。

28.2.2 SMTP命令

最小SMTP实现支持8种命令。

HELO,MAIL,RCPT,DATA和QUIT。

RSET命令异常中止当前的邮件事务并使两端复位。丢掉所有有关发送方、接收方或邮件的存储信息。

VRFY命令使客户能够询问发送方以验证接收方地址,而无需向接收方发送邮件。通常是系统管理员在查找邮件交付差错时手工使用的。

NOOP命令除了强迫服务器响应一个OK应答码(200)外,不做任何事情。

EXPN扩充邮件表,与VRFY类似,通常是由系统管理员使用的。

TURN命令使客户和服务器交换角色,无需拆除TCP连接并建立新的连接就能以相反方向发送邮件(Sendmail不支持这个命令)。

28.2.3 信封、首部和正文

电子邮件由三部分组成:

  1. 信封(envelope)是MTA用来交付的。
  2. 首部由用户代理使用。在我们的例子中可以看到9个首部字段:Received、Message-Id、From、Data、Reply-To、X-Phone、X-Mailer、To和Subject。每个首部字段都包含一个名,紧跟一个冒号,接着是字段值。RFC 822指明了首部字段的格式的解释(以X-开始的首部字段是用户定义的字段,其他是由RFC 822定义的)。长首部字段,如例子中的Received,被折在几行中,多余行以空格开头。
  3. 正文(body)是发送用户发给接收用户报文的内容。RFC 822指定正文为NVT ASCII文字行。当用DATA命令发送时,先发送首部,紧跟一个空行,然后是正文。用DATA命令发送的各行都必须小于1000字节。

28.2.4 中继代理

28.2.5 NVT ASCII

SMTP的一个特色是它用NVT ASCII表示一切:信封、首部和正文。正如我们在26.4节中谈到的,这是一个7bit的字符码,以8bit字节发送,高位比特被置为0。

28.2.6 重试间隔

28.3 SMTP的例子

28.3.1 MX记录:主机非直接连到Internet

DNS中的一种资源记录类型是邮件交换记录,称为MX记录。

28.3.2 MX记录:主机出故障

MX记录的另一个用途是在目的主机出故障时可提供另一个邮件接收器。

28.3.3 VRFY和EXPN命令

VRFY命令无需发送邮件而验证某个接收方地址是否OK。

EXPN的目的是无需向邮件表发送邮件就可以扩充该表。

28.4 SMTP的未来

28.4.1 信封的变化:扩充的SMTP

28.4.2 首部变化:非ASCII字符

首部字段中可以包含编码字(coded word)。它们具有以下格式:

=?charset?encoding?encoded-text?=

charset是字符集规范。有效值是两个字符串us-ascii和iso-8859-x,其中x是一个单个数字,例如在iso-8859-1中的数字“1”。

encoding是一个单个字符用来指定编码方法,支持两个值。

  1. Q编码意思是引号中可打印的(quoted-printable),目的是用于拉丁字符集。大多数字符是作为NVT ASCII(当然最高位比特置0)发送的。任何要发送的字符若其第8比特置1则被作为3个字符发送:第1个是字符是“=”,跟着两个十六进制数。例如,字符é(它的二进制8bit值为0xe9)作为三个字符发送:=E9。空格通常作为下划线或三个字符=20发送。这种编码的目的在于,某些文本中除了大多数ASCII字符外,还有几个特殊字符。
  2. B意思是以64为基数的编码。文本中的3个连续字节(24bit)被编码成4个6bit值。用于表示所有可能的6bit值的64个NVT ASCII字符如图28-6所示。当要编码的个数不是3的倍数时,等号符“=”被用作填充符。

28.4.3 正文变化:通用Internet邮件扩充

在RFC 1521中定义了5种不同的编码格式:

  1. 7bit,是默认的NVT ASCII;
  2. quoted-printable,我们在前面的一个例子中看到有非ASCII首部。当字符中只有很少一部分的第8bit置1时非常有用;
  3. base64,如图28-6所示;
  4. 8bit,包含字符行,其中某些为非ASCII字符且第8bit置1;
  5. binary编码,无需包含多行的8 bit数据。

RFC 1521推荐有非ASCII数据的text使用quoted-printable,而image、audio、video和octet-stream application使用base64。这样允许与符合RFC 821的MTA保持最大的互操作性。而且,multipart和message内容类型必须以7bit编码。

第29章 网络文件系统

29.1 引言

29.2 Sun远程过程调用

远程过程调用RPC(Remote Procedure Call)是一种不同的网络程序设计方法。客户程序编写时只是调用了服务器程序提供的函数。这只是程序员所感觉到的,实际上发生了下面一些动作。

  1. 当客户程序调用远程的过程时,它实际上只是调用了一个位于本机上的、由RPC程序包生成的函数。这个函数被称为客户残桩(stub)。客户残桩将过程的参数封装成一个网络报文,并且将这个报文发送给服务器程序。
  2. 服务器主机上的一个服务器残桩负责接收这个网络报文。它从网络报文中提取参数,然后调用应用程序员编写的服务器过程。
  3. 当服务器函数返回时,它返回到服务器残桩。服务器残桩提取返回值,把返回值封装成一个网络报文,然后将报文发送给客户残桩。
  4. 客户残桩从接收到的网络报文中取出返回值,将其返回给客户程序。

一个RPC程序包提供了很多好处。

  1. 程序设计更加容易,因为很少或几乎没有涉及网络编程。应用程序设计员只需要编写一个客户程序和客户程序调用的服务器过程。
  2. 如果使用了一个不可靠的协议,如UDP,像超时和重传等细节就由RPC程序包来处理。这就简化了用户应用程序。
  3. RPC库为参数和返回值的传输提供任何需要的数据转换。例如,如果参数是由整数和浮点数组成的,RPC程序包处理整数和浮点数在客户机和服务器主机上存储的不同形式。这个功能简化了在异构环境中的客户和服务器的编码问题。

Sun RPC

SunRPC有两个版本。

一个版本建立在插口API基础上,和TCP和UDP打交道。

另一个称为TI-RPC的(独立于运输层),建立在TLIAPI基础上,可以和内核提供的任何运输层协议打交道。

事务标识符(XID)由客户程序设置,由服务器程序返回。当客户收到一个应答,它将服务器返回的XID与它发送的请求的XID相比较。如果不匹配,客户就放弃这个报文,等待从服务器返回的下一个报文。每次客户发出一个新的RPC,它就会改变报文的XID。但是如果客户重传一个以前发送过的RPC(因为它没有收到服务器的一个应答),重传报文的XID不会修改。

调用(call)变量在过程调用报文中设置为0,在应答报文中设置为1。当前的RPC版本是2。接下来三个变量:程序号、版本号和过程号,标识了服务器上被调用的特定过程。

证书(credential)字段标识了客户。有些情况下,证书字段设置为空值;另外一些情况下,证书字段设置为数字形式的客户的用户号和组号。服务器可以查看证书字段以决定是否执行请求的过程。验证(verifier)字段用于使用了DES加密的安全RPC。尽管证书字段和验证字段是可变长度的字段,它们的长度也作为字段的一部分被编码。

接下来是过程参数(procedure parameter)字段。参数的格式依赖于远程过程的定义。

接收者(服务器残桩)如何知道参数字段的大小呢?既然使用的是UDP协议,UDP数据报的大小减去验证字段以上所有字段的长度就是参数的大小。如果使用的不是UDP而是TCP,因为TCP是一个字节流协议,没有记录边界,所以没有固定的长度。为了解决这个问题,在TCP首部和XID之间增加了一个4字节的长度字段,告诉接收者这个RPC调用由多少字节组成。这也使得一个RPC调用报文在必要时可以用多个TCP段来传输

29.3 XDR:外部数据表示

外部数据表示XDR(eXternal Data Representation)是一个标准,用来对RPC调用报文和应答报文中的值进行编码。这些值包括RPC首部字段(XID、程序号、接受状态等)、过程参数和过程结果。

29.4 端口映射器

包含远程过程的RPC服务器程序使用的是临时端口,而不是知名端口。这就需要某种形式的“注册”程序来跟踪哪一个RPC程序使用了哪一个临时端口。在Sun RPC中,这个注册程序被称为端口映射器(port mapper)。

端口映射器本身必须有一个知名端口:UDP端口111和TCP端口111。端口映射器也就是一个RPC服务器程序。它有一个程序号(100000)、一个版本号(2)、一个TCP端口111和一个UDP端口111。服务器程序使用RPC调用向端口映射器注册自身,客户程序使用RPC调用向端口映射器查询。端口映射器提供四个服务过程:

  1. PMAPPROC_SET。一个RPC服务器启动时调用这个过程,注册一个程序号、版本号和带有一个端口号的协议。
  2. PMAPPROC_UNSET。RPC服务器调用此过程来删除一个已经注册的映射。
  3. PMAPPROC_GETPORT。一个RPC客户启动时调用此过程。根据一个给定的程序号、版本号和协议来获得注册的端口号。
  4. PMAPPROC_DUMP。返回端口映射器数据库中所有的记录(每个记录包括程序号、版本号、协议和端口号)。

在一个RPC服务器程序启动,接着被一个RPC客户程序调用的过程中,进行了以下一些步骤:

  1. 一般情况下,当系统引导时,端口映射器必须首先启动。它创建一个TCP端点,并且被动打开TCP端口111。它也创建一个UDP端点,并且在UDP端口111等待着UDP数据报的到来。
  2. 当RPC服务器程序启动时,它为它所支持的程序的每一个版本创建一个TCP端点和一个UDP端点(一个给定的RPC程序可以支持多个版本。客户调用一个服务器过程时,说明它想要哪一个版本)。两个端点各自绑定一个临时端口(TCP端口号和UDP端口号是否一致无关紧要)。服务器通过RPC调用端口映射器的PMAPPROC_SET过程,注册每一个程序、版本、协议和端口号。
  3. 当RPC客户程序启动时,它调用端口映射器的PMAPPROC_GETPORT过程来获得一个指定程序、版本和协议的临时端口号。
  4. 客户发送一个RPC调用报文给第3步返回的端口号。如果使用的是UDP,客户只是发送一个包含RPC调用报文(见图29-1)的UDP数据报到服务器相应的UDP端口。服务器发送一个包含RPC应答报文(见图29-2)的UDP数据报到客户作为响应。

29.5 NFS协议

  1. 访问的是一个本地文件还是一个NFS文件对于客户来说是透明的。当文件被打开时,由内核决定这一点。文件被打开之后,内核将本地文件的所有引用传递给名为“本地文件访问”的框中,而将一个NFS文件的所有引用传递给名为“NFS客户”的框中。
  2. NFS客户通过它的TCP/IP模块向NFS服务器发送RPC请求。NFS主要使用UDP,最新的实现也可以使用TCP。
  3. NFS服务器在端口2049接收作为UDP数据报的客户请求。尽管NFS可以被实现成使用端口映射器,允许服务器使用一个临时端口,但是大多数的实现都是直接指定UDP端口2049。
  4. 当NFS服务器收到一个客户请求时,它将这个请求传递给本地文件访问例程,后者访问服务器主机上的一个本地的磁盘文件。
  5. NFS服务器需要花一定的时间来处理一个客户的请求。访问本地文件系统一般也需要一部分时间。在这段时间间隔内,服务器不应该阻止其他的客户请求得到服务。为了实现这一功能,大多数的NFS服务器都是多线程的—即服务器的内核中实际上有多个NFS服务器在运行。具体怎么实现依赖于不同的操作系统。既然大多数的Unix内核不是多线程的,一个共同的技术就是启动一个用户进程(常被称为nfsd)的多个实例。这个实例执行一个系统调用,使自己作为一个内核进程保留在操作系统的内核中。
  6. 同样,在客户主机上,NFS客户需要花一定的时间来处理一个用户进程的请求。NFS客户向服务器主机发出一个RPC调用,然后等待服务器的应答。为了给使用NFS的客户主机上的用户进程提供更多的并发性,在客户内核中一般运行着多个NFS客户。同样,具体实现也依赖于操作系统。Unix系统经常使用类似于NFS服务器的技术:一个叫作biod的用户进程执行一个系统调用,作为一个内核进程保留在操作系统的内核中。

29.5.1 文件句柄

NFS中一个基本概念是文件句柄(file handle)。它是一个不透明(opaque)的对象,用来引用服务器上的一个文件或目录。不透明指的是服务器创建文件句柄,把它传递给客户,然后客户访问文件时,使用对应的文件句柄。客户不会查看文件句柄的内容—它的内容只对服务器有意义。

29.5.2 安装协议

  1. 服务器上的端口映射器一般在服务器主机引导时被启动。
  2. 安装守护程序(mountd)在端口映射器之后被启动。它创建了一个TCP端点和一个UDP端点,并分别赋予一个临时的端口号。然后它在端口映射器中注册这些端口号。
  3. 在客户机上执行mount命令,它向服务器上的端口映射器发出一个RPC调用来获得服务器上安装守护程序的端口号。客户和端口映射器交互既可以使用TCP也可以使用UDP,但一般使用UDP。
  4. 端口映射器应答以安装守护程序的端口号。
  5. mount命令向安装守护程序发出一个RPC调用来安装服务器上的一个文件系统。同样,既可以使用TCP也可以使用UDP,但一般使用UDP。服务器现在可以验证客户,使用客户的IP地址和端口号来判别是否允许客户安装指定的文件系统。
  6. 安装守护程序应答以指定文件系统的文件句柄。
  7. 客户机上的mount命令发出mount系统调用将第5步返回的文件句柄与客户机上的一个本地安装点联系起来。文件句柄被存储在NFS客户代码中,从现在开始,用户进程对于那个服务器文件系统的任何引用都将从使用这个文件句柄开始。

29.5.3 NFS过程

  1. GETATTR。返回一个文件的属性:文件类型(一般文件,目录等)、访问权限、文件大小、文件的属主者及上次访问时间等信息。
  2. SETATTR。设置一个文件的属性。只允许设置文件属性的一个子集:访问权限、文件的属主、组的属主、文件大小、上次访问时间和上次修改时间。
  3. STATFS。返回一个文件系统的状态:可用空间的大小、最佳传送大小等。例如Unix的df命令使用此过程。
  4. LOOKUP。查找一个文件。每当一个用户进程打开一个NFS服务器上的一个文件时,NFS客户调用此过程。
  5. READ。从一个文件中读数据。客户说明文件的句柄、读操作的开始位置和读数据的最大字节数(最多8192个字节)。
  6. WRITE。对一个文件进行写操作。客户说明文件的句柄、开始位置、写数据的字节数和要写的数据。
  7. CREATE。创建一个文件。
  8. REMOVE。删除一个文件。
  9. RENAME。重命名一个文件。
  10. LINK。为一个文件构造一个硬链接。硬链接是一个Unix的概念,指的是磁盘中的一个文件可以有任意多个目录项(即名字,也叫作硬链接)指向它。
  11. SYMLINK。为一个文件创建一个符号链接。符号链接是一个包含另一个文件名字的文件。大多数引用符号链接的操作(例如,打开)实际上引用的是符号链接所指的文件。
  12. READLINK。读一个符号链接。即返回符号链接所指的文件的名字。
  13. MKDIR。创建一个目录。
  14. RMDIR。删除一个目录。
  15. READDIR。读一个目录。例如,Unix的ls命令使用此过程。

29.5.4 UDP还是TCP

29.5.5 TCP上的NFS

  1. 当服务器主机进行引导时,它启动一个NFS服务器,后者被动打开TCP端口2049,等待着客户的连接请求。这通常是另一个NFS服务器,正常的NFS UDP服务器在UDP端口2049等待着进入的UDP数据报。
  2. 当客户使用TCP安装服务器上的文件系统时,它对服务器上的TCP端口2049做一个主动打开。这样就为这个文件系统在客户和服务器之间形成了一个TCP连接。如果同样的客户安装同样服务器上的另一个文件系统,就会创建另一个TCP连接。
  3. 客户和服务器在它们连接的两端都要设置TCP的keepalive选项,这样双方都能检测到对方主机崩溃,或者崩溃然后重启动。
  4. 客户方所有使用这个服务器文件系统的应用程序共享这个TCP连接。例如,在图29-6中,如果在bsdi的/usr目录下还有另一个目录smith,那么对两个目录/nfs/bsdi/usr/rstevens和/nfs/bsdi/usr/smith下所有文件的引用将共享同样的TCP连接。
  5. 如果客户检测到服务器已经崩溃,或者崩溃然后重启动(通过收到一个TCP差错“连接超时”或者“对方复位连接”),它尝试与服务器重新建立连接。客户做另一个主动打开,为同一个文件系统请求重新建立TCP连接。在以前连接上超时的所有客户请求在新的连接上都会重新发出。
  6. 如果客户机崩溃,那么当它崩溃时正在运行的应用程序也要崩溃。当客户机重新启动时,它很可能使用TCP重新安装服务器的文件系统,这将导致和服务器的另一个连接。客户和服务器之间针对同一个文件系统的前一个连接现在打开了一半(服务器方认为它还开着),但是既然服务器设置了keepalive选项,当服务器发出下一个keepalive探查报文时,这个半开着的TCP连接就会被中止。

 29.6 NFS实例

29.6.1 简单的例子:读一个文件

29.6.2 简单的例子:创建一个目录

29.6.3 无状态

NFS的一个特征(NFS的批评者称之为NFS的一个瑕疵,而不是一个特征)是NFS服务器是无状态的(stateless)。服务器并不记录哪个客户正在访问哪个文件。请注意一下在前面给出的NFS过程中,没有一个open操作和一个close操作。LOOKUP过程的功能与open操作有些类似,但是服务器永远也不会知道客户对一个文件调用了LOOKUP过程之后是否会引用该文件。

无状态设计的理由是为了在服务器崩溃并且重启动时,简化服务器的崩溃恢复操作。

29.6.4 例子:服务器崩溃

客户要重传多久呢?客户有两个与此有关的选项。首先,如果服务器文件系统是“硬”安装的,客户就会永远重传下去。但是如果服务器文件系统是“软”安装的,客户重传了固定数目的次数之后就会放弃。在“硬”安装的情况下,客户还有一个选项决定是否允许用户中断无限制的重传。如果客户主机安装服务器文件系统时说明了中断能力,并且如果我们不想在服务器崩溃之后等5分钟,等着服务器重启动,就可以键入一个中断键以终止客户应用程序。

29.6.5 等幂过程

如果一个RPC过程被服务器执行多次仍然返回同样的结果,那么就把它叫作等幂过程(Idempotent Procedure)

29.7 第3版的NFS

第2版NFS协议规范和第3版的主要区别:

  1. V2中的文件句柄是32字节的固定大小的数组。在V3中,它变成了一个最多为64个字节的可变长度的数组。在XDR中,一个可变长度的数组被编码为一个4字节的数组成员个数跟着实际的数组成员字节。这样在实现时减少了文件句柄的长度,例如Unix只需要12个字节,但又允许非Unix实现维护另外的信息。
  2. V2将每个READ和WRITE RPC过程可以读写的数据限制为8192个字节。这个限制在V3中取消了,这就意味着一个UDP上的实现只受到IP数据报大小的限制(65535字节)。这样允许在更快的网络上读写更大的分组。
  3. 文件大小以及READ和WRITE过程开始偏移的字节从32字节扩充到64字节,允许读写更大的文件。
  4. 每个影响文件属性值的调用都返回文件的属性。这样减少了客户调用GETAT TR过程的次数。
  5. WRITE过程可以是异步的,而在V2中要求同步的WRITE过程。这样可以提高WRITE过程的性能。
  6. V3中删去了一个过程(STAT FS),增加了七个过程:ACCESS(检查文件访问权限)、MKNOD(创建一个Unix特殊文件)、READDIRPLUS(返回一个目录中的文件名字和它们的属性)、FSINFO(返回一个文件系统的静态信息)、FSSTAT(返回一个文件系统的动态信息)、PAT HCONF(返回一个文件的POSIX.1信息)和COMMIT(将以前的异步写操作提交到外存中)。

第30章 其他的TCP/IP应用程序

30.1 引言

30.2 Finger协议

Finger协议返回一个指定主机上一个或多个用户的信息。它常被用来检查某个人是否登录了,或者搞清一个人的登录名以便给他发送邮件。

30.3 Whois协议

Whois协议是另一种信息服务。

白页

使用SMTP的VRFY命令、Finger协议以及Whois协议在Internet上查找用户类似于使用电话号码簿的白页查找一个人的电话号码。

30.4 Archie、WAIS、Gopher、Veronica和WWW

30.4.1 Archie

Archie提供了Internet上几千个FTP服务器的目录。我们可以通过登录进一个Archie服务器,搜索那些名字中包含了一个指定的常规表达式的文件。输出是一个与文件名匹配的FTP服务器的列表。然后我们可以使用匿名FTP去那个站点取得想要的文件。

30.4.2 WAIS

WAIS(Wide Area Information Servers广域信息服务系统)知道几百个包含了有关计算机主题的和其他一般性主题信息的数据库。为了使用WAIS,我们要选择需要查找的数据库,指明关键字。

30.4.3 Gopher

Gopher是其他Internet资源服务如Archie、WAIS和匿名FTP的一个菜单驱动的前端程序。Gopher是最容易使用的工具之一,因为不管它使用了哪个资源服务,它的用户界面都是一样的。

30.4.4 Veronica

Veronica(Very Easy Rodent-Oriented Netwide Index to Computerized Archives)是一个Gopher标题的索引。一次Veronica搜索一般要查找几百个Gopher服务器。

30.4.5 万维网WWW

万维网使用一个称为超文本的工具,使得我们可以浏览一个大的/全球范围的服务和文档。信息和关键字一起显示,不过关键字被突出显示。我们可以通过选择关键字得到更多的信息。

30.5 X窗口系统

X窗口系统(XWindow System),或简称为X,是一种客户-服务器应用程序。它可以使得多个客户(应用)使用由一个服务器管理的位映射显示器。服务器是一个软件,用来管理显示器、键盘和鼠标。客户是一个应用程序,它与服务器在同一台主机上或者在不同的主机上。在后一种情况下,客户与服务器之间通信的通用形式是TCP,尽管也可以使用诸如DECNET的其他协议。在有些场合,服务器是与其他主机上客户通信的一个专门的硬件(一个X终端)。在另一种场合,一个独立的工作站,客户与服务器位于同一台主机,使用那台主机上的进程间通信机制进行通信,而根本不涉及任何网络操作。在这两种极端情况之间,是一台既支持同一台主机上的客户又支持不同主机上的客户的工作站。

X需要一个诸如TCP的、可靠的、双向的流协议(X不是为不可靠协议,如UDP,而设计的)。客户与服务器的通信是由在连接上交换的8bit字节组成的。

30.5.1 Xscope程序

Xscope是检查X客户与它的服务器之间交换的信息的一个方便的程序。大多数的X窗口实现都提供这个程序。它处在客户与服务器之间,双向传输所有的数据,同时解析所有的客户请求和服务器应答。

30.5.2 LBX:低带宽X

定义一个称为低带宽X(LBX)的标准的工作正在进行当中,它使用了下面的技术来减少网络流量的数目:快速缓存、只发送与前面分组的不同部分以及压缩技术。


附录A tcpdump程序

tcpdump通过将网络接口卡设置为混杂模式(promiscuous mode)来截获经过网络接口的每一个分组。正常情况下,用于诸如以太网媒体的接口卡只截获送往特定接口地址或广播地址的链路层的帧(2.2节)。

A.1 BSD分组过滤器

当前由BSD演变而来的Unix内核提供了BSD分组过滤器BPF(BSD Packet Filter),tcpdump用它来截获和过滤来自一个被置为混杂模式的网络接口卡的分组。BPF也可以工作在点对点的链路上,如SLIP(2.4节),不需要什么特别的处理就可以截获所有通过接口的分组。BPF还可以工作在环回接口上(2.7节)。

BPF将以太网设备驱动程序设置为混杂模式,然后从驱动程序那里接收每一个收到的分组和传输的分组。这些分组要通过一个用户指明的过滤器,使得只有那些用户进程感兴趣的分组才会传递给用户进程。

A.2 SunOS的网络接口分接头

SunOS 4.1.x提供了一个STREAMS伪设备驱动程序(pseudo-device driver),称为网络接口分接头(Network Interface Ta p)或者NIT([Rago 1993]包含了流设备驱动程序的其他细节。

一个不同点在于BPF可以截获网络接口收到的和传送的分组,而NIT只能截获接口收到的分组。

A.3 SVR4数据链路提供者接口

SVR4支持数据链路提供者接口DLPI(Data Link Provider Interface),它是OSI数据链路服务定义的一个流实现。

A.4 tcpdump的输出

A.5 安全性考虑

A.6 插口排错选项

查看一个TCP连接上发生的事情的另一种方法是使能插口排错选项,当然是在支持这一特征的系统中。这个特征只能工作在TCP上(其他协议都不行),并且需要应用程序支持(当应用程序启动时,使能一个插口排错选项)。


附录B 计算机时钟

硬件按照一定的频率产生一个时钟中断。

为了得到更好的时间测量需要:(1)一个更好的振荡器;(2)一个外部的更精确的时间资源(如,全球定位卫星提供的时间资源);或者(3)通过因特网访问一个具有更精确时钟的系统。

Unix系统中引起时间差错的另一个公共的原因是10 ms的中断只是引起内核给一个记录时间的变量增1。如果内核丢失了一个中断(也就是说两个连续中断之间间隔10 ms对于内核来说太快了),时钟将失去10 ms。丢失这种类型的中断经常引起Unix系统丢失时间。


附录C sock程序

sock程序运行在以下四种模式之一:

1)交互式客户:默认模式。程序和一个服务器相连,然后将标准输入的数据传给服务器,再将从服务器那里接收到的数图C-1sock程序作为交互式客户的默认操作据复制到标准输出。

附录C sock程序_即时通讯网(52im.net)

2)交互式服务器:指明-s选项。需要指明服务名字(或端口号):

sun % sock -s 5555        作为一个在端口 5555 监听的服务器

3)源客户:指明-i选项。在默认情况下,将一个1024字节的缓存写到网络中,写1024

次。-n选项和-w选项可以改变默认值。例如,

sun % sock -i -n12 -w4096 bsdi discard

把12个缓存,每个包含4096字节的数据,送给主机bsdi上的discard服务器。

4)接收器服务器:指明-i选项和-s选项。从网络中读数据然后扔掉。这些例子都使用了TCP(默认情况),-u选项指明使用UDP。

附录C sock程序_即时通讯网(52im.net)

附录C sock程序_即时通讯网(52im.net)


附录E 配置选项

E.1 BSD/386版本1.0

IPFORWARDING

这个常量的值初始化内核变量ipforwarding。如果值为0(默认),就不转发IP数据报。如果是1,就总是使能转发功能。

GATEWAY

如果定义了这个常量,就使得IPFORWA RDING的值被置为1。另外,定义这个常量还使得特定的系统表格(ARP快速缓存表和路由表)更大。

SUBNETSARELOCAL

这个常量的值初始化内核变量subnetsarelocal。如果值为1(默认),一个和发送主机具有同样网络号、但不同子网号的目的IP地址被认为是本地的。如果是0,只有在同一个子网的目的IP地址才认为是本地的。图E-1总结了上述规律。

IPSENDREDIRECTS

这个常量的值初始化内核变量ipsendredirects。如果值为1(默认),主机在转发IP数据报时,将发送ICMP重定向。如果是0,不发送ICMP重定向。

DIRECTED_BROADCAST

如果值为1(默认),如果收到的数据报的目的地址是主机的一个接口的直接广播地址,就将它作为一个链路层的广播来转发。如果是0,这些数据报就会被丢弃。

E.2 SunOS 4.1.3

IPFORWARDING

SUBNETSARELOCAL

IPSENDREDIRECTS

DIRECTED_BROADCAST

E.3 SRV4

IPFORWARDING

IPSENDREDIRECTS

E.4 Solaris 2.2

E.5 AIX 3.2.2

E.6 4.4BSD


缩略语

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chinalihuanyu/article/details/116532139

智能推荐

html中无序列表的默认样式及其修改:_html中怎么把无序列表的点改成数字-程序员宅基地

文章浏览阅读1.8w次,点赞7次,收藏16次。html中无序列表的默认样式及其修改:在我们进行常规的网页设计的时候经常要用到无序列表;然而在css3中;无序列表是有默认样式的,这些默认样式对我们来说有时候是不合适的。 <ul> <li>列</li> <li>表</li> </ul>从上图可以明显的看出,列表前面有一个很可能没必要存..._html中怎么把无序列表的点改成数字

Elastic:在腾讯云上部署 Elasticsearch 集群_elasticsearch云上部署-程序员宅基地

文章浏览阅读1.1k次。腾讯云(https://cloud.tencent.com/product/es)是基于开源搜索引擎 Elasticsearch 打造的高可用、可伸缩的云端全托管的 Elasticsearch 服务,包含 Kibana 及常用插件,并集成了安全、SQL、机器学习、告警、监控等高级特性(X-Pack)。使用腾讯云 ES,您可以快速部署、轻松管理、按需扩展您的集群,简化复杂运维操作,快速构建日志分析、异常监控、网站搜索、企业搜索、BI 分析等各类业务。在今天的文章中,我将展示如何使用腾讯云来部署 Elast_elasticsearch云上部署

虚拟机内存交换学习个人摘录总结_同一个虚拟机在不同电脑上内存使用 压缩 不一样-程序员宅基地

文章浏览阅读4.4k次。最近在玩虚拟机,看到了VM15选项中设置内存不能过大,否者会发生内存交换。我对此感到疑惑,先开始一番猜测,莫非是主机的内存与虚拟机的内存之间的交换。这个问题可就大了。利用子机攻击母机的套路还是存在的,前几天刚刚看到一篇文章。这让我更加有了兴趣。我想了一下,这种东西应该有前辈发表过吧,我在百度上一搜,发现不止虚拟机会发生内存交换,很多情况也会。但没有一篇搜索结果用的,抨击一波百度,明天Google一..._同一个虚拟机在不同电脑上内存使用 压缩 不一样

[Python爬虫] 5-爬虫进阶(多线程爬虫/动态网页抓取/图形验证码识别)_python实现多线程验证码识别-程序员宅基地

文章浏览阅读728次。# I.多线程爬虫# 1)概念:多线程是为了同步完成多项任务,通过提高资源使用效率来提高系统的效率# 线程:火车的车厢,进程:火车头## 2)threading模块:专门提供用来做多线程编程的模块# tips:可在打印时设置这两个打印内容: # threading.enumerate():查看当前线程的数量 # threading.current_thread():..._python实现多线程验证码识别

Android MediaCodec 硬编码器封装_mediacodec.createencoderbytype("video/avc");-程序员宅基地

文章浏览阅读5.2k次。Android硬编码对手机平台有要求,不同平台支持的视频质量以及是否支持硬编码都不相同。 需要关注inputBufferIndex值 以及outputBufferIndex 是否正常_mediacodec.createencoderbytype("video/avc");

【蒟蒻的Java代码记录系列】时间相关的小工具类_java 记录请求时间工具类-程序员宅基地

文章浏览阅读130次。【代码】【蒟蒻的Java代码记录系列】时间相关的小工具类。_java 记录请求时间工具类

随便推点

Vue3.2 运行时类型检测和运用ts特性的编译时类型检测_vue3 ts 怎么判断字段的类型-程序员宅基地

文章浏览阅读2.9k次。在Vue3内,我们可以在script标签里的export default里添加defineProps这样可以进行一种运行时的声明。运行时声明的写法:<template > <h1>我是DefineProps-Runtime</h1> <h3>你好{{ name }} 现在是{{ time }} 年</h3></template><script setup>defineProps({ ._vue3 ts 怎么判断字段的类型

源码技术分享 计算机毕业设计逆天版Python+Spark智慧城市交通大数据 交通流量预测 交通爬虫 地铁客流量分析 大数据毕业设计 大数据毕设 深度学习 机器学习_大数据技术在智慧交通中的应用爬虫-程序员宅基地

文章浏览阅读1.1k次,点赞4次,收藏26次。大数据毕业设计吊炸天Python+Spark智慧城市交通大数据分析计算机毕业设计吊炸天Python+Spark智慧城市交通大数据分析 大数据毕业设计吊炸天Hadoop+Spark智慧城市交通大数据分析 计算机毕业设计吊炸天Flink+Spark智慧城市交通大数据分析 计算机毕业设计吊炸天Hadoop+Spark智慧城市交通大数据分析_大数据技术在智慧交通中的应用爬虫

多测师肖sir__金牌高级讲师软件测试___疑难杂症之jmeter安装插件后启动闪退_jmeter提示安装库,插件,为什么自动退出了-程序员宅基地

文章浏览阅读202次。报错现象:杭州6期-刘靖(2353502787) 15:07:06An error occurred: org.apache.log.Loggererrorlevel=1请按任意键继续. .杭州6期-刘靖(2353502787) 15:07:16Don’t use GUI mode for load testing, only for Test creation and Test debugging !For load testing, use NON GUI Mode:jmeter _jmeter提示安装库,插件,为什么自动退出了

用二维码搭建设备巡检系统,轻松实现扫码巡检和数字化台账_变电站设备二维码身份csdn-程序员宅基地

文章浏览阅读314次。针对设备状态不透明、纸质记录效率低、故障报修不及时等设备点巡检的常见问题,可以在草料二维码上自主搭建涵盖点检、巡检、报修、维修、保养等功能的管理系统,无需安装APP,微信扫码就能查看设备档案、用表单替代纸质检查表。不管是设备参数、技术资料、联系人等静态信息,还是填写表单、更新状态、编辑可变内容等操作记录,都可以在二维码上展示,作为设备的电子档案。适用于生产设备的点检场景,将二维码作为设备的“数字身份证”,扫码查看设备参数、技术资料、相关责任人,添加点检、维修、保养等记录。_变电站设备二维码身份csdn

前端瓦片地图加载之塞尔达传说旷野之息_js 瓦片地图-程序员宅基地

文章浏览阅读673次,点赞4次,收藏8次。背景最近在 肝???? 塞尔达旷野之息,希望 2022年 新作发布前可以救出公主 ????。 同时公司有地图加载的需求,于是想以 旷野之息 地图为例,学习实践一下前端开发相关的地图知识,本文内容主要介绍通过使用瓦片地图加载原理,实现 塞尔达旷野之息 地图加载并添加交互锚点。基础知识瓦片地图 ????在游戏开发过程中,经常会遇到超过屏幕大小的地图,例如在即时战略游戏中,它使得玩家可以在地图中滚动游戏画面。这类游戏通常会有丰富的背景元素,如果直接使用背景图切换的方式,需要为每个不同的场景准备一张背景图,_js 瓦片地图

Redis搭建及使用-程序员宅基地

文章浏览阅读1.4k次,点赞2次,收藏7次。Redis是C语言开发基于内存结构进行键值对数据存储的、高性能的、非关系型Nosql数据库。用于缓存首页数据1. 缓存作为Key-Value形态的内存数据库,Redis 最先会被想到的应用场景便是作为数据缓存。而使用 Redis 缓存数据非常简单,只需要通过string类型将序列化后的对象存起来即可,不过也有一些需要注意的地方:必须保证不同对象的 key 不会重复,并且使 key 尽量短,一般使用类名(表名)加主键拼接而成。选择一个优秀的序列化方式也很重要,目的是提高序列化的效率和减少内存占用。_redis搭建