计算机网络--传输层

用户数据报协议UDP(User Datagram protocol)是无连接的,仅最大可能交付,没有拥塞控制,面向报文(对于应用传下来的报文不合并也不拆分,只添加UDP首部),支持一对一,一对多,多对一,多对多的交互通信。

传输控制协议TCP(Transmission Control protocol)是面向连接的,提供可靠交付,有拥塞控制,流量监控,通过双工通信,面向字节流(把应用层传下来的看成字节流,把字节流组织成大小不等的数据块),每一条TCP连接只能是点对点的(一对一)。

UDP首部格式:

首部字段只有8个字节,包括源端口、目的端口、长度、检验和。12字节的伪首部是为了计算校验和临时添加的。

TCP首部格式

序号:对于字节流进行编号,例如序号为301,表示第一个字节的标号为301,如果携带的数据长度为100字节,那么下一个报文段的序号为401.

确定号:期望收到的下一个报文的序号,例如B正确收到A发送来的一个报文段,序号为501,携带的数据长度为200字节,因此B期望下一个报文段的序号为701,B发送给A的确认报文段中的确认好为701.

数据偏移:指的是数据部分距离报文段起始的偏移量,实际上指的是首部长度。

确认ACK:当ACK=1时确认号确认号字段有效,否则无效。TCP规定,在连接建立后所传送的报文必须把ACK置1。

同步SYN:在连接建立时用来同步序号。当SYN=1,ACK=0时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中SYN=1,ACK=1.

终止FIN:用来释放一个连接,当FIN=1,ACK=0时表示这是一个连接请求报文段,若对方同意建立连接,则响应报文中SYN=1,ACK=1

窗口:窗口作为接受方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。

TCP如何保证可靠传输

  • 校验和:TCP将保证他首部和数据的校验和。这是一个端到端的校验和,目的是检测数据在传输过程中的任何变化。如果收到段的校验和有差错,TCP将丢弃这个报文段和不确认收到此报文段
  • 流量控制:TCP连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP使用的流量控制协议是可变大可变小的滑动窗口协议。(TCP利用滑动窗口来进行流量控制)。
  • 拥塞控制:当网络拥塞时,减少数据的发送(慢开始、拥塞避免、快重传、快恢复)。
  • 停止等待协议:也是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后在发下一个分组。超时重传:当TCP发出一个段后,他启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。

TCP的三次握手:

左边为客户端,右边为服务端:

  • 首先服务端处于监听状态,等待客户的连接请求。
  • 客户端主动打开,向服务端发送请求连接报文,SYN=1,ACK=0,选择一个初始的序号x(seq = x)。
  • 服务端收到连接请求报文,如果同意建立连接,则向客户端发送连接确认报文,SYN=1,ACK=1,确认号为x+1,同时也选择一个出事的序号y(seq=y)。
  • 客户端收到服务端的连接确认报文后,还要向服务端发出确认,确认号为y+1,序号为x+1。
  • 服务端收到客户端的确认后,连接建立。

三次握手的原因:

第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。

客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认,不会进行三次握手,因此就不会在打开连接。

TCP的四次挥手:

左边为客户端,右边为服务端:(注:发起断开的可以是客户端,也可以是服务端)

  • 第一次挥手,客户端发送连接释放报文,FIN=1.客户端进入FIN_WAIT_1状态,表示客户端没有数据再会发送给服务端(TCP属于于半关闭状态)。
  • 第二次挥手,服务端接收到客户端发送到的FIN报文段(进入CLOSE_WAIT状态),发出确认(ACK,seq),此时服务端还能向客户端发送数据。客户端进入TIME_WAIT_2状态。
  • 第三次挥手,当服务端不再需要连接时,服务端向客户端发送连接释放报文,FIN=1。同时服务端进入LAST-ACK状态。
  • 第四次挥手,客户端收到发出的确认返回ACK,进入TIME-WAIT状态,等待2MSL(报文最大存活时间)后如果没有收到回复,则证明服务端已经正常关闭,则释放连接。服务端收到客户端的确认后释放连接。

四次挥手的原因:

客户端发送了FIN连接释放报文之后,服务器收到了这个报文,就进入CLOSE_WAIT状态。这个状态是为了让服务器端发送还为传送完毕的数据,传送完毕之后,服务器会发送FIN连接释放报文。

四次挥手状态变化的解释:

  • FIN_WAIT_1:FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1的状态实际上是当socket在ESTABLISHED状态时,他想主动关闭连接,向对方发送FIN报文,此时该socket即将进入FIN_WAIT_1状态。而当对方回应ACK报文后,则进入FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种状态,都会马上回应ACK报文,所以FIN_WAIT_1状态比较难遇到,而FIN_WAIT_2状态常常可以用netstat(可以列出系统上所有的网络套接字连接情况)看到。(主动方)
  • FIN_WAIT_2:在FIN_WAIT_2状态下的socket,表示半连接,也即有一方要求close连接,但另外还告诉另一方,在等等还有数据需要发送。(主动方)
  • CLOSE_WAIT:当收到对方的FIN报文后,系统回复ACK报文给对方,此时进入CLOSE_WAIT状态。接下来考虑的是,被动方是否还有数据需要传送,如果没有传送的话就可以关闭这个socket,发送FIN给对方,即关闭连接,所以在CLOSE_WAIT状态下需要完成的事情是等待去关闭连接。(被动方)
  • LAST_ACK:是被动关闭一方再发送FIN后等待对方最后的ACK报文。当收到ACK报文后,也既可以进入CLOSED可用状态。
  • TIME_WAIT:表示收到了对方的FIN报文,并发送处了ACK报文,就等2MSL后即可回到CLOSED可用状态。如果FINWAIT1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可直接TIME_WAIT状态,无需FIN_WAIT_2。设置TIME_WAIT的两个理由:
    1. 确保最后一个确认报文能够到达。如果B没有收到A发送来的确认报文,那么就会重新发送连接释放请求报文,A等待一段时间就是为了处理这种情况的发生。
    2. 等待一端时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。
  • CLOSED:表示连接中断。

三次握手与四次挥手面试中常见的问题:

1.初始化连接SYN超时问题:

  • 在三次握手时,客户端发送SYN包给服务端以后就挂了,服务端回复SYN-ACK给服务端以后,一直没有收到客户端的ACK确认,这个时候连接既没有建立起来,也不能说是失败了。(这就需要一个超时时间来让server将连接断开),否则这个连接会一直占用server的SYN连接列中的一个位置,大量这样的连接就会将server的SYN队列耗尽,让正常的连接无法处理。
  • 目前linux系统中默认进行5次重发SYN-ACK包,重试的间隔时间从1s开始,下次重试间隔是前一次的双倍,5次的时间间隔为1s,2s,4s,8s,16s,总共31s,第5发出后还需要32s才知道第5次也超时了,所以总共要63s,由于SYN超时需要63s,那么就给了攻击者一个攻击服务器的机会,攻击者在短时间内把大量的SYN包发送给服务端(俗称SYN flood攻击),用于耗尽Server端的SYN队列。
  • 什么是SYN攻击:(SYN攻击指的是,攻击客户端在短时间内伪造大量不存在的IP地址,向服务器不断发送SYN包,服务器回复确认包,并等待客户端的确认。由于原地址不存在,服务端需要不断地重发直至超时,这些伪造的SYN包长时间占用未连接队列,正常的SYN请求被丢弃,导致目标系统运行缓慢,严重者会引起网络阻塞和系统瘫痪)。
  • 如何检测SYN攻击:
    • 检测SYN攻击非常方便,当你在服务器中看到大量半连接的状态时,特别是原IP地址是随机的,基本上就可以断定是一次SYN攻击。在linux上使用系统自带的netstats命令来检测SYN攻击。
  • 如何防御SYN攻击:
    • SYN攻击不能被完全阻止,除非TCP协议重新设计。我们所能做的是尽可能减轻SYN攻击的危害,常见的SYN攻击有以下几种:
      • 缩短SYN的时间
      • 增加最大连接次数
      • 过滤网管防护(过滤网管首先要指明的防火墙,过滤网管防护首先要包罗超时设置,SYN网管和SYN署理三种)
      • SYN cookies技术

2.如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP设有一个保活计时器,显然,客户端如果出现故障,服务端不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着关闭连接。

3.四次挥手时,当客户端和服务端两边同时断开时:(参考图片)

由图片可以看出:

TCP的客户端在收到服务端的FIN包前发出了FIN包,那么服务端的状态变成了FIN_WAIT1,

客户端在FIN_WAIT1状态下收到了服务端的FIN的ACK包后,那么客户端的状态变为FIN_WAIT2,

客户端在FIN_WAIT2下收到服务端的FIN包,在确认已经收到了服务端的全部数据后,就响应ACK给服务端,然后进入TIME__WAIT。

但是,因为两端是同时断开的,所以如果客户端在FIN_WAIT_1时收到了服务端的FIN包的话,客户端发出确认信号ACK给服务端,然后进入CLOSEING状态,客户端在CLOSEING状态下收到了自己的FIN包的ACK的话,那么就进入TIME_WAIT状态。于是TCP的两端同时发出FIN包的进行断开连接,那么两端可能出现完全一样的状态转移FIN_WAIT1——>CLOSEING——>TIME_WAIT,也就时客户端和服务端最后同时进入TIME_WAIT状态。

4.TCP的TIME_WAIT状态:

为什么主动关闭方进入TIME_WAIT,被动关闭方可以进入吗?

如果主动关闭方不进入TIME_WAIT,那么主动关闭方在发完ACK以后就直接关闭,如果最后发送的ACK包没有传送到对端时,这时被动关闭方没有收到自己的FIN的ACK就不能关闭连接,接着被动关闭方就会超时重传FIN包,但是这个时候已经没有对端会给该FIN回复ACK,被动关闭就无法正常关闭连接了。所以主动关闭方需要进入TIME_WAIT以便能够重发丢掉的被动关闭方FIN的ACK。

TIME_WAIT状态为什么需要经过2MSL的时间关闭连接?

为了保证主动端发送的最后一个确认报文能够到达被动端。这个确认报文可能会丢失,如果被动端收不到这个确认报文其会重传FIN和ACK报文,而主动端会在2MSL时间内收到这个重传的报文段,每次客户端收到这个重传报文后,就会重启2MSL计时器。这样可以保证客户端和服务端正常关闭。

为了防止已失效的报文段出现在下一次连接中。主动关闭方经过2MSL后,可以保证本次连接中传输的报文段都在网络中消失,这样一来就能够保证在后面的连接中不会出现旧的连接产生的报文段了。

TIME_WAIT状态是用来解决或避免什么问题?

在上面提过,如果主动关闭放没有TIME_WAIT时,就会引发一系列的问题,当主动关闭方关闭时,被动关闭方没有收到自己的FIN会重传FIN包到主动关闭放,由于此时连接已经不存在了,主动关闭方无法识别FIN包,协议栈会任务被动关闭当”疯了“,都没有建立连接就发送FIN包?于是就会回复RST包给被动关闭方,被动关闭方就会收到一个错误(connect reset by peer)。

防止已经断开的连接在链路中残留的FIN包终止掉新的连接(重用了已断开连接的所有的5元素源IP,目的IP,TCP,源端口,目的端口。这个概率比较低,涉及到了匹配问题,迟到的FIN分段的序号必须落在新连接的一方的期望序列范围内虽然概率低,但是确实可能发生,因为初始序列都是随机的,并且序列号是32位,会回绕)。

TIME_WAIT会带来哪些问题?

TIME_WAIT带来的问题:一个连接进入TIME_WAIT状态后需要等待2MSL的时长才能断开连接占用的资源,会造成以下的问题:

作为服务器:短时间内关闭大量的Client连接,会造成服务器出现大量TIME_WAIT连接,占用大量的tuple,严重消耗服务器的资源。

最为客户端:短时间内大量的短连接,会大量消耗Client机器的端口,毕竟端口只有65535个,端口被耗尽了,后续就无法在发起新的连接了。

如何解决TIME_WAIT的一些问题:

修改tcp_max_tw_buckets:tcp_max_tw_buckets控制并发的TIME_WAIT的数量,默认值是180000.如果超过默认值,内核会把多的TIME_WAIT连接清掉,然后在日志里打一个警告。官网文档说这个选项只是为了阻止一些简单的Dos攻击,平常不要人为的降低它。

启动快速回收机制,对应内核中net.ipv4.tcp_tw_recycle。要搞清楚这个参数必须搞清楚net.ipv4.tcp_timestamps:

net.ipv4.tcp_timestamps是在RFC 1323中定义的一个TCP选项。
tcp_timestamps的本质是记录数据包的发送时间
TCP作为可靠的传输协议,一个重要的机制就是超时重,因此如何计算一个准确的RTO对于TCP性能有着重要的影响,而tcp_timestamp主要为此设计的。

当timestamp和tw_recycle两个选项同时开启情况下,开启per-host的PAWS机制。从而能快速回收处于TIME-WAIT状态的TCP流。快速回收一般是70ms即可回收

开启重用机制

5.TCP的延时确认机制:

全名Delayed Acknowledgment,简称延时ACK,翻译为延时确认,延迟ACK的目的是为了减少网络中传输大量的小报文,该报文是针对ACK报文的.一个来自发送端的报TCP会延迟ACK的发送,等待一段时间,希望应用程序会对刚刚收到的数据进行应答,这样可以用新数据讲ACK捎带过去.(一般情况下这个时延在40ms~50ms之间,如果在这时间因为发送方接收到消息以后,那么ACK将随数据一块发送,对于这个时延需要注意的是,这个时延并不是指的收到数据发送ACK的时间延迟,而是内核会启动一个定时器,每隔200ms就会检查一次,比如定时器0ms启动,200ms到期,180ms的时候数据到来,那么20ms后没有新的数据到来,ACK仍然会发送,这个时延为20ms).

这样做的目的:

  • 这样做的目的ACK报文可以合并发送,可以降低流量.
  • 按照TCP协议确认机制是累计的,也就是说本身的确认号为X,X指的是所有X之前的数据不包含X的数据都已经收到,所以如果收到按序的两个包,只需要第二个确认号即可,这样可以省下一个ACK的消耗.RFC建议最多等待两个包的积累,这样可以保证消息的及时通知.

6.TCP的窗口机制:

TCP协议里窗口机制有2种:一种是固定窗口大小;一种是滑动窗口大小。

固定窗口:这个窗口的大小就是一次传输几个数据,对所有数据帧按顺序进行编号,发送方在发送过程中始终保持着一个发送窗口,只有落在发送窗口内的帧才允许被发送,同时接收方也维持着一个接受窗口,只有落在接收窗口内的帧才允许接收。这样可以调整发送方窗口和接收方窗口的大小可以实现流量控制。

如图所示:

假设滑动窗口大小为1,每次只能发送一个数据只有接收方对这个数据进行确认以后才能发送第二个数据。我们可以看到发送方每发送一个数据接受方就要给发送方一个ACK对这个数据进行确认。只有接收到了这个确认数据以后发送方才能传输下个数据。这样如果说窗口过小,那么当传输比较大的数据的时候就需要不停的发送与确认,这个时候就会造成很大的延迟。如果说窗口的大小定义的过大。这样可能就会造成拥塞的情况。这是固定窗口的工作原理。

滑动窗口:

滑动窗口协议是TCP使用的一种流量控制方法。该协议允许发送方在停止并等待接收确认报文前可以连续发送多个分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输。只有在接收窗口向前滑动时(与此同时也发送确认),发送窗口才有可能向前滑动。收发两端的窗口按照以上规律不断向前滑动,因此这种协议成为滑动窗口协议。

在滑动窗口中缓存内的数据可以分成四类:

1.Sent and Acknowledged(已发送并收到确认):这些数据表示以发送成功并已经确认的数据,比如图中的前31个bytes,这些数据其实的位置是在窗口之外,因为窗口内顺序最低的被确认之后,要移除窗口,实际上是窗口进行合拢,同时打开接收新的待发送的的数据。

2.Send But Not Yet Acknowledged(已发送但未接收到确认):这部分数据称为发送但没有被确认,数据被发送出去,没有收到接收端的ACK,认为并没有完成发送,这属于窗口内的数据。

3.Not Send,Recipient Ready to Receive(允许发送但未发送):称为可用窗口或有效窗口,这部分是尽快发送的数据,这部分数据已经被加载到缓存中,也就是窗口中了,等待发送,其实这个窗口时完全由接收方告知的,接受方告知还时能够接受这些包,所以发送方需要尽快的发送这些包。

4.No Send, Recipent Not Ready to Receive:这些数据属于未发送同时接受段也不允许发送的,因为这些数据已经超出了发送端所接收的范围。

对于发送方来讲,窗口内包括两部分:发送窗口(已经发送了为收到ACK),可用窗口,接受端允许发送但是没有发送的那部分称为可用窗口。

滑动窗口的原理:

  1. 假设32~45这些数据,是上层Application发送给TCP的,TCP将其分成四段发送给服务端。
  2. 1:32~34  2:35~36  3:37~41  4:42~45这四个片段,依次发送出去,此时假设接收端收到了1,2,4
  3. 此时接收端的行为时回复一个ACK包说明已经接收到了32~36的数据,并将4进行缓存(保证顺序,产生一个保存3的hole)
  4. 发送端接收到ACK以后,就会将32~36的数据包从发送并没有确认切到发送已确认,这个时候窗口向右移动,可用窗口增大。
  5. 对于丢失的3,如果超时一定时间,TCP就会重新传送(重传机制),重传成功以后3,4一块被确认,不成功seq4也将被丢弃。
  6. 就是不断地重复上述的动作来进行数据的传输和流量的控制,原理图如下所示。

TCP滑动窗口的剖析:

滑动窗口协议的基本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口;同时,接收方也维持了一个连续的允许接收的帧的序号,称为接收窗口。发送窗口和接收窗口的序号的上下界是不一样的,甚至大小也可能不同。不同的滑动窗口协议靠口大小一般不同。

滑动窗口的3种动作:展开(右边向右),合拢(左边向右),收缩(右边向左)这三种动作受接收端的控制。

合拢:表示已经接收到相应字节的确认

展开:表示允许缓存发送更多对的字节

收缩(非常不希望出现的,一般是禁止的):表示本来可以发送的,现在不能发送了;但是如果收缩的是那些已发送的,就会有问题;为了避免收端会等待缓存中有更多的缓存空间时才进行通信。

7.TCP的超时重传:

每一个数据包都带有下一个数据包的编号,如果下一个数据包没有收到,那么ACK的编号就不会发生变化,如果发送方发现收到三个连续 的重复ACK,或者超时了还没有收到任何ACK,就会确认丢包,从而在发送这个包。

TCP的发送方在规定的时间内没有收到确认就要重传已发送的报文段。但是重传的时间确实TCP最复杂的问题之一。由于TCP的下层是互联网环境,发送的报文段可能只经过一个高速的局域网,也可能经过多个低速网络,并且每一个IP数据包所选择的路由还可能不同。如果超时重传时间设置太短,就会引起很多报文的不必要的重传,是网络负荷增大。但若把超时重传时间设置的过长,则又使得网络的空闲时间增大,降低传输速率。

TCP采用了自适应算法,记录了一个报文段发出的时间,以及收到相应的确认的时间。这两个时间之差就是报文段的往返时间RTT。TCP保留了RTT的一个加权平均往返时间RTTs(平滑往返时间 )。每当第一次测量到RTT样本时,RTTs值就取为所测量到的RTT样本值。但有以后每测量到一个新的RTT样本,就会按下式重新计算一次RTTs。

新的RTTs = (1-\alpha )\timesRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)——其中的 α 取值在0.8 到 0.9之间

RTO = min[UpBOUND,max[LowBOUND,(BETA*SRTT)]]——BETA(延迟方差因子(BETA is a delay variance factor (e.g., 1.3 to 2.0))

针对上面算法问题,有众多大神改进,难以长篇累牍,推荐阅读《TCP 的那些事儿》、《TCP中RTT的测量和RTO的计算

TCP的重传机制:

  • 通过上面我们可以知道,TCP的重传是由超时触发的,这会引发一个重传选择问题,假设TCP发送端连续发了1、2、3、4、5、6、7、8、9、10共10包,其中4、6、8这3个包全丢失了,由于TCP的ACK是确认最后连续收到序号,这样发送端只能收到3号包的ACK,这样在TIME_OUT的时候,发送端就面临下面两个重传选择:

    仅重传4号包

    优点:按需重传,能够最大程度节省带宽。

    缺点:重传会比较慢,因为重传4号包后,需要等下一个超时才会重传6号包

    重传3号后面所有的包,也就是重传4~10号包

    优点:重传较快,数据能够较快交付给接收端。

    缺点:重传了很多不必要重传的包,浪费带宽,在出现丢包的时候,一般是网络拥塞,大量的重传又可能进一步加剧拥塞

  • 快速重传算法:

    • 就是在连续收到3次相同确认号的ACK,那么就进行重传。这个算法基于这么一个假设,连续收到3个相同的ACK,那么说明当前的网络状况变好了,可以重传丢失的包了。

  • 选择确认算法(SACK):

    • 快速重传解决了timeout的问题,但是没解决重传一个还是重传多个的问题。出现难以决定是否重传多个包问题的根源在于,发送端不知道那些非连续序号的包已经到达接收端了,但是接收端是知道的,如果接收端告诉一下发送端不就可以解决这个问题吗?于是提出了SACK算法。

    • SACK中加入了一个SACK选项(TCP option field),允许接收端在返回Duplicate ACK时,将已经收到的数据区段(连续收到的数据范围)返回给发送端,数据区段与数据区段之间的间隔就是接收端没有收到的数据。发送端就知道哪些数据包已经收到,哪些该重传,因此SACK的发送端可以在一个RTT时间内重传多个数据包。

    • 整个TCP选项长度不超过40字节,实际最多不超过4组边界值。

SACK依靠接收端的接收情况反馈,解决了重传风暴问题,这样够了吗?接收端能不能反馈更多的信息呢?显然是可以的,于是,RFC2883对对SACK进行了扩展,提出了D-SACK,也就是利用第一块SACK数据中描述重复接收的不连续数据块的序列号参数,其他SACK数据则描述其他正常接收到的不连续数据。这样发送方利用第一块SACK,可以发现数据段被网络复制、错误重传、ACK丢失引起的重传、重传超时等异常的网络状况,使得发送端能更好调整自己的重传策略。

D-SACK,有几个优点:

发送端可以判断出,是发包丢失了,还是接收端的ACK丢失了。(发送方,重传了一个包,发现并没有D-SACK那个包,那么就是发送的数据包丢了;否则就是接收端的ACK丢了,或者是发送的包延迟到达了)

发送端可以判断自己的RTO是不是有点小了,导致过早重传(如果收到比较多的D-SACK就该怀疑是RTO小了)。

发送端可以判断自己的数据包是不是被复制了。(如果明明没有重传该数据包,但是收到该数据包的D-SACK)

发送端可以判断目前网络上是不是出现了有些包被delay了,也就是出现先发的包却后到了。

8.TCP的流量控制:

  • 利用滑动窗口看来实现流量控制。所谓流量控制就是让发送方的发送速率不要太快,要让接收端来得及接收。
  • 考虑一种情况:
    • TCP的每一个连接都设有一个持续计时器。当接收窗口的大小为0时,只要TCP连接的一方收到对方的零窗口通知,就会启动持续计时器。若持续计时器设置的时间到期,就会发送零窗口探测报文(仅携带一个字节的数据),而对方就在确认这个报文段时给出一个现在的窗口值。如果窗口仍未零,那么收到报文段一方就重新设置持续计时器。如果窗口不是零,那么死多的僵局就会打破。这样也可以及时的确认发送的报文是否丢失。
  • 必选考虑传输效率:Nagle算法
    • 算法如下:若发送应用程序吧要发送的数据逐个字节地发送到TCP的发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节都缓存起来。当发送方接收到第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文段发送出去,同时继续对随后到达的数据进行缓存。只要在收到对一个报文段的确认后才继续发送下一个报文段。当数据到达较快而网络速率较慢时,用这样的方法可明显地减少所用网络的带宽。Nagle算法还规范ing,当到达的数据已达到发送窗口大小的一半或已达到报文段的最大长度时,就立即发送一个报文段,这样可以有效的提高网络的吞吐量。
    • 出现的问题(糊涂窗口综合征):当TCP接收的缓存已满,而交互的应用进程一次只从TCP中读取一个字节,然后向发送方发送确认,并把窗口设置为1个字节。接着发送方又来1个数据。接收方发出确认,仍然将窗口设置为1字节。这样下去网络的效率很低。解决办法:让接收方等待一段时间,使得或者接收缓存已有足够空间容纳最长的报文段,或者等到接收缓存已有一半空闲的空间。只要满足二者之一,接收方就发出确认报文,并向发送方通知当前窗口的大小。

9.TCP的拥塞控制:

拥塞:在计算机网络中的链路容量,交换节点中的缓存和处理机等,都是网络的资源。在某一段时间,若对网络中某一资源的需求超过了改资源所能提供的可用部分,网络的性能就会变坏。这种情况叫做拥塞。

拥塞控制要完成的两个任务:1:公平性,2:拥塞过后的恢复

拥塞控制算法:

  1. 慢开始算法
  2. 拥塞避免算法
  3. 快速重传
  4. 快速恢复

慢开始算法和拥塞避免:

发送方维持一个叫做拥塞窗口cwnd的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态在变化。发送方让自己的发送窗口等于拥塞窗口,另外考虑到接收窗口的大最终发送窗口的上限值为Min[rwnd,cwnd].

慢开始法的思想就是,不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就拥塞窗口的大小。

如下图所系慢启动传输图:

为了防止拥塞窗口cwnd增长引起网络拥塞,还需设置一个慢开始门限(ssthresh)。ssthresh的用法如下:

当cwnd < ssthresh 时,使用慢开始算法

当cwnd > ssthresh 时,使用拥塞避免算法

当cwnd = ssthresh时,任意使用两种算法其中之一

拥塞避免算法让拥塞窗口缓慢增长,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样拥塞窗口按线性规律缓慢增长。

无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认,虽然没有收到确认可能是其他原因的分组丢失,但是因为无法判定,所以都当做拥塞来处理),就把慢开始门限设置为出现拥塞时的发送窗口大小的一半。然后把拥塞窗口设置为1,执行慢开始算法。如下图:

快速重传和快速恢复:

快重传要求接收方在收到一个失序的报文就立即重复确认,而不要等到自己发送数据时捎带确认,快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对尚未收到的报文段,而不必继续等待设置重传计时器时间到期。如下图:

快重传配合使用的还有快恢复算法,有以下两个要点:

1.当发送方连续发送三个重复确认时,就执行"乘法减小算法",把ssthresh门限减半。但是接下来并不执行慢开始算法。

2.考虑到如果网络出现拥塞的话就不会受到重复的确认,所以发送方现在认为网络可能没有拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh的大小,然后执行拥塞避免算法

如下图:

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章