IP路由选择
在一般的体制中,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首部协议字段所指定的协议模块进行处理。如果数据报的目的不是这些地址,那么( 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 P地址看成由单纯的一个网络号和一个主机号组成,而是把主机号再分成一个子网号和一个主机号。
这样做的原因是因为A类和B类地址为主机号分配了太多的空间,可分别容纳的主机数为
22 4-2和21 6-2。事实上,在一个网络中人们并不安排这么多的主机(各类I P地址的格式如图1 - 5
所示)。由于全0或全1的主机号都是无效的,因此我们把总数减去2。
这个掩码是一个32 bit的值,其中值为1的比特留给网络号和子网号,为0的比特留给主机号
给定I P地址和子网掩码以后,主机就可以确定I P数据报的目的是:( 1)本子网上的主机;
(2)本网络中其他子网中的主机;( 3)其他网络上的主机。如果知道本机的I P地址,那么就知道
它是否为A类、B类或C类地址(从I P地址的高位可以得知),也就知道网络号和子网号之间的分
界线。而根据子网掩码就可知道子网号与主机号之间的分界线。
Ping程序
目的是为了测试另一台主机是否可达。该程序发送一份I C M P回显请求报文给主机,并等待返回I C M P回显应答
我们称发送回显请求的p i n g程序为客户,而称被p i n g的主机为服务器。
-----------------------------------------------------------------------------------------------------
ICMP:Internet控制报文协议
它传递差错报文以及其他需要注意的信息。
I C M P报文通常被I P层或更高层协议( T C P或U D P)使用。一些I C M P报文把差错报文返回给
用户进程。
I C M P报文是在I P数据报内部被传输的
下面各种情况都不会导致产生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差错报文对广播分组响应所带来的广播风暴。
现在来分析一种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不可达报文。
我们所有的例子都假定对路由表的搜索能找到匹配的表项,即使匹配的是默认项。如果
路由表中没有默认项,而又没有找到匹配项,这时会发生什么情况呢?
结果取决于该I P数据报是由主机产生的还是被转发的(例如,我们就充当一个路由器)。
如果数据报是由本地主机产生的,那么就给发送该数据报的应用程序返回一个差错,或者是
“主机不可达差错”或者是“网络不可达差错”。如果是被转发的数据报,那么就给原始发送
端发送一份I C M P主机不可达的差错报文
当I P数据报应该被发送到另一个路由器时,收到数据报的路由器就要发送I C M P重定向差
错报文给I P数据报的发送端
重定向一般用来让具有很少选路信息的主机逐渐建立更完善的路由表。主机启动时路由
表中可以只有一个默认表项(在图9 - 3所示的例子中,为R 1或R 2)。一旦默认路由发生差错,
默认路由器将通知它进行重定向,并允许主机对路由表作相应的改动。
ICMP路由器发现报文
在本章前面已提到过一种初始化路由表的方法,即在配置文件中指定静态路由。这种方
法经常用来设置默认路由。另一种新的方法是利用I C M P路由器通告和请求报文。
一般认为,主机在引导以后要广播或多播传送一份路由器请求报文。一台或更多台路由
器响应一份路由器通告报文。另外,路由器定期地广播或多播传送它们的路由器通告报文,
允许每个正在监听的主机相应地更新它们的路由表。
当路由器启动时,它定期在所有广播或多播传送接口上发送通告报文。准确地说,这些
通告报文不是定期发送的,而是随机传送的,以减小与子网上其他路由器发生冲突的概率。
一般每两次通告间隔4 5 0秒和6 0 0秒。一份给定的通告报文默认生命周期是3 0分钟。
动态选路
在前面各章中,我们讨论了静态选路。在配置接口时,以默认方式生成路由表项(对于
直接连接的接口),并通过r o u t e命令增加表项(通常从系统自引导程序文件),或是通过I C M P
重定向生成表项(通常是在默认方式出错的情况下)。
在网络很小,且与其他网络只有单个连接点且没有多余路由时(若主路由失败,可以使
用备用路由),采用这种方法是可行的。如果上述三种情况不能全部满足,通常使用动态选
路。
本章讨论动态选路协议,它用于路由器间的通信。我们主要讨论R I P,即选路信息协议
(Routing Infromation Protocol),大多数T C P / I P实现都提供这个应用广泛的协议。
当相邻路由器之间进行通信,以告知对方每个路由器当前所连接的网络,这时就出现了
动态选路。路由器之间必须采用选路协议进行通信,这样的选路协议有很多种。路由器上有
一个进程称为路由守护程序( routing daemon)U n i x系统上常常运行名为r o u t e d路由守护程序另一个程序是g a t e d。I G P和E G P都支持它,它运行选路协议,并与其相邻的一些路由器
进行通信
RIP:选路信息协议
让我们来看一下采用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秒,所有或部分路由器会将其完整路由表发送给相邻路由器。发
送路由表可以是广播形式的(如在以太网上),或是发送给点对点链路的其他终点的。
每条路由都有与之相关的定时器。如果运行R I P的系统发现一条路由在3分钟内未更新,
就将该路由的度量设置成无穷大( 1 6),并标注为删除。这意味着已经在6个3 0秒更新时间里
没收到通告该路由的路由器的更新了。再过6 0秒,将从本地路由表中删除该路由,以保证该
路由的失效已被传播开
这种方法看起来很简单,但它有一些缺陷。首先, R I P没有子网地址的概念。例如,如果
标准的B类地址中16 bit的主机号不为0,那么R I P无法区分非零部分是一个子网号,或者是一个
主机地址。有一些实现中通过接收到的R I P信息,来使用接口的网络掩码,而这有可能出错。
其次,在路由器或链路发生故障后,需要很长的一段时间才能稳定下来。这段时间通常
需要几分钟。在这段建立时间里,可能会发生路由环路。在实现R I P时,必须采用很多微妙的
措施来防止路由环路的出现,并使其尽快建立。RFC 1058 [Hedrick 1988a]中指出了很多实现
R I P的细节。
OSPF:开放最短路径优先
与采用距离向量的R I P协议不同的是, O S P F是一个链路状态协议。距离向量的意思是,
R I P发送的报文包含一个距离向量(跳数)。每个路由器都根据它所接收到邻站的这些距离向
量来更新自己的路由表。在一个链路状态协议中,路由器并不与其邻站交换距离信息。它采用的是每个路由器主
动地测试与其邻站相连链路的状态,将这些信息发送给它的其他邻站,而邻站将这些信息在
自治系统中传播出去。每个路由器接收这些链路状态信息,并建立起完整的路由表。
B G P是一种不同自治系统的路由器之间进行通信的外部网关协议
-----------------------------------------------------------------------------------------------------
UDP:用户数据报协议
U D P是一个简单的面向数据报的运输层协议:进程的每个输出操作都正好产生一个U D P
数据报,并组装成一份待发送的I P数据报。这与面向流字符的协议不同,如T C P,应用
程序产生的全体数据与真正发送的单个I P数据报可能没有什么联系。
因此T C P端口号由T C P来查看,而U D P端口号由U D P来查看。T C P端口号与U D P端口
号是相互独立的。
U D P检验和是一个端到端的检验和。它由发送端计算,然后由接收端验证。其目的是为
了发现U D P首部和数据在发送端到接收端之间发生的任何改动。
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数据报被分片后,每一片都成为一个分组,具有自己的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数据报。没有办法只重传数据报中的一个数据报片。事实上,如果对数据报分片的
是中间路由器,而不是起始端系统,那么起始端系统就无法知道数据报是如何被分片的。就这
个原因,经常要避免分片
另外需要解释几个术语: I P数据报是指I P层端到端的传输单元(在分片之前和重新组装
之后),分组是指在I P层和链路层之间传送的数据单元。一个分组可以是一个完整的I P数据报,
也可以是I P数据报的一个分片
------------------------------------------------------------------------------------------------------------------
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段都包含源端和目的端的端口号,用于寻找发端和收端应用进程。这两个值加
上I P首部中的源端I P地址和目的端I P地址唯一确定一个T C P连接。
序号用来标识从T C P发端向T C P收端发送的数据字节流,它表示在这个报文段中的的第一
个数据字节。如果将字节流看作在两个应用程序间的单向流动,则T C P用序号对每个字节进
行计数
既然每个传输的字节都被计数,确认序号包含发送确认的一端所期望收到的下一个序号。
因此,确认序号应当是上次已成功收到数据字节序号加1。只有A C K标志(下面介绍)为1时
确认序号字段才有效
当建立一个新的连接时, 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时
确认序号字段才有效。
建立连接-为什么要三次握手?
第一次握手:黄河发起呼叫,长江收到了。这时长江可以确认的是,黄河的发信机和自己的收信机是好的,否则的话他收不到黄河的呼叫;黄河能确认什么呢?他什么也不能确认,有可能自己的电台除了指示灯是好的,其它都是坏的,他在对着一台铁疙瘩发功。
第二次握手:长江回应,黄河收到了。这时黄河可以确认的是,自己和长江的收发信机都是好的,否则的话他收不到长江的回应信号。这时黄河可以说正事了吗?还不能,虽然长江发出了回应,但他并不能确认自己的发信机和黄河的收信机都是好的。
第三次握手:黄河对长江的回应进行回应。这时黄河很清楚,双方收发信机都是好的,自己的这次回应长江肯定能收到,这个回应的目的只是消除长江对黄河的收信机和长江自己的发信机的担心。然后,黄河不必等长江的再次回应就可以说正事了。
有些读者看到这里,心里会想“且慢,你凭什么说第三次握手后,长江肯定会收到?长江刚才的状态好,不代表后来的状态好,俗话说人算不如天算,我看再多握几次手会更可靠些。”这种想法有道理,几句话还真说不清,那么不妨先讲一个与此有关的战斗小故事。
战场态势是这样的:
驻扎在两个山头上的红1团和红2团分别有两个营,而在山谷的蓝团有三个营,若红1团和红2团孤军下山作战会失败,而两个团同时进攻就会胜利,对于红方来说,问题的关键是要同时发起进攻。
战斗前的准备过程是这样的:
红1团团长找了个传令兵,命令他跑到红2团,告诉红2团团长明早9时发起进攻。传令兵没有被蓝团俘虏,成功地跑到了红2团的山头,告诉红2团团长明早9时两个团同时进攻。红2团团长一边握着传令兵的手激动地说“太好了!我早就等着这个消息呢!”,一边心里暗自核计“虽然我知道了这个消息,但是红1团的团长并不知道我已经知道了,谁都知道传令兵有可能被俘,消息很有可能传不过来,若明天总攻前,红1团团长不知道我已经得到了消息,他一定不会贸然进攻的,换成我也不会”。于是,红2团团长对传令兵说“兄弟,你辛苦了,先抽袋烟吧,抽完后再辛苦你跑回去,告诉你们团长,说我已经得到消息了,明天按时总攻。”
传令兵又跑回到红1团,侥幸又没被蓝团俘获,他告诉红1团团长有关红2团团长已经获知明早进攻的消息,但红1团团长明早敢发起攻击吗?他不敢,因为他心里清楚,红2团团长并不知道他(红1团团长)已经知道了“红2团团长已获知明早9时发起攻击”这个消息,红1团团长继续想,如果是他本人是红2团团长,就不会贸然攻击,因为自己已经获知明早9时发起攻击这件事,对方未必知道,而有可能因为传令兵回团时被抓,敌人反而知道了,自己贸然攻击,有可能就会失败。于是,红1团团长对传令兵说“兄弟,你辛苦了,先抽袋烟吧,抽完后再辛苦你跑一趟红2团,告诉他们团长,就说我已经知道他已经知道了明早9点进攻这件事,让他放心地打吧。”
写到这里,聪明的读者已经猜到了,即使传令兵再次来到红2团,红2团团长也不敢开战,还是要传令兵再次回红1团报信,因为红2团团长担心红1团团长不知道他(红2团团长)已经知道了红1团团长知道他(红2团团长)知道明早9点发生攻击的事。(此句53个字,想到松鼠们多用短句的建议,心里严重疚结中……)
回到三次握手问题上,红1团和红2团其实就是通信的双方,这场永远也达不成协议的战斗,说明了一个重要的通信道理:世界上不存在完全可靠的通信协议。
“三次握手”是电台点对点通信的一般规则,但即使三次握手成功后,以后的通信就能保证正常吗?当然不能,握手成功后的设备故障、干扰、话务员的伤亡等,无数种可能性会导致通信失败。三次握手成功只说明了之前的通信条件和环境,而不能决定和预测之后的通信条件和环境。根据经验,两个电台之间的通信失败,最大的可能性是两个电台本身的故障,三次握手的成功排除了这种可能。以后的情况很难预测的,通信协议只能做到尽可能的可靠,而不能做到理论上的完全可靠。
电台通信一定要三次握手吗?当然不一定。潜伏者为了不暴露自己,可以只使用收信机而不发信,回应总部时可以采用其它手段,例如在指定电线杆上贴个寻人启示。如果电台的发信机出了故障,也可能不经过三次握手而达成通信,在对越自卫反击战中,某部的电台发信机坏了,指挥所在没有收到对方握手信号的情况下,连续盲发14份报文,该部全部收到,并按指示顺利地完成了任务,该电台台长因此荣立了二等功。
如果是两次:
C发送请求,S应答并分配资源 若S的应答没有到达C端,C认为连接未建立,而S认为建立了 S会在一段时间内保留分配的资源
如果大量C这样请求,S会崩溃
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)。
连接终止
建立一个连接需要三次握手,而终止一个连接要经过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)将执行主动关闭,而另一方(收到这个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软件自动产生的。
最大报文段长度( 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首部。
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进行确认后,这个
连接便彻底关闭了。
tcp状态变迁图
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字段。
1)对I P数据报T T L的限制是基于跳数,而不是定时器。对一个具体实现所给定的M S L值,处理的原则是:当T C P执行一个主动关闭,并发回最送最后的A C K以防这个A C K丢失(另一端超时并重发最后的F I N)。
2)这种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分钟
如果一方已经关闭或异常终止连接而另一方却还不知道,我们将这样的T C P连接称为半
打开(H a l f - O p e n)的。任何一端的主机异常都可能导致发生这种情况。只要不打算在半打开
连接上传输数据,仍处于连接状态的一方就不会检测另一方已经出现异常。
两个应用程序同时彼此执行主动打开的情况是可能的,尽管发生的可能性极小。每一方
必须发送一个S Y N,且这些S Y N必须传递给对方。这需要每一方使用一个对方熟知的端口作
为本地端口。这又称为同时打开( simultaneous open)。
一个同时打开的连接需要交换4个报文段,比正常的三次握手多一个。此外,要注意的是
我们没有将任何一端称为客户或服务器,因为每一端既是客户又是服务器。
我们在以前讨论过一方(通常但不总是客户方)发送第一个F I N执行主动关闭。双方都执
行主动关闭也是可能的, T C P协议也允许这样的同时关闭( simultaneous close)。
滑动窗口,拥塞窗口,流量控制
在这个图中,我们将字节从1至11进行标号。接收方通告的窗口称为提出的窗口( o ff e r e d
w i n d o w),它覆盖了从第4字节到第9字节的区域,表明接收方已经确认了包括第3字节在内的
数据,且通告窗口大小为6。回顾第1 7章,我们知道窗口大小是与确认序号相对应的。发送方
计算它的可用窗口,该窗口表明多少数据可以立即被发送。
当接收方确认数据后,这个滑动窗口不时地向右移动。窗口两个边沿的相对运动增加或
减少了窗口的大小。我们使用三个术语来描述窗口左右边沿的运动:
1) 称窗口左边沿向右边沿靠近为窗口合拢。这种现象发生在数据被发送和确认时。
2) 当窗口右边沿向右移动时将允许发送更多的数据,我们称之为窗口张开。这种现象发
生在另一端的接收进程读取已经确认的数据并释放了T C P的接收缓存时。
3) 当右边沿向左移动时,我们称之为窗口收缩。
1) 发送方不必发送一个全窗口大小的数据。
2) 来自接收方的一个报文段确认数据并把窗口向右边滑动。这是因为窗口的大小是相对
于确认序号的。
3) 正如从报文段7到报文段8中变化的那样,窗口的大小可以减小,但是窗口的右边沿却
不能够向左移动。
4) 接收方在发送一个A C K前不必等待窗口被填满。在前面我们看到许多实现每收到两个
报文段就会发送一个A C K。
慢启动
迄今为止,在本章所有的例子中,发送方一开始便向网络发送多个报文段,直至达到接
收方通告的窗口大小为止。当发送方和接收方处于同一个局域网时,这种方式是可以的。但
是如果在发送方和接收方之间存在多个路由器和速率较慢的链路时,就有可能出现一些问题。
一些中间路由器必须缓存分组,并有可能耗尽存储器的空间。[Jacobson 1988]证明了这种连
接方式是如何严重降低了T C P连接的吞吐量的。
现在,T C P需要支持一种被称为“慢启动(slow start)”的算法。该算法通过观察到新分组
进入网络的速率应该与另一端返回确认的速率相同而进行工作。
慢启动为发送方的T C P增加了另一个窗口:拥塞窗口(congestion window),记为c w n d。当
与另一个网络的主机建立T C P连接时,拥塞窗口被初始化为1个报文段(即另一端通告的报文
段大小)。每收到一个A C K,拥塞窗口就增加一个报文段( c w n d以字节为单位,但是慢启动
以报文段大小为单位进行增加)。发送方取拥塞窗口与通告窗口中的最小值作为发送上限。拥
塞窗口是发送方使用的流量控制,而通告窗口则是接收方使用的流量控制。
发送方开始时发送一个报文段,然后等待A C K。当收到该A C K时,拥塞窗口从1增加为2,
即可以发送两个报文段。当收到这两个报文段的A C K时,拥塞窗口就增加为4。这是一种指数
增加的关系。
在某些点上可能达到了互联网的容量,于是中间路由器开始丢弃分组。这就通知发送方
它的拥塞窗口开得过大。
TCP的超时与重传
T C P提供可靠的运输层。它使用的方法之一就是确认从另一端收到的数据。但数据和确
认都有可能会丢失。T C P通过在发送时设置一个定时器来解决这种问题。如果当定时器溢出
时还没有收到确认,它就重传该数据。对任何实现而言,关键之处就在于超时和重传的策略,
即怎样决定超时间隔和如何确定重传的频率。