运输层是OSI七层模型中最重要最关键的一层,是唯一负责总体数据传输和控制的一层。运输层要达到两个主要目的:第一,提供可靠的端到端的通信(“端到端的通信” 是应用进程之间的通信);第二,向会话层提供独立于网络的运输服务。 首先,运输层之上的会话层、表示层及应用层均不包含任何数据传输的功能,而网络层又不一定需要保证发送站的数据可靠地送至目的站,其次会话层不必考虑实际网络的结构、属性、连接方式等实现的细节。运输层屏蔽了下面网络层的细节,它使应用进程看来好像在两个运输层实体之间有一条端到端的逻辑通信信道,因此运输层的功能也可是为应用进程之间提供端到端的逻辑通信( “进程”:运行着的程序)。这一章基本没有什么计算题,全是理解记忆的知识,看懂了,就一定能过!!!
目录
一、用户数据报协议 UDP
二、 传输控制协议 TCP
2.1 TCP和UDP的对比(重点)
2.2 可靠传输的工作原理
2.2.1 停止等待协议
2.2.2 滑动窗口(连续ARQ协议)
2.3 TCP报文段的首部格式(重点)
三、TCP可靠传输的实现
3.1 以字节为单位的滑动窗口(重点)
3.2 超时重传时间的选择 和 选择确认SACK(略)
四、TCP的流量控制
五、TCP的拥塞控制
5.1 TCP 的拥塞控制方法(重点)
慢开始:
拥塞避免:
快重传:
快恢复:
六、TCP的运输连接管理(重点)
三报文握手建立 TCP 连接
TCP 的连接释放(四报文挥手)
结束语
运输层和网络层的联系和区别:
之前介绍的物理层、数据链路层以及网络层它们共同解决了将主机通过异构网络互联起来所面临的问题,实现了主机到主机的通信,但实际上,在计算机网络中进行通信的真正实体是位于通信两端主机中的进程,即两台主机的应用进程互相通信。因此运输层的任务就是为应用进程之间的通信提供服务。
逻辑通信:
“逻辑通信”是指运输层之间的通信好像是沿水平方向传送数据,但事实上,这两条数据并没有一条水平方向的物理连接,要传送的数据是沿着图中上下多次的虚线方向传送的。
运输层的两个主要协议 :
这里简单做个概述,后文会详细介绍的。
TCP/IP 的运输层主要有两个协议:
两个对等的运输层实体在通信时传送的数据单位:
① UDP 在传送数据之前不需要先建立连接。对方的运输层在收到 UDP 报文后,不需要给出任何确认。UDP 不提供可靠交付,但由于其设计简单,在某些情况下效率非常高。
② TCP 则提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。
③ TCP 不提供广播或多播服务,只提供一对一的服务;而 UDP 支持一对一、一对多、多对一和多对多的交互通信。由于 TCP 要提供可靠的、面向连接的运输服务,因此不可避免地增加了许多开销。这不仅使协议数据单元的首部增大很多,还要占用许多的处理器资源。而 UDP 则简单得多。
使用 UDP 或 TCP 的典型应用和应用层协议:
运输层的端口:
通过运输层可实现多进程通信。如果不使用运输层,那么一次通信只能交付一个分组,意味着你不能边听歌边打游戏( 痛苦(ʘ̥∧ʘ̥) )。运输层相当于一个应用层和网络层中间的一个管理员,对于应用层来说它通过分用把从网络层收到的分组通过端口号,交付给指定的应用进程;对于网络层层,它通过复用把应用层各种数据都打包成不同分组下发给网络层。
但是如何指明各应用进程?
计算机中的进程是用进程标识符(PID)来标志的。但是在互联网环境下,用进程标识符来标志运行在应用层的各种应用进程则是不行的。这是因为不同的操作系统使用不同格式的进程标识符,且进程标识符的分配是动态进行的。
为了使不同计算机的应用进程能够互相通信,就必须使用与操作系统无关的方法对应用进程进行标志。
解决这个问题的方法就是在运输层使用协议端口号(protocol port number),或通常简称为端口(port)。只要把所传送的报文交到目的主机的运输层,剩下的工作(即最后交付目的进程)就由运输层协议依据端口号来完成,端口是一种逻辑接口,是应用层实体与运输层实体进行层间交互的服务访问点。 接收方的运输层通过端口将应用数据上交给不同的应用进程。
运输层用一个 16 位端口号来标志一个端口,故可表示 65536 个不同的端口(端口号为 0~65535)
互联网上的计算机通信时是采用客户 - 服务器方式(在之前第一章概述部分有介绍,P11页)。客户在发起通信请求时,必须先知道对方服务器的IP地址(用来找到目的主机)和 端口号(用来找到目的进程)。其实严格来将,TCP是客户-服务器方式,UDP是对等的方式,但是其实从本质上来说对等连接方式还是使用客户-服务器方式,只是对等连接方式中的每台主机即是客户同时又是服务器,而TCP是严格的分客户端和服务端的。
因此运输层的端口号分为下面的两大类:
【1】服务器端使用的端口号。
这里又分为两类:
其中最重要的一类是熟知端口号或全球通用端口号,数值为 0~1023。这些端口号被指派给了互联网中最重要的一些应用,让所有用户都知道,当一种新的应用程序出现后,IANA必须为它指派一个熟知端口,否则互联网上其他应用进程就无法和它通信:
常用的熟知端口号:
e.g : FTP:21、TELNET:23、SMTP:25、DNS:53、HTTP:80、HTTPS:443
另一类叫做登记端口号,数值为 1024~49151。这类端口号是为没有熟知端口号的应用程序使用的,需要在 IANA 登记,以防止重复。
【2】客户端使用的端口号。
数值为 49152~65535。这类端口号仅在客户进程运行时动态分配,由客户进程临时使用。客户进程结束后,其所使用的端口号会被系统收回,以供其他客户进程使用。
为了说明运输层端口号的的应用,还有照应下一章应用层要讲的DNS域名服务器和HTTP,这里就例举一个非常好的栗子:
在浏览器中输入域名,回车浏览它的内容。
(本人不才,为了叙述的准确性,就找了这位博主的阐述:guardwhy):
用户PC、DNS服务器、WEB服务器通过交换机进行互联,它们处于同一个以太网中。DNS服务器中的记录有该域名所对应的IP地址。我们在用户PC中使用网页浏览器来访问Web服务器的内容,在网页浏览器的地址栏中输入Web服务器的域名。
1、用户PC中的DNS客户端进程会发送一个DNS查询请求报文,其内容为"域名www.porttest.com所对应的IP地址是什么?",将UDP用户数据报封装在IP数据报中后,通过以太网发送给DNS服务器。
DNS查询请求报文需要使用运输层的UDP协议,封装成UDP用户数据报,其首部中的源端口字段的值,在短暂端口号(49151~65535)中挑选一个未被占用的,用来表示DNS客户端进程,例如49152。目的端口字段的值设置为53,这是DNS服务端进程所使用的熟知端口号。
2、DNS服务器收到该数据报后,从中解封出UDP用户数据报,交付给本服务器中的DNS服务器端进程,DNS服务器端进程解析DNS查询请求报文的内容,然后按其要求查找对应的IP地址。之后,会给用户PC发送DNS响应报文,其内容为"域名www.porttest.comsu所对应的IP地址是192.168.0.3"。
DNS响应报文需要使用运输层的UDP协议,封装成UDP用户数据报,其首部中的源端口字段的值设置为熟知端口号53,表明这是DNS服务器端进程所发送的UDP用户数据报,目的端口字段的值设置为49152,这是之前用户PC中发送DNS查询请求报文的DNS客户端进程所使用的短暂端口号。之后,将UDP用户数据报封装在IP数据报中的通过以太网发送给用户PC。
3、用户PC收到该数据报后,从中解封出UDP用户数据报,交付给用户PC中的DNS客户端进程。DNS客户端进程解析DNS响应报文的内容,就可知道自己之前的所请求的Web服务器的域名,所对应的IP地址为192.168.0.3。
4、现在,用户PC中的HTTP客户端进程,可以向Web服务器发送HTTP请求报文,其内容为"首页内容是什么?"HTTP请求报文需要使用运输层的TCP协议封装成TCP报文段,其首部中的源端口字段的值,在短暂端口号49151~65535中挑选一个未被占用的,用来表示HTTP客户端进程,例如仍然使用之前用过的49152。目的端口字段的值设置为80,这是HTTP服务器进程所使用的熟知端口号。
5、之后,将TCP报文段封装在IP数据报中,通过以太网发送给Web服务器。Web服务器收到该数据报后,从中解封出TCP报文段。TCP首部中的目的端口号为80,这表明应该将TCP报文段的数据载荷部分也就是HTTP请求报文,交付给本服务器中的HTTP服务器端进程,HTTP服务器端进程解析HTTP请求报文的内容,然后按其要求查找首页内容。然后,会给用户PC发送HTTP响应报文,其内容是HTTP客户端所请求的首页内容,HTTP响应报文需要使用运输层的TCP协议封装成TCP报文段。
其首部中的源端字段的值设置为熟知端口号80。表明这是HTTP服务器端进程所发送的TCP报文段,目的端口字段的值设置为49152,这是之前用户PC中,发送HTTP请求报文HTTP客户端进程所使用的短暂端口号。
6、交付给用户PC中的HTTP客户端进程后,HTTP客户端进程解析HTTP响应报文的内容,并在网页浏览器中进行显示,这样我们就可以在网页浏览器中,看到Web服务器所提供的首页内容。
最后,博主对此例的阐述可谓通俗易懂,感谢了 ε٩(๑> ₃ <)۶з
一、用户数据报协议 UDP
用户数据报协议UDP只在IP的数据报服务之上增加了很少一点的功能,这就是复用和分用的功能以及差错检测的功能。
UDP的主要的特点:
1、UDP 是无连接的,即发送数据之前不需要建立连接。
2、UDP 使用尽最大努力交付,即不保证可靠交付。
3、UDP 是面向报文的,即一次发送和交付一个完整的报文。
解释:UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。接收方 UDP 对 IP 层交上来的 UDP 用户数据报,在去除首部后就原封不动地交付上层的应用进程,一次交付一个完整的报文,因此应用程序必须选择合适大小的报文:
若报文太长,UDP 把它交给 IP 层后,IP 层在传送时可能要进行分片,这会降低 IP 层的效率。
若报文太短,UDP 把它交给 IP 层后,会使 IP 数据报的首部的相对长度太大,这也降低了 IP 层的效率。
4、UDP 没有拥塞控制,很适合实时通信,因为实时通信要求源主机以恒定的速率发送数据,并允许丢失部分数据。
5、UDP 支持一对一、一对多、多对一和多对多的交互通信。
6、UDP 的首部开销小,只有 8 个字节。
对 “ UDP 支持一对一、一对多、多对一和多对多的交互通信 “ ,进行解释。
复用:将 UDP 用户数据报组装成不同的 IP 数据报,发送到互联网。
分用:根据 UDP 用户数据报首部中的目的端口号,将数据报分别传送到相应的端口,以便应用进程到端口读取数据。
这里的一对多通信就是:a -> x 同时 a -> y 。相反如果改成 a -> x 同时 b -> x ,就是多对一。
注意:⚠️ ⚠️ ⚠️
这里的概念,和网络层的单播、广播、组播不同,这里侧重考虑的是端到端的交互通信。但这也向我们表示了网络层的【广播、组播】的数据报的上层协议也一定必须是UDP,不能是TCP(它只支持单播),有些题中也会说UDP广播、组播,就是强调的这个。上一章网络层:讲IPV6时,就对比IPV4详细介绍了单播、广播、组播(IP多播),可以去看看。
UDP 的首部格式
● 源端口:源端口号。在需要对方回信时选用,不需要时可全写0。
● 目的端口:目的端口号。在终点交付报文时必须用到。若不存在对应于该端口的应用进程,就丢弃报文,并由ICMP发送“端口不可达”的差错报文给发送方,这就是上一章网络层讲的路由分析诊断程序tracert。
● 长度:UDP 用户数据报的长度。其最小值是8字节(仅有首部)。
● 检验和:差错校验机制,检测 UDP 数据报在传输中是否有错,有就丢弃。
在计算检验和时,临时把“伪首部”和 UDP 用户数据报连接在一起计算。伪首部仅仅是为了计算检验和。
从上图可以看出:校验和既检查了 UDP 用户数据报的源端口号和目的端口号以及数据部分, 又同时对IP数据报的源 IP 地址和目的 IP 地址进行了校验。
计算 UDP 检验和的方法这里略了,我们学校不要求掌握。
二、 传输控制协议 TCP
TCP的特点:
【1】TCP 是面向连接的运输层协议。TCP 在传送数据之前,必须先建立连接;在传送数据完毕后,必须释放已经建立的连接。
使用UDP协议的通信双方,可以随时发送数据。使用TCP协议的通信双方,在进行数据传输之前必须使用“三报文握手”来建立TCP连接。
TCP连接建立成功后才能进行数据传输,数据传输接收后,必须使用"四报文挥手",来释放TCP连接。
而UDP只需要知道目的端的IP和端口号就可以发送,不需要建立连接。
TCP的连接建立我放到了最后一节详细介绍。
【2】每一条 TCP 连接只能有两个端点(endpoint),每一条 TCP 连接只能是点对点的(一对一)。
注意:
(1)TCP连接的端点不是主机,不是主机IP地址,也不是协议端口,更不是应用进程。而是套接字或插口,但其实就是为了实现应用进程间的可靠通信,那为什么端点不是应用进程呢?
你可以这么理解,套接字是比应用进程更为准确的描述,应用进程是人,而套接字是它的名字,它标识一个主机上的某进程,反正套接字是一个很抽象的概念,下一章我们还会有更多的介绍。
端口号拼接到 IP 地址后面,中间用冒号隔开,即构成了套接字。
套接字的表示方法:套接字 socket = (IP地址: 端口号)
每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定。即:
TCP 连接 ::= {socket1, socket2} = {(IP1: port1), (IP2: port2)}
(2)TCP 连接是一条虚连接(即逻辑连接),不是一条真正的物理连接。
(3)UDP的通信是无连接的,不需要套接字(Socket)。
【3】TCP 提供可靠交付的服务。通过 TCP 连接传送的数据,无差错、不丢失、不重复,并且按序到达。
【4】TCP 提供全双工通信。
当然TCP和UDP都提供全双工通信,客户端和服务器端能同时收发数据。
TCP 连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序把数据传送给 TCP 的发送缓存,由 TCP 在合适的时候把数据发送出去;在接收时,TCP 把收到的数据放入接收缓存,上层的应用进程在合适的时候读取缓存中的数据。
注意:
UDP存在接受缓存区,但不存在发送缓存区:
为什么UDP不存在发送缓冲区?从概念上来说就是只要有数据就发,不管对方是否可以正确接收,所以不缓冲,不需要发送缓冲区,而且UDP不保证可靠性,没有重传机制,如报文丢失时,UDP不需要重新发送,而TCP不同,它必须具备发送缓冲区,当报文丢失时,TCP必须保证重新发送。
UDP具有接收缓存区,但是这个接收缓存区不能保证收到的UDP报文的顺序和发送的UDP报文顺序一致,如果缓存区满了 ,再此到达的数据报会被丢弃。
【5】面向字节流。“流”指的是一连串的字节序列。
TCP是面向字节流的,这正是TCP实现可靠传输、流量控制、以及拥塞控制的基础。
虽然应用程序和 TCP 的交互是一次一个数据块,但 TCP 把应用程序交下来的数据仅仅看成是一连串的无结构的字节流,因此TCP 不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系,但是总的来看,接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样,并且接收方应用程序有识别字节流的能力。
对上面那句话图解一下,助于你们理解:
2.1 TCP和UDP的对比(重点)
2.2 可靠传输的工作原理
这里先不介绍TCP报文段的首部格式,下面会讲。这里我们重点是先理清楚可靠传输的工作原理,这有助于后面理解TCP可靠传输的实现。
我们知道理想传输条件有以下两个特点:
(1)传输信道不产生差错。
(2)不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据。
2.2.1 停止等待协议
全双工通信的双方既是发送者也是接收者。但是为了讨论问题的方便,这里我们仅考虑A 发送数据而B 接收数据并发送确认。下文也把传输的数据单元叫做分组,是因为并不考虑数据在哪一个层次上传输的,而是重在理清原理的实现。
【1】无差错情况
每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。
● A 发送完分组 M1 后就暂停发送,等待 B 的确认 (ACK)。
● B 收到 M1 后向 A 发送 ACK。
● A 在收到了对 M1 的确认后,就再发送下一个分组 M2。发送完之后就暂停发送,等待 B 的下一次确认。
● B 收到 M2 后向 A 发送 ACK
…………
【2】出现差错情况
若 B 接收 M1 时检测出了差错,就丢弃 M1,其他什么也不做;若 M1 在传输过程中丢失了,这时 B 什么都收不到,当然也什么都不会做。在这两种情况下,如何保证可靠传输呢?
做法:A 为每一个已发送的分组设置一个超时计时器。A 只要在超时计时器到期之前收到了相应的确认,就撤销该超时计时器,继续发送下一个分组 M2;否则就重传分组 M1。
注意:⚠️ ⚠️ ⚠️
(1)每发送完一个分组,必须暂时保留已发送的分组的副本,只有在收到相应的确认后才清除暂时保留的分组副本,就如上面介绍的发送缓存和接受缓存。
(2)分组和确认分组都必须进行编号。这样才能明确哪一个分组收到了确认,哪一个分组还没有收到确认。
(3)超时计时器的重传时间应当比分组传输的平均往返时间更长一些,防止不必要的重传。
【3】确认丢失和确认迟到情况
(1)若 B 所发送的对 M1 的确认丢失了,那么 A 在设定的超时重传时间内将不会收到确认,因此 A 在超时计时器到期后重传 M1;B 收到重传的分组就丢弃(之前已经收到过了),并向 A 重传确认。如图1:
(2)若 B 对分组 M1 的确认迟到了,则 A 在超时计时器到期后重传 M1;B 会收到重复的 M1,然后丢弃重复的 M1 并重传确认;A 最终会收到迟到的确认,但对迟到的确认什么也不用做,直接丢弃即可。如图2:
最后,使用上述的确认和重传机制,我们就可以在不可靠的传输网络上实现可靠的通信。
这种机制常称为自动重传请求 ARQ (Automatic Repeat reQuest),意思是:重传的请求是发送方自动进行的,不需要接收方的通知。
2.2.2 滑动窗口(连续ARQ协议)
从上面,我们不难看出ARQ 的优点是简单,但缺点是信道利用率太低。
这里的RTT是往返时间,Td、Ta是分别是A和B发送分组所需时间。 (当然这是粗略的计算,还有很大因素没有考虑)。
如果RTT远大于Td,那么如果你还是发完一个分组就等下来等待对方对它的确认,那信道利用率整体上就更低了。
为了提高效率,发送方可采用流水线传输,即发送方连续发送多个分组,不必每发完一个分组就停下来等待对方的确认。由于信道上一直有数据不间断地传送,这种传输方式可以获得很高的信道利用率。
流水线传输时,发送方使用滑动窗口,接收方使用累积确认。
把上述抽象的理解为如下易通的模型:
发送窗口的意义是:位于发送窗口内的分组都可以连续发送出去,而不需要等待对方的确认。
若发送方收到对第 1 个分组的确认,就把发送窗口向前滑动一个分组的位置,这样就可以发送新的分组了。
连续ARQ协议(就是这个流水线机制)采用Go-back-N(回退N)协议(简称GBN协议)进行超时重传。Go-back-N表示需要再退回来重传已发送过的N个分组。
累计确认:接收方不必对收到的分组逐个发送确认,而是在收到几个分组后,对按序到达的最后一个分组发送确认。这就表示,到这个分组为止的所有分组都已正确收到了。
累计确认有优点也有缺点,比如缺点:
假设发送方发送了 5 个分组,而中间的第 3 个分组丢失了。这时接收方只能对前两个分组发出确认,而发送方只能把后面的三个分组再超时重传一次。可见当通信质量不好时,连续ARQ协议会带来负面影响,难到就没有什么方法,比如只需要重传第3个分组,其实这是可以的,比如选择确认SACK,但是这里不会讲解,下文也只是简介了一下,你只需要知道有这个功能就ok了。
GBN协议的特点:
1)若采用n个比特对分组编号时,若接受窗口为1(即只能按序接受分组,这里的单位都是分组)那么发送窗口的大小W应满足:1 ≤ W ≤ ;
证明:发送窗口 + 接受窗口
2)接收窗口大小为1,所以只能接收期望收到的分组,对于收到的其他分组直接丢弃;
3)如果出现超时,发送方会重传所有已发送但未被确认的分组。
2.3 TCP报文段的首部格式(重点)
TCP虽然是面向字节流的,但TCP传送的数据单元却是报文段,而这些字节流仅仅是应用层数据,只是在运输层组成了TCP报文。TCP首部的前20字节是固定的,后面4n 字节是根据需求增加的,这一点和IP数据报的首部很像。
源端口和目的端口 —— 各占 2 个字节。端口是运输层与应用层之间的服务接口。运输层的复用和分用功能都要通过端口才能实现。
序号 —— 占 4 字节。序号范围:[ 0 , ],当达到上限时,下一个序号就又回到0。TCP 连接中传送的字节流(应用层数据)中的每一个字节都按顺序编号,序号字段的值指的是本报文段所发送的数据的第一个字节的序号。整个字节流的起始序号在连接建立时设置。
例如:
确认号 —— 占 4 字节,是期望收到对方的下一个报文段的数据的第一个字节的序号。若确认号 = N,则表明:到序号 N – 1 为止的所有数据都已正确收到。下文由于我们仅考虑一端发送数据而另一端接受数据并发送确认,不考虑双向同时的通信,因此我们不关心发送方确认号是多少,仅关心接收方发送的确认报文的确认号是多少。
例如:
假设主机 B 正确收到了主机 A 发送过来的一个报文段,其序号字段值是 501,而数据长度是 200 字节。那么 B 在发送给 A 的确认报文段中,确认号应置为多少?
答:A 发送的报文段,其数据部分的序号为 501 ~ 700,这表明 B 正确收到了 A 发送的到序号 700 为止的数据。因此,B期望收到 A 的下一个报文段的数据序号是 701,于是 B 发送给 A 的确认报文段中确认号为 701。
数据偏移(即首部长度)—— 占 4 位,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。“数据偏移”的单位是 4 字节。TCP 首部的最大长度是 60 字节,因此选项长度不超过 40 字节。
保留 —— 占 6 位,保留为今后使用,目前置为全 0。
紧急 URG —— 当 URG = 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。URG 字段往往与紧急指针字段配合使用。
确认 ACK —— 只有当 ACK = 1 时确认号字段才有效;当 ACK = 0 时,确认号无效。TCP 规定:在连接建立后, 所有传送的报文段都必须把 ACK 置 1 。
推送 PSH —— 接收方 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满后再向上交付。
复位 RST —— 当 RST = 1 时,表明 TCP 连接中出现严重差错(如主机崩溃或其他原因),必须释放连接,然后再重新建立连接。
同步 SYN —— 在TCP连接建立时用来同步序号。SYN = 1 表示这是一个连接请求或连接接受报文段。
● 当 SYN = 1,ACK = 0 时,表明这是连接请求报文段。
● 当 SYN = 1,ACK = 1 时,表明这是连接接受报文段。
终止 FIN —— 用来释放一个连接。FIN = 1 表明此报文段的发送方的数据已发送完毕,并要求释放此连接。
窗口 —— 占 2 字节,它是发送本报文段的一方的接收窗口。窗口值告诉对方,从本报文段首部中的确认号算起,自己还可以接收(对方还可以发送)多少字节的数据。窗口值是接收方让发送方设置其发送窗口的依据。(这很重要,因为接收方的数据缓存空间是有限制的)
例如:
假设主机 A 向主机 B 发送了一个报文段,其确认号是 701,窗口字段是 1000。
这就是告诉 B:“从 701 号算起,我(主机 A)的接收缓存空间还可接收 1000 个字节的数据,你在给我发送数据时,必须把你的发送窗口设置为 1000。
检验和 —— 占 2 字节。检验和字段检验的范围包括首部和数据这两部分。在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部。
这个伪首部和前面介绍的UDP首部检验和,添加的的伪首部是基本一样的,只是:UDP长度字段应改为TCP长度;第四个字段中的17应改为6(TCP协议号是6)。
还有一点就是,对于检验和错误的TCP报文会直接丢弃掉,因为上文我们介绍过:A 为每一个已发送的分组设置一个超时计时器。A 只要在超时计时器到期之前收到了相应的确认,就撤销该超时计时器,继续发送下一个分组 M2;否则就重传分组 M1。
紧急指针 —— 占 2 字节,仅在 URG = 1 时才有意义。它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据),因此紧急指针指出了紧急数据的末尾在报文段中的位置。
当所有紧急数据处理完后,TCP就告诉应用程序恢复到正常操作。并且,值得注意的是:即使窗口为零时也可以发送紧急数据。
选项 —— 长度可变,最长可达 40 字节。 (对它不做详细介绍,有需要自行看书上:P228)
填充 —— 使整个 TCP 首部长度是 4 字节的整数倍。
三、TCP可靠传输的实现
下面我们还是只需考虑一个方向上的数据传输:A 发送数据给 B。则 A 维持一个发送窗口,B 维持一个接收窗口。
3.1 以字节为单位的滑动窗口(重点)
发送窗口:在没有收到确认的情况下,发送方可以连续把窗口内的数据全部发送出去。窗口越大,发送方就可以连续发送更多的数据,因而可以获得更高的发送速率。
接收窗口:接收方只接收接收窗口内的数据。
为了更好的帮助理解,这里假设 A 收到了 B 发来的确认报文段,其中窗口是 20 字节,而确认号是 31。下面就是详细的过程图解:
上面都是对发送窗口需要注意的地方,简介了一下 。
下面是对接收窗口的简介。
下面开始介绍发送窗口和接收窗口互动的过程:
B发送给A的信息正是:A 收到了 B 发来的确认报文段,其中窗口是 20 字节,而确认号是 31。表明希望收到从31开始,并且最多还能接受20字节的分组。
这里不用管发送窗口,发出的报文的确认号和窗口值是多少,因为我们这里考虑的是一个方向上的数据传输,但实际上A 和 B可以同时互相通信的。这里先将P1 - P2 间的数据发送出去。
假设B的接收窗口已经按序收到了31、32、33。此时B的接收窗口就向前移动三个字节,即前移。并向A发送确认报文信息(累计确认,只需要将确认号设为34)。
当然,如果A收到了确认信息,也跟着向前移动三个字节,此时就。
注意:即使A现在收到的是确认号是34的确认报文,但这仅仅是告诉A(从31到33的数据以收到确认,并交付主机),此时34 - 41之前已经发送出去的数据还没有收到确认,但是主机不会再把它们发送一次,而是继续等待收到确认 或 在超时计时器下等待超时重传,但是此时A的发送窗口还有没发送但允许发送的数据,A就发送出去(这里假设把剩余的都发送出去了)
好了,基本过程就如上述所述。看到这里,你可能就会疑惑接收窗口和发送窗口的接收缓存和发送缓存了。
发送缓存和发送窗口
发送窗口通常只是发送缓存的一部分。但发送缓存和发送窗口的后沿是重合的
发送缓存暂时存放:
(1) 发送应用程序传送给发送方 TCP 准备发送的数据;
(2) TCP 已发送出但尚未收到确认的数据。
接收缓存和接收窗口
若不能及时读取,缓存最终会被填满,使接收窗口减小到零。
如果能够及时读取,接收窗口就可以增大,但最大不能超过接收缓存的大小。
3.2 超时重传时间的选择 和 选择确认SACK(略)
需要的可以查询其他优秀的博客哦,我们学校没做过多的介绍。
接收到的字节流序号不连续,能否设法让发送方只传送缺少的数据而不重传已经正确到达的数据?
SACK简介:
TCP的报文段的确认字段是一种累积确认,它只通告收到的最后一个按序列到达的字节,而没有通告所有收到的失序到达的那些字节,虽然这些字节已经被接收方接收并暂存在接收缓存中。这些没有被确认的字节可能会因为超时而被发送方重传。所以一个可选的功能选择确认(Selective ACK,SACK)可以解决。
每一个字节块需要用两个边界序号来标识。TCP在首部提供了一个 可 变 长的 “ SACK选项字段 ”来存放这些信息。除此之外,要使用选择确认功能,在建立TCP连接时,双方还要分别在SYN报文段和SYN+ACK报文段的首部选项中添加“允许SACK选项字段”,表示都支持选择确认功能。注意:SACK(Selective ACK)是TCP选项,它使得接收方能告诉发送方哪些报文段丢失,哪些报文段重传了,哪些报文段已经提前收到等信息。根据这些信息TCP就可以只重传哪些真正丢失的报文段。需要注意的是只有收到失序的分组时才会可能会发送SACK,TCP的ACK还是建立在累积确认的基础上的。也就是说如果收到的报文段与期望收到的报文段的序号相同就会发送累积的ACK,SACK只是针对失序到达的报文段的。SACK包括了两个TCP选项,一个选项用于标识是否支持SACK,是在TCP连接建立时时发送;另一种选项则包含了具体的SACK信息。
四、TCP的流量控制
流量控制(flow control)就是让发送方的发送速率不要太快,要让接收方来得及接收。
而我们上面介绍的滑动窗口机制可以很方便地在 TCP 连接上实现对发送方的流量控制。
流量控制的基本方法:就是接收方根据自己的接收能力控制发送方的发送速率。TCP采用控制发送方发送窗口大小(发送窗口的上限就是TCP报文段首部窗口写入的数值大小)的方法来实现TCP连接上的流量控制。
在建立连接时,接收方在报头中会携带接收窗口大小的信息。发送方的发送窗口不能超过接收方的接收窗口的数值。需要注意的是,TCP的窗口单位是字节而不是报文段。
当发送者收到了一个窗口为0的应答,发送者便停止发送,等待接收者的下一个应答。若含有新窗口值的报文段在传送过程中丢失,将导致死锁局面的产生:A 一直等待 B 发送的非零窗口的通知,而 B 也一直等待 A 发送的数据。
为了避免流量控制引发的死锁,TCP使用了持续计时器。每当发送者收到一个零窗口的应答后就启动该计时器。时间一到便主动发送零窗口探测报文询问接收者的窗口大小。若接收者仍然返回零窗口,则重置该计时器继续等待;若窗口不为0,则表示应答报文丢失了,此时重置发送窗口后开始发送,这样就避免了死锁的产生。
五、TCP的拥塞控制
在某段时间内,若对网络中某资源(带宽、缓存、处理机等)的需求超过了该资源所能提供的可用部分,网络的性能就要变坏,这种情况称为拥塞 (congestion)。
若网络中有许多资源同时呈现供应不足,网络的性能就要明显变坏,整个网络的吞吐量将随输入负荷的增大而下降,当输入负载继续增大时,网络的吞吐量可能下降到0,即网络无法工作。这就是死锁(deadlock)。出现资源拥塞的条件: 对资源需求的总和 > 可用资源
简单增加一些网络资源能解决拥塞吗?
不能,而且还可能使网络的性能更坏。
例如:
(1) 增大缓存,但未 提高处理机 的速度 ,分组排队等待的时间 将会大大增加,引起大量超时 重传;(2) 提高带宽,但不增大缓存空间和 处理机的速度 ,将会因队列溢出而丢弃新到的分组,同样会引起 大量超时 重传;(3) 简单地提高处理机的 速率也会将瓶颈转移到其他地方;并且我们应知道:超时重传会导致更多的分组进入网络,反而会进一步加剧网络的拥塞。
总之,网络拥塞是一个非常复杂的问题,他往往是由很多因素共同作用引起的,并且是一个动态变化的过程。实现拥塞控制除了增大网络的某些可用资源外,还可以通过减少一些用户对某些资源的需求来实现。
拥塞控制和流量控制的区别和联系
拥塞控制就是防止过多的数据注入到网络中,以防网络中的路由器或链路过载。它是一个全局性的过程,涉及到所有的主机和路由器。
流量控制是指在给定的发送端和接收端之间的点对点通信量的控制,即接收端抑制发送端发送数据的速率,以便使接收端来得及接收。
拥塞控制和流量控制也有相似的地方。某些拥塞控制算法通过向发送端发送控制报文(也就是确认报文),使发送端降低发送速率,以缓解网络拥塞的情况,这一点和流量控制很相似。
5.1 TCP 的拥塞控制方法(重点)
TCP 进行拥塞控制的算法有四种:
慢开始(slow-start)、拥塞避免(congestion avoidance)、快重传(fast retransmit)和快恢复(fast recovery) 。
下面为了方便介绍它们,我们只考虑单个方向上数据的传送,并忽略接收窗口对发送窗口的影响(即接收方总是有足够大的缓存空间,因而发送窗口的大小由网络的拥塞程度来决定)。
发送方维持一个叫做拥塞窗口 cwnd (congestion win-dow)的状态变量。由于不考虑接收窗口,于是发送方让自己的发送窗口等于拥塞窗口。
发送方控制拥塞窗口的原则是:
● 只要网络没有出现拥塞,拥塞窗口就可以再增大一些,以便把更多的分组发送出去,提高网络的利用率。● 但只要网络出现拥塞(依据就是出现了 超时 ),拥塞窗口就减小一些,以减少注入到网络中的分组数,缓解网络出现的拥塞。
慢开始:
慢开始算法的思路是:当主机在刚建立的 TCP 连接上发送数据时,并不清楚网络当前的状况,不宜把大量的数据注入网络,而是应当由小到大逐渐增大注入到网络中的数据量,即由小到大逐渐增大拥塞窗口的数值。
由小到大逐渐增大拥塞窗口数值(以报文段个数和轮次为单位)。
为了便于理解,我们用报文段的个数作为窗口大小的单位(实际的窗口大小单位还是字节)。cwnd 初始值设为 1,发送方每收到一个对新报文段的确认就把 cwnd 加 1。
轮次指的是:发送方把拥塞窗口所允许发送的报文段都连续发送出去,并收到对这些报文段的确认所经历的时间。
注意:发送方只要收到一个对新报文段的确认,其拥塞窗口 cwnd 就立即加 1,并可以立即发送新的报文段,而不需要等这个轮次中所有的确认都收到后再发送新的报文段。
另外,为了防止拥塞窗口 cwnd 增长过大引起网络拥塞,需要设置一个慢开始门限 ssthresh,其用法如下:
拥塞避免:
拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢地增大,即每经过一个轮次,把拥塞窗口 cwnd 值加 1,而不是加倍,使拥塞窗口 cwnd 按线性规律缓慢增长,而慢开始是指数型增长。
注意:“拥塞避免”并非完全避免拥塞,而是让拥塞窗口增长得缓慢些,使网络不容易出现拥塞。
当网络出现拥塞时 :
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(如超时计时器到期),就要把 ssthresh 设置为出现拥塞时的拥塞窗口值的一半。
然后把拥塞窗口 cwnd 重新设置为 1,并执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间处理队列中积压的分组。
图解阐述:
当 TCP 连接建立后,将拥塞窗口置为 1。为便于理解,图中的窗口单位不使用字节而使用报文段个数。慢开始门限的初始值设置为 16 个报文段,即 ssthresh = 16。
发送端的发送窗口既不能超过拥塞窗口 cwnd,也不能超过接收窗口 rwnd。但是我们假定接收窗口足够大,因此现在发送窗口的数值等于拥塞窗口的数值。
(1)在执行慢开始算法时,拥塞窗口 cwnd 的初始值为 1,发送第一个报文段 M1。
(2)发送端收到对 M1 的确认,就把 cwnd 加 1。于是发送端可以接着发送 M2 和 M3 两个报文段。
(3)发送端收到两个确认,cwnd 从 2 增大到 4,可接着发送后面的 4 个报文段…………。拥塞窗口 cwnd 随着传输轮次按指数规律增长。
(4)当拥塞窗口 cwnd 增长到慢开始门限值 ssthresh 时(即当 cwnd = 16 时),就改为执行拥塞避免算法,拥塞窗口按线性规律增长。
(5)假定拥塞窗口的数值增长到 24 时,网络出现超时,表明产生了拥塞。
(6)发生拥塞后发送端调整门限值 ssthresh = cwnd/2 = 12,同时设置拥塞窗口 cwnd = 1。发送端重新进入慢开始阶段,执行慢开始算法。
(7)当 cwnd = 12 时改为执行拥塞避免算法,拥塞窗口又按线性规律增长。
……………………
快重传:
为了避免单个报文段的意外丢失被发送方误认为网络产生了拥塞,同时为了让发送方尽早知道有个别报文段没有到达接收方,需要应用快重传算法。
做法:快重传算法首先要求接收方每收到一个失序的报文段就立即发出对已收到的报文段的重复确认。当发送方连续收到三个重复的确认时,就执行“快重传”,这样就不会出现超时,发送方也就不会误认为网络出现了拥塞。
图解阐述:
快恢复:
得益于快重传的功能,发送方知道现在只是丢失了个别的报文段,于是就不启动慢开始,但是以防万一,还是要执行快恢复算法的。
发送方在快重传丢失的报文段的同时,执行快恢复算法:令拥塞窗口 cwnd 减半,并设置慢开始门限 ssthresh 为同样的数值,然后开始执行拥塞避免算法,使拥塞窗口缓慢地线性增大。
例题:
TCP 的拥塞窗口 cwnd 与传输轮次 n 的关系如图所示:
(1)哪些传输轮次是慢开始阶段,哪些是拥塞避免阶段,哪些是快恢复阶段?
(2)门限的初始值是多少?快恢复阶段门限值是多少?
(3)假定在第 26 轮次之后收到 3 个重复的确认,因而检测出了报文段丢失,那么拥塞窗口 cwnd 和门限应设置为多大?
答案:
(1)慢开始:1 - 6、23 - 26;拥塞避免:6 – 16、17 - 22 ;快恢复:16 - 17
(2)门限的初始值是 32,快恢复的门限值是 21
(3)cwnd 应设为 4,门限值也为 4
上面讲的看懂了,就非常的简单,所有自己想想吧~
最后再强调一下:
上面我们说阐述的时建立在接收方有最够大的接收缓存,但实际上这不可能,并且接收窗口还会根据自己的接受能力制约 发送窗口,那么发送窗口就不会单纯的等于拥塞窗口,而是:
发送方的发送窗口的上限值应当取接收窗口和拥塞窗口这两个变量中较小的一个,即:
发送方的发送窗口一定不能超过接收方给出的接收窗口值rwnd。
六、TCP的运输连接管理(重点)
运输连接有三个阶段,即:连接建立、数据传送和连接释放。
TCP 连接的建立采用客户-服务器方式。主动发起连接建立的应用进程叫做客户(client),被动等待连接建立的应用进程叫做服务器(server)。
三报文握手建立 TCP 连接
图解阐述:(对于SYN和序号,上面TCP首部格式有介绍)
注意:一开始A发出的连接请求报文的ACK = 0;这里的seq = y 和上图的seq = x 毫无关系,这是两边各自维护的序号,不要迷糊了。;这里B发给A的报文段其实也可以拆分成两个报文段(可以先发送一个确认报文(ACK = 1 , ack = x + 1,seq = y -1), 然后再发送一个同步报文段(SYN = 1 , seq = y),这种就是四报文握手,但效果是一样。
这里可以这么理解,相当于B是发送方,A是接收方,那么A收到B的确认后,还要向B给出确认。那么A期望收到的下一个序号就一定是ack = y + 1,并且自己也一定要消耗一个序号(即使不携带数据)。
为什么客户端还需要再发送一次确认?
其实书上P248已经解释的相当清楚了,但我还是总结一下吧:
主要是为了防止已经失效的连接请求报文段突然又传到了B,因而产生错误。“已失效的连接请求报文段”的产生在这样一种情况下:A之前由于超时没到B的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了(因为网络并发量很大在某结点被阻塞了),以致延误到连接释放以后的某个时间才到达B。但是B收到此失效的报文段后,就认为是A又发出一次新的连接请求。于是就向A发出确认报文段,同意建立连接。如果不采用三次握手,那么只要B再发出确认,新的连接就建立了,并一直等待A发来数据,因此B的许多资源就白白浪费。
由于需要三个报文的交互才能建立 TCP 连接,所以迟到的连接请求报文段将不会导致新的 TCP 连接的建立,也就不会浪费网络和服务器端的资源。
例题:
TCP 的连接释放(四报文挥手)
数据传输结束后,通信的双方都可释放连接。如图,现在A和B正处于ESTABLISHED状态,把它CLOSED掉!!!
此时,A 到 B 这个方向的连接已经关闭(但还是会接收B发来的连接释放报文,并给出确认,其他时间拒收)
B还要重复上次的确认号ack = u + 1(因为上次的确认发给A后,A收到后就没有响应了) 。
但是这时候还没真正释放掉,这时会进入TIME - WAIT(时间等待)状态,还需要再等待2MSL后,才进入CLOSED状态。
Why ?
【1】为了保证A发送的最后一个确认报文段能够达到B。这个ACK报文段可能丢失,因而使处在LAST-ACK状态的B收不到A发送的FIN+ACK报文段的确认。B会超时重传这个ACK+FIN报文段,而A就能在这个时间内收到这个重传的报文。接着A再重传一次确认报文,并且重启2MSL计时器。使A和B都能正常的进入释放连接状态。
【2】防止已经关闭的连接报文段出现在新的连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有旧报文段都从网络中消失。这样新的连接中不会出现旧连接的数据报文。
结束语
好了,到目前为止你就复习完了网络层,如果有什么建议,欢迎在评论区下方讨论,后续我还会更新应用层 ~
期待您的点赞、收藏、关注,你的支持是我最大的动力 ₍ᐢ..ᐢ₎ ♡