运输层 | 花野猫的数字花园
Dors Dors 是花野猫开发为知识工作者打造的数字花园应用,包含的博客、个人记事本、及其他实用功能。
运输层协议概述
进程之间的通信
运输层为相互通信的应用进程提供逻辑通信。运输层向其上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时都只用到下三层的功能。
通信的真正端点并不是主机而是主机中的进程。 → 为什么需要运输层——端到端的通信是应用进程之间的通信 :IP 协议虽然能把分组送到目的主机,但是这个分组还停留在主机的网络层而没有交付到应用进程。真正进行通信的实体是在主机中的应用进程。网络层为主机之间提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信。
在一台主机中经常有多个应用进程同时分别和另一台主机中的多个应用进程通信。例如,主机的应用层运行浏览器客户进程的同时,还可运行电子邮件的客户进程。这说明运输层有着复用和分用的功能
复用(multiplexing):在发送方不同的应用进程都可以使用同一个运输层协议传送数据(当然需要加上适当的首部)
分用(demultiplexing):接收方的运输层在剥去报文的首部后能够把这些数据正确交付目的应用进程 。
“运输层提供应用进程间的逻辑通信”:从应用层来看,只要把应用层报文交给下面的运输层, 运输层就可以把这报文传送到对方的运输层,运输层向高层用户屏蔽了下面网络核心的细节(如网络拓扑、所采用的路由选择协议等),但事实上这两个运输层之间并没有一条水平方向的物理连接。数据是经过多个层次传送的。
运输层还要对收到的报文进行差错检测。在网络层,IP 数据报首部中的检验和字段,只检验首部是否出现差错而不检查数据部分。
运输层的两个主要协议
根据应用程序的不同需求,运输层需要有两种不同的运输协议,即面向连接的 TCP 和无连接的 UDP,运输层实体之间逻辑通信信道对上层的表现因运输层使用的不同协议而有很大的差别。当采用 TCP 协议时,尽管下面的网络是不可靠的(只提供尽最大努力服务),但这种逻辑通信信道就相当于一条全双工的可靠信道。但当采用UDP协议时,这种逻辑通信信道仍然是一条不可靠信道。
按照 OSI 的术语,两个对等运输实体在通信时传送的数据单位叫做运输协议数据单元TPDU (Transport Protocol Data Unit)。但在 TCP/IP 体系中,则根据所使用的协议是TCP 或UDP,分别称之为TCP报文段(segment) 或UDP用户数据报。
UDP 在传送数据之前不需要先建立连接。远地主机的运输层在收到UDP报文后,不需要给出任何确认。虽然UDP不提供可靠交付,但在某些情况下UDP却是一种最有效的工作方式。
TCP 则提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。TCP 不提供广播或多播服务。由于 TCP 要提供可靠的、面向连接的运输服务,因此不可避免地增加了许多的开销,如确认、流量控制、计时器以及连接管理等。这不仅使协议数据单元的首部增大很多,还要占用许多的处理机资源。
使用UDP和TCP协议的各种应用和应用层协议
应用 应用层协议 运输层协议 名字转换 DNS(域名系统) U DP 文件传送 TFTP(简单文件传送协议) UDP 路由选择协议 RIP(路由信息协议) UDP IP地址配置 DHCP(动态主机配置协议) UDP 网络管理 SNMP(简单网络管理协议) UDP 远程文件服务器 NFS(网络文件系统) UDP IP电话 专用协议 UDP 流式多媒体通信 专用协议 UDP 多播 IGMP(网际组管理协议) UDP 电子邮件 SMTP(简单邮件传送协议) TCP 远程终端接入 TELNET(远程终端协议) TCP 万维网 HTTP(超文本传送协议) TCP 文件传送 FTP(文件传送协议)
TCP/IP 运输层的两个主要协议都是互联网的正式标准,即:
用户数据报协议UDP (User Datagram Protocol) [RFC 768]
传输控制协议TCP (Transmission Control Protocol) [RFC 793]
应用层的端口 给应用层的每个应用进程赋予一个非常明确的标志是至关重要的。在单个计算机中的进程是用进程标识符(一个不大的整数)来标志的。但是在互联网环境下,不同的操作系统使用不同格式的进程标识符,必须用与特定操作系统无关的统一的方法对 TCP/IP 体系的应用进程进行标志。
进程的创建和撤销都是动态,因此无法把一个特定机器上运行的特定进程,指明为互联网上通信的最后终点。解决这个问题的方法就是在运输层使用协议端口号(protocol port number),或通常简称为端口。虽然通信的终点是应用进程,但只要把所传送的报文交到目的主机的某个合适的目的端口,剩下的工作就由TCP或UDP来完成。
这种在协议栈层间的抽象的协议端口是软件端口,和路由器或交换机上的硬件端口不同。硬件端口是不同硬件设备进行交互的接口,而软件端口是应用层的各种协议进程与运输实体进行层间交互的一种地址。不同的系统具体实现端口的方法可以是不同的(取决于系统使用的操作系统)。
UDP和TCP的首部格式中,都有源端口和目的端口这两个重要字段。当运输层收到 IP 层交上来的运输层报文时,就能够根据其首部中的目的端口号把数据交付应用层的目的应用进程。
TCP/IP 的运输层用一个 16 位端口号(可允许有 65535 个不同的端口号)来标志一个端口。两个计算机中的进程要互相通信,不仅必须知道对方的 IP 地址(为了找到对方的计算机),而且要知道对方的端口号(为了找到对方计算机中的应用进程)。
服务器端使用的端口号:
熟知端口号(wellknown port number)或系统端口号,数值为0~1023。可在网址www.iana.org查到。IANA 把这些端口号指派给了 TCP/IP 最重要的一些应用程序,让所有的用户都知道。当一种新的应用程序出现后,IANA 必须为它指派一个熟知端口,否则互联网上的其他应用进程就无法和它进行通信。
登记端口号,数值为 1024~49151。这类端口号是为没有熟知端口号的应用程序使用的。使用这类端口号必须在IANA按照规定的手续登记,以防止重复。
客户端使用的端口号:数值为 49152~65535。仅在客户进程运行时才动态选择,又叫做短暂端口号。这类端口号留给客户进程选择暂时使用。当服务器进程收到客户进程的报文时,就知道了客户进程所使用的端口号,因而可以把数据发送给客户进程。通信结束后,端口号就可以供其他客户进程使用。
用户数据报协议UDP
UDP 概述 UDP只在IP的数据报服务之上增加了复用和分用的功能以及差错检测的功能。UDP的主要特点是:
无连接,即发送数据之前不需要建立连接(当然,发送数据结束时也没有连接可释放),因此减少了开销和发送数据之前的时延。
使用尽最大努力交付,不保证可靠交付,因此主机不需要维持复杂的连接状态表(这里面有许多参数)。
面向报文。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。UDP 一次发送一个报文,应用程序必须选择合适大小的报文。若报文太长,UDP把它交给IP层后,IP层在传送时可能要进行分片,这会降低IP层的效率。反之,若报文太短,UDP把它交给IP层后,会使IP数据报的首部的相对长度太大,这也降低了IP层的效率。
没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。这适合某些实时应用的要求如 IP 电话、实时视频会议等,其要求源主机以恒定的速率发送数据,并且允许在网络拥塞时丢失数据,但却不允许数据有太大的时延。
支持一对一、一对多、多对一和多对多的交互通信。
首部开销小,只有8个字节,比TCP的20个字节的首部要短。
当很多的源主机同时都向网络发送高速率的实时视频流时,网络就有可能发生拥塞,结果大家都无法正常接收。还有一些使用 UDP 的实时应用,需要对 UDP 的不可靠的传输进行适当的改进,以减少数据的丢失。应用进程本身可以增加一些提高可靠性的措施,如采用前向纠错或重传已丢失的报文。
UDP 的首部格式 用户数据报UDP 有两个字段:数据字段和首部字段。首部字段很简单,只有8个字节(图5-5),由四个字段组成,每个字段的长度都是两个字节。各字段意义如下:
字段名称 字段含义 字节数 源端口 在需要对方回信时选用。不需要时可用全0 2 目的端口 在终点交付报文时必须使用 2 长度 UDP用户数据报的长度,其最小值是8(仅有首部) 2 检验和 检测UDP用户数据报在传输中是否有错。有错就丢弃 2
当运输层从IP层收到UDP数据报时,就根据首部中的目的端口,把数据报通过相应的端口,上交应用进程。如果接收方 UDP 发现目的端口号不正确(即不存在对应于该端口号的应用进程),就丢弃该报文,并由网际控制报文协议 ICMP 发送“端口不可达”差错报文给发送方。ICMP的traceroute,就是让发送的UDP用户数据报故意使用一个非法的UDP 端口,结果ICMP 就返回“端口不可达”差错报文,因而达到了测试的目的。
虽然在 UDP 之间的通信要用到其端口号,但由于 UDP 的通信是无连接的,因此不需要使用套接字(TCP之间的通信必须要在两个套接字之间建立连接)。
UDP 用户数据报首部中检验和的计算方法有些特殊。在计算检验和时,要在 UDP 用户数据报之前临时添加增加 12 个字节的伪首部。检验和就是按照这个临时的UDP用户数据报来计算的。伪首部既不向下传送也不向上递交,而仅仅是为了计算检验和。IP数据报的检验和只检验IP数据报的首部,但UDP的检验和是把首部和数据部分一起都检验。
在发送方,首先是先把全零放入检验和字段。再把伪首部以及 UDP 用户数据报看成是由许多16 位的字串接起来的。若UDP用户数据报的数据部分不是偶数个字节,则要填入一个全零字节(但此字节不发送)。然后按二进制反码计算出这些16位字的和。将此和的二进制反码写入检验和字段后,就发送这样的UDP用户数据报。在接收方,把收到的UDP用户数据报连同伪首部(以及可能的填充全零字节)一起,按二进制反码求这些 16 位字的和。当无差错时其结果应为全 1。否则就表明有差错出现,接收方就应丢弃这个 UDP 用户数据报(也可以上交给应用层,但附上出现了差错的警告)。图 5-7 给出了一个计算 UDP 检验和的例子。这里假定用户数据报的长度是15字节,因此要添加一个全0的字节。读者可以自己检验一下在接收端是怎样对检验和进行检验的。这种差错检验方法的检错能力不强,但简单,处理起来较快。
,这样的检验和,既检查了UDP用户数据报的源端口号和目的端口号以及UDP用户数据报的数据部分,又检查了IP数据报的源IP地址和目的地址。
传输控制协议TCP概述
TCP 最主要的特点 特点名称 特点描述 面向连接 TCP 是面向连接的运输层协议。应用程序在使用 TCP 协议之前,必须先建立 TCP 连接。在传送数据完毕后,必须释放已经建立的 TCP 连接。 点对点通信 每一条 TCP 连接只能有两个端点(endpoint),只能是点对点的(一对一)。 可靠交付 TCP 提供可靠交付的服务。传送的数据,无差错、不丢失、不重复,并且按序到达。 全双工通信 TCP 提供全双工通信。TCP 允许通信双方的应用进程在任何时候都能发送数据。TCP 连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序在把数据传送给 TCP 的缓存后,就可以做自己的事,而 TCP 在合适的时候把数据发送出去。在接收时,TCP 把收到的数据放入缓存,上层的应用进程在合适的时候读取缓存中的数据。 面向字节流 “流”指的是字节序列。“面向字节流”的含义是:虽然应用程序和 TCP 的交互是一次一个数据块(大小不等),但 TCP 把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。TCP 并不知道所传送的字节流的含义。TCP 不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系(例如,发送方应用程序交给发送方的 TCP 共 10 个数据块,但接收方的 TCP 可能只用了 4 个数据块就把收到的字节流交付上层的应用程序)。由接收方的应用程序把它还原成有意义的应用层数据。
TCP 和UDP 在发送报文时所采用的方式完全不同。TCP并不关心应用进程一次把多长的报文发送到 TCP 的缓存中,而是根据对方给出的窗口值 和当前网络拥塞的程度 来决定一个报文段应包含多少个字节(UDP 发送的报文长度是应用进程给出的)。
TCP 的连接 TCP 把连接作为最基本的抽象。TCP 的许多特性都与TCP 是面向连接的这个基本特性有关。每一条 TCP 连接有两个端点。那么,TCP 连接的端点叫做套接字(socket)或插口。根据RFC 793的定义:端口号拼接到(concatenated with) IP地址即构成了套接字。因此,套接字的表示方法是在点分十进制的 IP 地址后面写上端口号,中间用冒号或逗号隔开。每一条TCP连接唯一地被通信两端的两个端点(即两个套接字)所确定。即:
TCP 连接 ::= {socket1, socket2} = {(IP1: port1), (IP2: port2)}
总之,TCP 连接就是由协议软件所提供的一种抽象。虽然有时为了方便,我们也可以说,在一个应用进程和另一个应用进程之间建立了一条TCP 连接。
可靠传输的工作原理 TCP 下面的网络所提供的是不可靠的传输。因此,TCP 必须采用适当的措施才能使得两个运输层之间的通信变得可靠。理想的传输条件下,传输信道不产生差错,且不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据。此时不需要采取任何措施就能够实现可靠传输。
然而实际的网络都不具备以上两个理想条件。需要依靠可靠传输协议,当出现差错时让发送方重传出现差错的数据,同时在接收方来不及处理收到的数据时,及时告诉发送方适当降低发送数据的速度。
停止等待协议 这里讨论原理时,把A叫做发送方,而B叫做接收方。并不考虑数据是在哪一个层次上传送的 ,把传送的数据单元都称为分组。“停止等待”就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。
无差错情况下,A 发送,B 确认,A 收到确认后再发送下一个分组
出现差错时。B 接收分组时检测出了差错,就丢弃,而不通知 A 。也可能是 M1在传输过程中丢失了,A只要超过了一段时间仍然没有收到确认,就认为刚才发送的分组丢失了,因而重传前面发送过的分组。这就叫做超时重传。这需要在每发送完一个分组时设置一个超时计时器。如果在超时计时器到期之前收到了对方的确认,就撤销已设置的超时计时器。
A在发送完一个分组后,必须暂时保留已发送的分组的副本,在收到相应的确认后才能清除。
分组和确认分组都必须进行编号。这样才能明确是哪一个发送出去的分组收到了确认。
超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些。太长会使通信的效率就会很低。太短会导致产生不必要的重传,浪费网络资源。然而,在运输层重传时间的准确设定是非常复杂的,这是因为已发送出的分组到底会经过哪些网络,以及这些网络将会产生多大的时延(这取决于这些网络当时的拥塞情况),这些都是不确定因素。
连续ARQ协议 连续ARQ协议中,发送方维持的发送窗口内的分组都可连续发送出去,而不需要等待对方的确认。这样,信道利用率就提高了。“向前”是指“向着时间增大的方向”,而“向后”则是“向着时间减少的方向”。分组发送是按照分组序号从小到大发送的。
协议规定,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。接收方一般都是采用累积确认的方式。接收方不必对收到的分组逐个发送确认,而是在收到几个分组后,对按序到达的最后一个分组发送确认,累积确认优点是:容易实现,即使确认丢失也不必重传。但缺点是不能向发送方反映出接收方已经正确收到的所有分组的信息。例如,如果发送方发送了前 5 个分组,而中间的第 3 个分组丢失了。这时接收方只能对前两个分组发出确认。发送方无法知道后面三个分组的下落,而只好把后面的三个分组都再重传一次。这就叫做 Go-back-N(回退 N),表示需要再退回来重传已发送过的 N 个分组。可见当通信线路质量不好时,连续ARQ协议会带来负面的影响。
TCP 可靠传输的实现
发送窗口的描述 发送窗口的位置由窗口前沿和后沿的位置共同确定。窗口里面的序号表示允许发送的序号。
后沿 前沿 位置特征 后沿的后面部分表示已发送且已收到了确认,这些数据不需要再保留。 前沿的前面部分表示不允许发送的,因为接收方都没有为这部分数据保留临时存放的缓存空间。 变化情况 前移 不动:没有收到新的确认,或者收到新的确认但对方通知的窗口缩小了 向后收缩: 对方通知的窗口缩小了。很可能在收到这个通知以前已经发送了窗口中的许多数据,现在又要收缩窗口,容易产生错误。
要描述一个发送窗口的状态需要三个指针:P1,P2 和 P3
窗口段 数据状态 P3 – P1 发送窗口 P2 – P1 已发送但尚未收到确认的字节数 P3 – P2 当前尚未发送的字节数(可用窗口 、有效窗口 )
A 收到 B 发来的确认报文段,根据其中窗口( 20 字节)、确认号(31 → 表明 B 期望收到的下一个序号是 31,而序号 30 为止的数
据已经收到了 ) 这两个数据构造出自己的发送窗口。
A 可以连续把窗口内的数据都发送出去。发送的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用。
B 的接收窗口大小是 20。在接收窗口外的数据已经发送过确认,并且已经交付主机了,可以不再保留。窗口内的序号(31 ~ 50)是允许接收的。
若 A 已发送到 41,B 收到了序号为 32 和 33 的数据,31 的数据没有收到(也许丢失了,也许滞留在网络中的某处)。B 只能对按序收到的数据中的最高序号给出确认,因此确认报文段中的确认号仍然是 31。
B 收到了序号为 31 的数据,并把序号为 31 ~ 33 的数据交付主机,然后 B 删除这些数据。接着把接收窗口向前移动 3 个序号,同时给 A 发送确认,其中窗口值仍为 20,但确认号是 34。
A 收到 B 的确认后,就可以把发送窗口向前滑动 3 个序号,但指针 P2 不动,现在 A 的可用窗口增大了,可发送的序号范围是 42 ~ 53。
(2013年真题·39)主机甲与主机乙之间己建立一个 TCP 连接,双方持续有数据传输,且数据无差错与丢失。若甲收到 1 个来自乙的 TCP 段,该段的序号为 1913 、确认序号为 2046 、有效载荷为100 字节,则甲立即发送给乙的 TCP 段的序号和确认序号分别是
A. 2046 、2012
B. 2046 、 2013
C. 2047 、 2012
D. 2047 、 2013
TCP的流量控制
利用滑动窗口实现流量控制 如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。所谓 流量控制(flow control) 就是让发送方的发送速率不要太快,要让接收方来得及接收。
TCP为应用程序提供了流量控制(Flow Control)服务,以解决发送方发送数据太快导致接收方来不及接收,使接收缓存溢出的问题。流量控制是一个速度匹配服务,使发送方的发送速率与接收方应用程序的读速率相匹配。
利用滑动窗口机制 ,可以很方便地使接收方控制发送方发送窗口大小,来实现连接上的流量控制:
假设A向B发送数据,每一个报文段为 100 字节长,而数据报文段序号的初始值设为 1(seq = 1)。
TCP 的窗口单位是字节,不是报文段。
大写ACK表示首部中的确认位ACK,小写 ack 表示确认字段的值。只有在ACK = 1时确认号字段 ack 才有意义。
连接建立时双方商定发送窗口大小,在报文段首部的TCP窗口字段 写入,发送方的发送窗口的大小必须小于该值。例:rwnd = 400(rwnd 表示 receiver window)。
通信的过程中,接收方会根据接收缓存中可用大小,在确认报文中设置 rwnd 来动态调整对方的发送窗口大小的上限值。
若窗口值减到 rwnd = 0,表示不允许发送方再发送数据了。这将持续到主机 B 重新发出一个新的窗口值为止,TCP 为每一个连接设有一个持续计时器(persistence timer)。此时 A 启动持续计时器。
若 B的接收缓存又有了一些存储空间,想通知 A,但是 B发送的 rwnd = 400 的报文段在传送过程中丢失。而形成 A等待B发送的非零窗口的通知,而B等待A发送的数据。
持续计时器可打破死锁局面,到期后就发送一个零窗口探测报文段 (仅携带 1 字节的数据),对方就在给出了现在的窗口值。如果窗口仍然是零,A 重新设置持续计时器。
TCP 的传输效率 应用进程把数据传送到 TCP 的发送缓存后,剩下的发送任务就由 TCP来控制了。可以用不同的机制来控制TCP报文段的发送时机。例如,
第一种机制是TCP维持一个变量,它等于最大报文段长度MSS。只要缓存中存放的数据达到MSS字节时,就组装成一个 TCP 报文段发送出去。
第二种机制是由发送方的应用进程指明要求发送报文段,即TCP支持的推送(push)操作。
第三种机制是发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(但长度不能超过MSS)发送出去。
但是,如何控制TCP发送报文段的时机仍然是一个较为复杂的问题。例如,一个交互式用户使用一条TELNET连接(运输层为TCP协议)。假设用户只发1个字符,加上 20 字节的首部后,得到 21 字节长的 TCP 报文段。再加上 20 字节的 IP 首部,形成41字节长的IP数据报。在接收方TCP立即发出确认,构成的数据报是40字节长(假定没有数据发送)。若用户要求远地主机回送这一字符,则又要发回 41 字节长的 IP 数据报和40字节长的确认IP数据报。这样,用户仅发1个字符时,线路上就需传送总长度为162 字节共 4 个报文段。当线路带宽并不富裕时,这种传送方法的效率的确不高。因此应适当推迟发回确认报文,并尽量使用捎带确认的方法。
在 TCP 的实现中广泛使用 Nagle 算法。算法如下:若发送应用进程把要发送的数据逐个字节地送到 TCP 的发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节都缓存起来。当发送方收到对第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文段发送出去,同时继续对随后到达的数据进行缓存。只有在收到对前一个报文段的确认后才继续发送下一个报文段。当数据到达较快而网络速率较慢时,用这样的方法可明显地减少所用的网络带宽。Nagle 算法还规定,当到达的数据已达到发送窗口大小的一半或已达到报文段的最大长度时,就立即发送一个报文段。这样做,就可以有效地提高网络的吞吐量。
另一个问题叫做糊涂窗口综合征(silly window syndrome)[RFC 813],有时也会使TCP的性能变坏。设想一种情况:TCP 接收方的缓存已满,而交互式的应用进程一次只从接收缓存中读取1个字节(这样就使接收缓存空间仅腾出1个字节),然后向发送方发送确认,并把窗口设置为1个字节(但发送的数据报是40字节长)。接着,发送方又发来1个字节的数据(请注意,发送方发送的 IP 数据报是 41 字节长)。接收方发回确认,仍然将窗口设置为1 个字节。这样进行下去,使网络的效率很低。
要解决这个问题,可以让接收方等待一段时间,使得或者接收缓存已有足够空间容纳一个最长的报文段,或者等到接收缓存已有一半空闲的空间。只要出现这两种情况之一,接收方就发出确认报文,并向发送方通知当前的窗口大小。此外,发送方也不要发送太小的报文段,而是把数据积累成足够大的报文段,或达到接收方缓存的空间的一半大小。上述两种方法可配合使用。使得在发送方不发送很小的报文段的同时,接收方也不要在缓存刚刚有了一点小的空间就急忙把这个很小的窗口大小信息通知给发送方。
TCP协议的拥塞控制
拥塞控制的一般原理 在计算机网络中的链路容量(即带宽)、交换结点中的缓存和处理机等,都是网络的资源。在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫做拥塞(congestion)。
若网络中有许多资源同时呈现供应不足,网络的性能就要明显变坏,整个网络的吞吐量将随输入负荷的增大而下降。
从原理上讲,寻找拥塞控制的方案无非是寻找使不等式(5-7)不再成立的条件。这或者是增大网络的某些可用资源(如业务繁忙时增加一些链路,增大链路的带宽,或使额外的通信量从另外的通路分流),或减少一些用户对某些资源的需求(如拒绝接受新的建立连接的请求,或要求用户减轻其负荷,这属于降低服务质量)。但正如上面所讲过的,在采用某种措施时,还必须考虑到该措施所带来的其他影响。
网络拥塞是一个非常复杂的问题。简单地任意增加一些资源,例如,把结点缓存的存储空间扩大,或把链路更换为更高速率的链路,或把结点处理机的运算速度提高,在许多情况下,反而还可能使网络的性能更坏。
当某个结点缓存的容量太小时,到达该结点的分组因无存储空间暂存而不得不被丢弃。若将该结点缓存的容量扩展到非常大,于是凡到达该结点的分组均可缓存队列中排队,由于输出链路的容量和处理机的速度并未提高,因此在这队列中的绝大多数分组的排队等待时间将会大大增加,结果上层软件只好把它们进行重传(因为早就超时了)。简单地扩大缓存的存储空间同样会造成网络资源的严重浪费,因而解决不了网络拥塞的问题。
简单地将处理机的速率提高,可能会使上述情况缓解一些,但往往又会将瓶颈转移到其他地方。问题的实质往往是整个系统的各个部分不匹配。只有所有的部分都平衡了,问题才会得到解决。
拥塞引起的重传并不会缓解网络的拥塞,反而会加剧网络的拥塞。如果一个路由器没有足够的缓存空间,它就会丢弃一些新到的分组。但当分组被丢弃时,发送这一分组的源点就会重传这一分组,甚至可能还要重传多次。这样会引起更多的分组流入网络和被网络中的路由器丢弃。
所谓拥塞控制就是防止过多的数据注入到网络中,使网络中的路由器或链路不致过载。拥塞控的前提,就是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素。但 TCP 连接的端点只要迟迟不能收到对方的确认信息,就猜想在当前网络中的某处很可能发生了拥塞,但这时却无法知道拥塞到底发生在网络的何处,也无法知道发生拥塞的具体原因。(是访问某个服务器的通信量过大?还是在某个地区出现自然灾害?)
流量控制所要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收。这里面网络本身的带宽可能是足够大的,因而不存在产生拥塞的问题。流量控制往往是指点对点通信量的控制,是个端到端的问题(接收端控制发送端)。
拥塞控制和流量控制之所以常常被弄混,是因为某些拥塞控制算法是向发送端发送控制报文,并告诉发送端,网络已出现麻烦,必须放慢发送速率。这点又和流量控制是很相似的。进行拥塞控制需要付出代价。这首先需要获得网络内部流量分布的信息。在实施拥塞控制时,还需要在结点之间交换信息和各种命令,以便选择控制的策略和实施控制。这样就产生了额外开销。拥塞控制有时需要将一些资源(如缓存、带宽等)分配给个别用户(或一些类别的用户)单独使用,这样就使得网络资源不能更好地实现共享。十分明显,在设计拥塞控制策略时,必须全面衡量得失。
负载(offered load),也称为输入负载或网络负载,代表单位时间内输入给网络的分组数目。因此提供的负载。吞吐量(throughput),代表单位时间内从网络输出的分组数目。具有理想拥塞控制的网络,在吞吐量饱和之前,网络吞吐量应等于提供的负载,故吞吐量曲线是 45°的斜线。但当提供的负载超过某一限度时,由于网络资源受限,吞吐量不再增长而保持为水平线,即吞吐量达到饱和。这就表明提供的负载中有一部分损失掉了(例如,输入到网络的某些分组被某个结点丢弃了)。虽然如此,在这种理想的拥塞控制作用下,网络的吞吐量仍然维持在其所能达到的最大值。
但是,实际网络的情况就很不相同了。随着提供的负载的增大,网络吞吐量的增长速率逐渐减小。在网络吞吐量还未达到饱和时,就已经有一部分的输入分组被丢弃了。当网络的吞吐量明显地小于理想的吞吐量时,网络就进入了轻度拥塞的状态。
当提供的负载达到某一数值时,网络的吞吐量反而随提供的负载的增大而下降,这时网络就进入了拥塞状态。当提供的负载继续增大到某一数值时,网络的吞吐量就下降到零,网络已无法工作,这就是所谓的死锁(deadlock)。
实践证明,拥塞控制是很难设计的,因为它是一个动态的(而不是静态的)问题。当前网络正朝着高速化的方向发展,这很容易出现缓存不够大而造成分组的丢失。但分组的丢失是网络发生拥塞的征兆而不是原因。在许多情况下,甚至正是拥塞控制机制本身成为引起网络性能恶化甚至发生死锁的原因。可以从控制理论的角度来看拥塞控制这个问题。这样,从大的方面看,可以分为开环控制和闭环控制两种方法。开环控制就是在设计网络时事先将有关发生拥塞的因素考虑周到,力求网络在工作时不产生拥塞。但一旦整个系统运行起来,就不再中途进行改正了。
闭环控制是基于反馈环路的概念,主要有以下几种措施:
监测网络系统以便检测到拥塞在何时、何处发生。
把拥塞发生的信息传送到可采取行动的地方。
调整网络系统的运行以解决出现的问题。有很多的方法可用来监测网络的拥塞。主要的一些指标是:由于缺少缓存空间而被丢弃的分组的百分数、平均队列长度、超时重传的分组数、平均分组时延、分组时延的标准差,等等。上述这些指标的上升都标志着拥塞的增长。一般在监测到拥塞发生时,要将拥塞发生的信息传送到产生分组的源站。当然,通知拥塞发生的分组同样会使网络更加拥塞。
另一种方法是在路由器转发的分组中保留一个比特或字段,用该比特或字段的值表示网络没有拥塞或产生了拥塞。也可以由一些主机或路由器周期性地发出探测分组,以询问拥塞是否发生。此外,过于频繁地采取行动以缓和网络的拥塞,会使系统产生不稳定的振荡。但过于迟缓地采取行动又不具有任何实用价值。因此,要采用某种折中的方法。但选择正确的时间常数是相当困难的。
TCP 的拥塞控制方法 算法名称 描述 慢开始 (Slow Start) 每经过一个传输轮次,发送方的拥塞窗口 cwnd 加倍(初始为不超过 2 至 4 个发送方的最大报文段 SMSS (Sender Maximum Segment Size)的数值)。 拥塞避免 (Congestion Avoidance) 拥塞窗口大小达到慢开始门限 ssthresh 时,将拥塞窗口控制为按线性规律增长,每经过一个 RTT 把 cwnd 加 1。 网络出现超时,则调整门限值 ssthresh = cwnd / 2,同时设置 cwnd = 1,进入慢开始阶段 快重传 (Fast Retransmit) 当发送方连续收到多个重复的确认时,表明某个报文段丢失,发送方会立即重传该报文段,而不必等待超时。 快恢复 (Fast Recovery) 在快重传后,发送方调整门限值 ssthresh = cwnd / 2 = 8,同时设置拥塞窗口 cwnd = ssthresh 或 ssthresh + 3 × MSS, 并开始执行拥塞避免算法
真题 【2009题39】一个TCP连接总是以1KB的最大段长发送TCP段,发送方有足够多的数据要发送。当拥塞窗口为16KB时发生了超时,如果接下来的4个RTT(往返时间)时间内的TCP段的传输都是成功的,那么当第4个RTT时间内发送的所有TCP段都得到肯定应答时,拥塞窗口大小是()。
A. 7KB B. 8KB C. 9KB D. 16KB
TCP 的运输连接管理
TCP 连接的建立 TCP 建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个 TCP 报文段。
三报文握手建立连接过程 最初两端的 TCP 进程都处于 CLOSED(关闭)状态。A 主动打开连接,而 B 被动打开连接:
阶段 标志事件 B → LISTEN (收听) B 的 TCP 服务器进程先创建传输控制块 TCB,准备接受客户进程的连接请求。 A → SYN-SENT (同步已发送) A 的 TCP 客户进程创建传输控制模块 TCB。在打算建立 TCP 连接时, 向 B 发出连接请求报文段,首部中:SYN 报文段不能携带数据,但要消耗掉一个序号。 B → SYN-RCVD (同步收到) B 发送确认。确认报文段中:SYN = ACK =1 确认号 ack = x + 1 初始序号 seq = y 这个报文段也不能携带数据,但同样要消耗掉一个序号。 A → ESTABLISHED (已建立连接) A 向 B 给出确认。确认报文段: ACK =1 确认号 ack = y + 1 序号 seq = x+1 ACK 报文段可以携带数据。若不携带数据则不消耗序号,即下一个数据报文段的序号仍是 seq = x + 1。 B → ESTABLISHED (已建立连接) B 收到 A 的确认
四报文握手 B 发送给 A 的报文段,也可拆成两个报文段。可以先发送一个确认报文段(ACK = 1, ack = x + 1),然后再发 送一个同步报文段(SYN = 1, seq = y)。这样的过程就变成了四报文握手,但效果是一 样的。
客户端发送最后一次确认的目的
防止已失效的连接请求报文段突然又传送到了服务端,导致服务端等待客户端发送数据,造成资源浪费。
A 发出连接请求而未收到确认,再重传连接请求,收到后确认建立了连接。数据传输完毕后释放了连接。
请求报文段在某些网络结点长时间滞留了,以致延误到连接释放以后 的某个时间才到达 B。
B 收到失效的连接请求报文段后误认为是新的连接请求,发出确认报文段。并一直等待 A 发来数据,导致 B 的资源浪费。
采用三报文握手的办法,A 不会向 B 的确认发出确认。B 由于收不到确认,就知道 A 并没有要求建立连接。