【计网】(六)传输层(TCP、UDP、可靠传输、流量控制......)

news/2024/5/18 16:37:23 标签: udp, tcp/ip, 网络

文章目录

    • 传输层
    • UDP协议
    • TCP协议
      • TCP首部字段
      • 可靠传输
      • 流量控制
        • 窗口关闭问题
        • 糊涂窗口综合症
      • 拥塞控制
        • 慢启动
        • 拥塞避免
        • 拥塞发生
        • 快速恢复
      • 连接管理
        • 建立连接(3次握手)
        • 释放连接(4次挥手)

传输层

传输层有两大协议:TCP和UDP。主要掌握TCP,这也是面试的高频考点。

  • TCP(Transmission Control Protocol):传输控制协议
  • UDP(User Datagram Protocol):用户数据报协议

TCP和UDP的区别如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EJPv0eMa-1661415056481)(image/image-20220815101145177.png)]

UDP协议

UDP:用户数据报协议。它是无连接的,所以减少了建立连接和释放连接(三次握手、四次挥手)的开销。UDP是尽最大能力进行交付,它不会保证可靠性,换句话说:它会一直传输,但是它并不保证这个数据能否成功传输到目的设备。

所以UDP的首部字段比较简单,如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IvaBpGve-1661415056482)(image/image-20220815100407367.png)]

  • 源端口号、目的端口号,这都没什么好说的。指的是这个数据来自(去往)系统的某个端口。

  • UDP长度:指的是这个数据段的长度,也就是首部 + 数据部分。单位字节。

  • UDP校验和:为了保证这个数据段到达目的地后,数据是完好的。计算内容是:伪首部+首部+数据。

    • 伪首部:仅仅只是为了辅助计算校验和,并不会往下传递到网络层。伪首部是固定的12字节,
      由源IP地址(4个字节) + 目的IP地址(4个字节) + 保留位(1个字节,默认是0) + 协议代表值(1个字节,UDP固定值17) + UDP长度(2个字节)组成。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cW6qyaYM-1661415056483)(image/image-20220815101225235.png)]

TCP协议

什么是TCP协议?

TCP是面向连接的、可靠的、基于字节流的传输层通信协议。

  • 面向连接:一对一连接,不能像UDP协议那样可以一个主机向多个主机同时发送数据。
  • 可靠的:无论什么样的网络链路出来了怎么样的变化,TCP都可以保证将一个报文传输到接收端。
  • 字节流:消息是没有边界的,所以⽆论我们消息有多⼤都可以进⾏传输。并且消息是有序的,当上一个消息没有收到的时候,即使它先收到了后⾯的字节,那么也不能扔给应⽤层去处理,同时对重复的报⽂会⾃动丢弃。

TCP首部字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BagKEhmx-1661415056484)(image/image-20220815102129354.png)]

  • 序列号:在建立连接时,由计算机生成的随机数作为初始值,通过SYN包传递给接收端,每当传递一次数据,序列号就会累加本次数据的长度(数据字节数)。在建立连接后,表示这一次传给接收端的TCP数据部分的第一个字节的编号。目的是为了解决网络包乱序问题

  • 确认应答号:指下一次期望收到的数据的序列号,发送端收到这个确认应答号之后,就可以认为这个序号之前的所有数据都已经接收到了。目的是为了解决不丢包问题

  • 控制位:有6个。但是主要掌握ACK、RST、SYN、FIN。

    • ACK(Acknowledgement)即承认ACK=1时,确认应答号这个字段才有效。TCP规定除了最初建立连接时的SYN包之外,该位必须设置为1。
    • RST(Reset) 即重置:RST=1时,表示TCP连接中出现了异常,必须强制断开连接。
    • SYN(Synchronization):当SYN=1时,表示希望建立连接,并在其序列号字段设置初始值。
    • FIN(Finish)即结束:当FIN=1时,表示希望断开连接,即后续不会再有数据发送。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换FIN位为1的TCP段。
    • URG(Urgent)即紧急:当URG=1时,紧急指针字段才有效。表示当前报文段中有紧急数据,应优先尽快发送。
    • PSH(Push)
  • 窗口:占2个字节。这个字段有流量控制功能,用于告诉对方下一次允许一次性发送的数据大小。

  • 首部长度:占4位。范围在 0x0101 ~ 0x1111。在此基础之上 * 4,就是真正的首部长度。所以真正的首部长度是20字节 ~ 60字节。

  • 校验和:和UDP的校验和是一样的。都是通过 伪首部+首部+数据部分 进行计算的。伪首部占12字节,仅在计算校验和时起到作用,也不会传递到网络层。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KCGwiBye-1661415056484)(image/image-20220815111701699.png)]

可靠传输

TCP实现可靠传输的方式之一,是通过序列号确认应答在TCP中,当发送端的数据达到接收端后,接收端会返回一个确认应答消息,表示已经收到数据了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bQEEbQq2-1661415056485)(image/image-20220815145021828.png)]

当然整个网络错综复杂,难免有时会出现丢包的情况,所以TCP中有一个重传机制,它会自动重传丢失的数据。

  • 超时重传:在发送数据会,会设置一个定时器,当超过指定的时间后,没有收到对方的ACK确认应答报文,就会重发该数据。

还有一种超时重传的可能性,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CbpOp4Ke-1661415056486)(image/image-20220815150533616.png)]

滑动窗口

产生窗口的原因?

在如上图所示,TCP是每发送一个数据,都要进行一次确认应答。当上一个数据包收到之后,接收端返回确认应答之后,发送端才会发送下一个数据。

很显然,这样传递数据,效率太低了。假设数据包往返的时间越长,通信的效率就越低。

为了解决这个问题,所以才引入了窗口的概念。即使在往返时间比较长的情况下,也不会减低网络通信的效率。

窗口的大小指的是 无需等待确认应答,而可以继续发送数据的最大值

窗口的实现就是在操作系统上开辟的一块缓存空间,发送方主机在等到确认应答之前,必须在缓冲区中保留已经发送的数据。后续如果接收到相应的确认应答,才会将刚发送的数据从缓冲区清除。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wd2RFKrR-1661415056487)(image/image-20220815152547694.png)]

TCP首部中有一个字段:窗口,也就是窗口大小。

这个字段是接收端告诉发送端自己还有多少缓冲区空间可以用来接收数据。于是发送端就可以根据这个接收端的处理能力(窗口)来发送数据,而不会导致接收端处理不过来的问题。

发送方的滑动窗口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r8xf5XDl-1661415056488)(image/image-20220815153758850.png)]

如上图,在发送完1、2、3这几个数据段之后,接收方会返回确认应答,并且还会返回窗口的大小。

此时发送方看到接收方已经收到了前面的数据,它的窗口就会往后面滑动。这就是滑动窗口的意思。

切记,窗口大小的单位是字节。上图只是举例子的形式,表示窗口的大小。比如 窗口大小=4000,表示接收方可以一次性接收4000字节的数据,而4000字节,到底可以分为几个数据段,我们后面再说。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SLB00AMy-1661415056488)(image/image-20220815154405196.png)]

整个滑动窗口+自动重传的流程如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SwIoHEQF-1661415056489)(image/image-20220815154936401.png)]

重传机制-SACK

SACK(Selective Acknowledgement)即 选择性确认,作用是 使TCP只重传丢失的包,而不是重传后续所有的包

举个例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B67FlZUy-1661415056490)(image/image-20220815155726612.png)]

如上图,确认应答回复的是 期望下一次数据包发送2,也就是说 2之前的数据包都已经接收到了。2、3、4数据包有可能都丢失了。那么发送端就要重新发送2、3、4数据包。

很明显,3、4数据包已经接收到了,再重传过来也没啥作用。所以只需让发送端重传2数据包即可。
那么如何通知发送方只重传2数据包呢? 就是SACK起作用了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6E0lrOIt-1661415056491)(image/image-20220815160200325.png)]

SACK是存储在TCP首部的选项字段中。如上图所示,

  • Kind:占1个字节,Kind=5时代表这是SACK选项。
  • Length:占1个字节,表明SACK选项一共占用多少字节。
  • Left Edge:占4个字节,表示接收端已经接收某些数据的 左边界
  • Right Edge:占4个字节,表示接收端已经接收某些数据的 右边界

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rkeLmqzo-1661415056491)(image/image-20220815160603711.png)]

下图来自“小林coding”。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zefaDFoP-1661415056492)(image/image-20220815160939787.png)]

流量控制

发送方不能无脑的一直发送数据,还要考虑到接收方的情况,要考虑接收方的缓冲区是否还能存储。

如果接收方的缓冲区已经满了,发送方还在继续发送数据,此时当数据来到接收方时,并不会被存储到缓冲区,而是直接丢掉,然后就会触发重传机制,浪费带宽资源。

为了避免这种现象发生,TCP提供了一种机制可以让发送方根据接收方的实际接收能力来控制发送的数据量,这就是常听说的流量控制。通过确认报文中的窗口字段来控制发送方的发送速率,发送方的发送窗口大小不能超过接收方给出的窗口大小。当发送方收到接收窗口的大小为0时,发送方就会停止发送数据

窗口关闭问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4yGo7Gyu-1661415056493)(image/image-20220815171513339.png)]

如上图,当接收方的缓冲区满了之后,就会向发送方返回一个窗口大小=0的消息,发送方看到接收方的缓冲区满了后,就会暂时停止发送数据。

当接收方的缓冲区有剩余空间时,就会发送一个ACK报文给发送方,告诉发送方我又有缓冲空间啦。但是存在一个问题,假设这个给发送方的ACK报文丢了怎么办?会出现什么问题?如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MKJT42q7-1661415056493)(image/image-20220815172057218.png)]

当新的窗口大小的这个包丢了之后,二者就会陷入死锁状态,在哪里一直等待。


如何解决死锁的问题呢?

为了解决这个问题,TCP为每个连接都设有一个持续定时器,只要TCP连接一方收到对方的0窗口通知时,就会启动持续定时器

如果持续定时器的时间到点了,就会发送一个窗口探测报文,而对方在接收到这个报文后,就会返回自己当前的窗口大小。

下图来自“小林coding”。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cQU7Ytw0-1661415056494)(image/image-20220815172613947.png)]

当然,如果窗口探测之后,窗口大小还是0,那就会重新启动持续计时器。

窗口探测一般为3次,每次大约30秒 ~ 60秒(不同的实现可能不一样)。如果3次过后,接收窗口大小还是0,有的TCP实现就会发送RST报文来断开连接。

糊涂窗口综合症

如果接收方太忙了,根本来不及处理缓冲区的数据,导致缓存区的数据囤积的越来越多,使缓存区的空间越来越小,最后使其占满(即窗口大小=0)。

如果在窗口大小=0后,接收方处理了几个字节的数据,使窗口大小稍微变大一点点。而发送方看见接收方还有一点点缓冲区空间,就发送一点数据过来,可能这个数据才几个字节的长度。

存在的问题就是:TCP+IP的首部就有40字节,而数据部分才几个字节,这买卖属实是不划算,要用这么多的开销,获得最低的效益。就好比路边拉乘客的私家车,明明可以乘坐8个人,结果每次只乘坐1个人就开车走了,这1个人的车费还不如一去一来的油费呢。

所以为了解决这个问题,从两个方向出发:

  • 从接收方着手,让接收方不通告小窗口,当窗口大小 < min(MSS, 缓存空间/2)时,就会向发送方返回 窗口大小=0 的报文。只有当接收方的窗口大小 >= MSS 或者 >= 缓存空间/2时,才把窗口打开,让发送方发送数据过来。

  • 从发送方着手,发送方通常的策略是 使用Nagle算法,该算法的思路是延时处理,它满足以下两个条件的其中一个时,就可以发送数据:

    • 要等到窗口大小 >= MSS 或者是 数据大小 >= MSS
    • 收到之前发送数据的ACK回包

    只要上述两个条件都没满足,发送方就会一直囤积数据,直到满足上的发送条件即可。

    另外, Nagle 算法默认是打开的,如果对于⼀些需要⼩数据包交互的场景的程序,⽐如, telnet 或 ssh 这样的交互性⽐较强的程序,则需要关闭 Nagle 算法。

拥塞控制

可能你会不理解,前面不是已经有了流量控制吗?怎么还有拥塞控制呢?

因为二者所解决的问题是不一样的。前面说了流量控制是防止接收端的缓冲区空间不够用的情况;而拥塞控制解决的是网络带宽不够用的情况。

一般来说,计算机网络都处在一个共享的环境。因此也有可能会因为其他主机之间的通信使得网络拥堵。网络出现拥堵时,如果继续发送大量的数据包,可能会导致很多的数据包出现延迟、丢包等状况,进而可能就会触发TCP超时重传机制,但一旦又开始重传,就又导致网络的负担增加,可能就会导致更多的数据包延迟、丢失,进入恶性循环

所以TCP协议就会自己调整,当网络拥堵的时候,就尽量少发送点数据包。于是就有了拥塞控制,目的就是为了避免发送方的数据填满整个网络。上文为了控制发送方的发送数据量,增加了发送窗口swnd接收窗口rwnd,现在又增加一个拥塞窗口cwnd;拥塞窗口是发送方维护的一个状态变量,它可以根据网络拥塞程度来变化。

所以 发送窗口swnd = min(接收窗口rwnd, 拥塞窗口cwnd)

拥塞窗口的变化规则就是 只要网络中没有出现拥塞,窗口就会增大,反之就会减小。


那么如何判断网络是否出现拥塞?

只要发送方没有在规定时间内接收到 ACK确认应答报文,换句话说就是触发了超时重传,就会认为网络出现了拥塞。


拥塞控制有四个算法

  • 慢启动
  • 拥塞避免
  • 拥塞发生
  • 快速恢复

慢启动

在TCP刚建立连接后,首先是慢启动阶段,字面意思就是刚开始发送数据时,是一个比较缓慢的过程。

慢启动算法记住一个规则:每收到一个ACK确认应答报文,拥塞窗口cwnd的大小就+1。

就如下图所示,来自《无名之辈》桥段,告诉我们起步要慢。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KZvixQ66-1661415056494)(image/image-20220816094204223.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-31O42SY7-1661415056495)(image/image-20220816094315133.png)]

慢启动趋势图如下:来自“小林coding”。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-isc2MpCj-1661415056495)(image/image-20220816162254389.png)]

如图,慢启动阶段的拥塞窗口cwnd是指数级增长

当然,这个增长是有一个上限的,上限称为慢启动门限 ssthresh(slow start threshold)状态变量。一般情况下,ssthresh的大小是65535字节。

当拥塞窗口cwnd < ssthresh时,就是处于慢启动阶段;当拥塞窗口 >= ssthresh时,就是处于拥塞避免阶段。

拥塞避免

当进入拥塞避免阶段,拥塞窗口cwnd的增长就会稍微变得缓慢一点。增长规则是每收到一个ACK确认应答报文,cwnd 就会增加1/cwnd。

举个例子:假设现在发送方一次性发出去 8个数据段,理应来说将会收到8个ACK确认应答报文(但只会收到一个ACK确认应答报文,就是上文提交到的 自动重传+滑动窗口部分提及的),所以cwnd = cwnd + 8 * 1/8 = cwnd + 1。

下图所示,假设慢启动门限 ssthresh = 8。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0o7Ko3pA-1661415056496)(image/image-20220816163837779.png)]

所以拥塞避免阶段,就是从慢启动阶段的指数级增长变为了线性增长,增长速度变慢了。就这样一直增长下去,就会进去拥塞发送阶段。

拥塞发生

来到拥塞发生阶段,就说明已经有数据包丢失或者数据包延迟抵达。就会触发重传机制,这里的重传机制有两种:

  • 超时重传
  • 快速重传

当发生超时重传,就会使用拥塞发生算法。ssthresh和cwnd都会发生变化。

  • ssthresh = cwnd / 2
  • cwnd = 1

下图来自“小林coding”。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bcSdVlpl-1661415056497)(image/image-20220816165132504.png)]

如上图,cwnd就会重新从1开始,直接从拥塞避免阶段 -> 慢启动阶段。这种大起大落的情况,反应太过激烈,会造成网络卡顿。所以还有第2种拥塞发生情况,即快重传。

快重传

当接收方发现丢了其中某一个包,就会发送三次这丢失的这个包的ACK,于是发送端就会快速重传这个丢失的包,就不必等待超时重传。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iptlFJMy-1661415056498)(image/image-20220816165810788.png)]

这种情况的拥塞发送,ssthresh和cwnd的变化如下:

  • cwnd = cwnd / 2
  • ssthresh = cwnd

当使用快重传的拥塞发送,就会进入下一个阶段:快速恢复。

快速恢复

快速重传和快速恢复一般都是同时搭配使用的,快速恢复算法认为,还能收到3个重复的ACK报文时,至少说明此时的网络还不算太拥堵。在上文说过,进入快速恢复时,慢开始门限ssthresh拥塞窗口cwnd已经发生变化了。

  • cwnd = cwnd / 2
  • ssthresh = cwnd

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wlkYhPax-1661415056499)(image/image-20220824212536480.png)]

快速恢复的具体流程如下:

  • 拥塞窗口cwnd = ssthresh + 3.(+3的原因是已经确认收到那3个重复的ACK报文)
  • 重传丢失的数据包;
  • 如果此时还收到那个重复的ACK报文,那么cwnd += 1;
  • 如果收到新的ACK报文,那么cwnd = 第一步的慢启动门限ssthresh,原因是该ACK确认了新的数据,即该恢复过程已经结束,可以回到恢复之前的状态,也就是说可以再次进入拥塞避免状态。

好处就是,直接就进入了拥塞避免状态,不再是从慢启动状态开始

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7sQmarWX-1661415056500)(image/image-20220824212243076.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZSm5C0pI-1661415056500)(image/image-20220824212559605.png)]

连接管理

建立连接(3次握手)

TCP协议是面向连接的,所以在传输数据之前,首先需要建立连接。建立连接过程如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UYrWlot5-1661415056501)(image/image-20220824213604893.png)]

  • CLOSED:表示当前处于关闭状态。
  • LISTEN:表示服务器处于监听状态,随时准备和客户端建立连接。
  • SYN-SENT:表示客户端已经发送SYN报文,等待服务器返回第2次握手(SYN+ACK)的报文。
  • SYN-RCVD:表示服务器已经发送第2次握手的报文,等待客户端返回第3次握手(ACK)的报文。
  • ESTABLISHED:表示已经建立连接成功,可以相互进行通信。

过程

  1. 客户端首先发送一个SYN报文,所谓的SYN报文,指的就是TCP首部字段中的SYN标志=1。然后TCP首部字段的序号是系统随机生成的。这样的一个SYN报文就称为建立连接请求。
  2. 当服务器收到来自客户端的SYN报文,就知道客户端想跟我建立连接,服务器就会回应客户端“我同意跟你建立连接”(ACK=1),然后服务器也会向客户端发送SYN报文(SYN=1,seq=随机值)。原本是需要两次TCP报文,但是这两次可以合并成一个TCP报文。
  3. 此时客户端接收到来自服务器的SYN+ACK报文,就知道客户端上次发送的SYN报文他已经接收到了,此时服务器也想跟我建立连接,我就得回应服务器一个ACK报文,表示“客户端同意跟服务器建立连接”。

注意:这3次握手中,前2次握手是不包含任何应用数据的,这前2次握手只是单纯为了建立连接,且前2次握手的TCP首部的长度一般在32字节,这里面包含了缓存区窗口大小、MSS(Maximum Segment Size)、是否支持SACK、Window scale(窗口缩放系数)等等。但是在第3次握手时,是可以携带应用数据的,这也是面试常问的话题。

Window scale(窗口缩放系数):在TCP首部字段中,有窗口大小字段(16位),这个字段里面的数据并不是真实的缓存区窗口的大小,真实的缓冲区窗口大小 = 窗口大小字段值 * Window scale。

为什么是3次握手?为什么不是2次或者4次握手?

从3个方面说:

  • 3次握手才能避免重复历史连接的初始化(主要原因)
  • 3次握手才可以同步双方的初始序号
  • 3次握手才能避免资源浪费

情况一

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cBpCGHRv-1661415056502)(image/image-20220824221413168.png)]

3次握手的主要原因就是为防止旧的重复连接初始化造成混乱。就如上图,第1次SYN报文超时了,导致客户端发送了第2次SYN报文。此时应该以第2次SYN报文来建立连接。

  • 旧的SYN报文比新的SYN报文先达到服务器;
  • 此时服务器就会返回SYN+ACK报文给客户端;
  • 客户端收到后可以根据自己的上下文,判断出这是一个历史连接(序列号过去或超时),那么客户端就会发送RST报文,强制断开本次连接。

所以这第3次握手,有两种情况:如果返回的第2次握手是历史连接,就发送RST进行中止连接;如果返回的第2次握手不是历史连接,就返回ACK报文建立连接。

情况二

TCP 协议的通信双⽅, 都必须维护⼀个序列号, 序列号是可靠传输的⼀个关键因素,它的作⽤:

  • 接收⽅可以去除重复的数据;
  • 接收⽅可以根据数据包的序列号按序接收;
  • 可以标识发送出去的数据包中, 哪些是已经被对⽅收到的;

当客户端发送携带初始序列号的 SYN 报⽂的时候,需要服务端回⼀个 ACK 应答报⽂,表示客户端的 SYN 报⽂已被服务端成功接收,那当服务端发送初始序列号给客户端的时候,依然也要得到客户端的应答回应, 这样⼀来⼀回,才能确保双⽅的初始序列号能被可靠的同步 。

而两次握手,只能保证其中一方的初始序列号被接受,并不能保证另一方的初始序列号也能被接受。

情况三

如果只有2次握手,假设网络有点拥堵,导致客户端发送了多个SYN报文来建立连接,此时服务器就会返回ACK表示同意建立连接。且返回ACK后就直接进入ESTABLISHED状态;后续再次接到客户端发送的重复的SYN报文时,也是会进行建立连接的,此时就建立了多个冗余的TCP连接,造成资源浪费。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eHvHWVhc-1661415056502)(image/image-20220824224930828.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-80fzcONk-1661415056503)(image/image-20220824224949754.png)]

即两次握⼿会造成消息滞留情况下,服务器重复接受⽆⽤的连接请求 SYN 报⽂,⽽造成重复分配资源。

综上所诉,通过3次握手能防止历史连接的建立、减少双方不必要的资源开销、能帮助双方同步初始序列号。

释放连接(4次挥手)

双方都可以主动断开连接,断开连接后主机中的资源将会被释放。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xFDpRXo1-1661415056503)(image/image-20220825090441865.png)]

过程:

  1. 客户端想关闭连接,就发送了一个FIN报文,然后客户端就进入FIN-WaIT-1状态;
  2. 服务器收到来自客户端的FIN报文,就知道客户端想断开连接了,此时就回复一个ACK报文,表示同意断开连接,然后服务器就进入CLOSE-WAIT状态。此时只是客户端想断开连接,服务器还是可以向客户端发送数据。
  3. 当客户端接收到服务器的ACK报文后,就进入了FIN-WAIT-2状态。此时只是客户端不能发送数据,但还是能接收来自服务器的数据
  4. 待服务器将最后的数据发送完之后,也会发送FIN报文,表示想断开连接,然后进入LAST-ACK状态。
  5. 当客户端收到FIN报文后,就会直接返回ACK报文,表示同意断开连接,然后就直接进入TIME-WAIT状态。
  6. 此时客户端在等待2MSL后,就会自动进入CLOSE状态。
  7. 服务器在就收到最后一个ACK报文后,也会进入CLOSE状态。

注意:所谓的4次挥手,指的就是双方都会发送一个FIN、一个ACK。主动提起关闭连接的一方才有TIME-WAIT状态。

为什么挥手需要4次?不可以是3次吗?

答:假设客户端提起关闭连接,在前2次挥手(FIN+ACK)之后,只能说是客户端不再向服务器发送任何应用数据;但在服务器发送第2次挥手时,此时的服务器可能还有一些应用数据需要返回给客户端,所以导致这里的第2次挥手(ACK)和第3次挥手(FIN)不能合并在一起。所以一般情况下,第2次和第3次挥手是分开的,就成了4次挥手。

是有可能变成3次挥手的,只要在服务器发送第2次挥手时,服务器后续不会再发送任何应用数据,就有可能将第2次和第3次挥手合并在一起。


为什么TIME-WAIT等待的时间是2MSL?

答:MSL(Maximum Segment Lifetime)报文最大生存时间。它指的是任何报文在网络中存在的最长时间,超过这个时间的报文就会被丢弃。前面的文章提到过网络层的TTL(存活时间),这二者是不一样的。一个是在网络层,一个是在传输层。且MSL的单位是时间,TTL的单位是路由器数量。所以MSL应该要大于等于TTL消耗为0的时间,以确保报文已被自然消亡。

2倍的MSL的原因是:网络中的数据包进行传递时,来自发送方的数据,被接收方收到后会返回一个ACK,这样一去一来就是2倍的MSL。

设置这个等待时间的原因:在客户端发送最后一个ACK报文后,客户端是需要保证这个ACK能够到达服务器。如果在一定的时间内,服务器没有收到最后一个ACK报文,它会重发FIN报文来断开连接,而客户端在发送ACK报文后,需要做的就是等。在2MSL时间内,没有收到来自服务器的FIN报文,就说明发送的ACK报文已经到达了。也就是要保证被动关闭的一方能够正确地关闭连接。

在Linux系统中的2MSL默认是60秒,即一个MSL是30秒。也就是说Linux系统停留在TIME-WAIT的时间是固定的60秒。如果想更改这个值,那就需要改动Linux内核里面的参数,并重新编译Linux内核。


如果被动关闭的一方还没有收到最后一个ACK,但主动关闭的一方已经进入CLOSE状态,会发送什么?

答:这种情况下,被动关闭一方会发送多次FIN报文(第3次挥手),在进行多次尝试后,还没有结果,就会发送RST报文,强制断开连接。


如果已经建⽴了连接,但是客户端突然出现故障了怎么办?(长连接、短连接)

答:TCP连接中,有长连接和短连接的概念。所谓的短连接就是每当发送数据时,才会建立连接,数据发送完之后就会立刻断开连接;长连接则相反。

在长连接中,可能很长一段时间,双方都没有进行交互数据,此时并不知道这个TCP连接是否还存活(即有用)。TCP就有一个机制:保活机制

它定义了一个时间段,在这个时间段了,双方没有进行连接相关的活动,TCP保活机制就会每隔一段时间就发送一个探测报文(俗称心跳包),当另一方收到这个探测报文就会作出回应,表示这个TCP连接还是存活的。如果连续几个探测报文都没有响应,则认为这个TCP连接已经消亡,系统内核会将错误信息传递给上层应用程序。

在Linux内核中都有相应的参数来设置保活时间、探测报文次数、探测报文时间间隔:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bw0DkZuI-1661415056504)(image/image-20220825101020312.png)]

  • 7200的单位是秒,即表示保活时间是2个小时。在2个小时之内,没有进行任何连接相关的活动,就会触发保活机制。

  • 75的单位是秒,指的是每个75秒发送一个探测报文。

  • 9指的是一共会进行9次探测报文。


既然 IP 层会分⽚,为什么 TCP 层还需要 MSS 呢?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gYy5MQA7-1661415056504)(image/image-20220825153155317.png)]

在前面的数据链路层提到过MTU的概念,也在网络层说过IP分片的问题。

  • MTU(Maximum Transmission Unit)最大传输单元。这是在数据链路层的帧中的一个概念,指的是每一个帧的数据部分的长度不能超过MTU,在数据链路层中的以太网帧,MTU= 1500字节。
  • MSS(Maximum Segment Size)最大数据段大小。在传输层中,整个数据称为段。而这MSS指的是TCP报文中的数据部分长度不能超过MSS。

MSS是在TCP建立连接的时候,双方都会告诉对方自己的MSS是多大,一般都是1200~1400字节左右。

可能会有人疑惑,既然网络层也有分片功能,为啥传输层现在又有分片功能?

答:二者是有一定的目的的。在使用UDP协议时,它在传输层就不会进行分段,在网络层时,当数据部分太大时,才会进行分片。分片的过程:假设现在A数据包有4000字节,它在网络层分片,可能就是会分为3~4片左右;而分出来的片中,只有第一片有TCP首部,其余的片并没有TCP首部,而是只加了IP首部。当数据传递到对方的网络层时,才会合并数据,并传递到上一层传输层。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rpg5epx7-1661415056505)(image/image-20220825155412385.png)]

这看起来是没有什么问题。但是 如果这个UDP协议是自己更改为具有可靠传输功能的,那么当其中某一片数据丢包时,此时发送端就会超时重传,而重传数据就只能重传分片以前的整个数据包,此时就出现了传输的数据重复,浪费了带宽资源。

所以,才有了传输层就分段的功能,作用是在传输层分段,这样分出来的每一个段都是有TCP首部的,分出来的每一段的长度是小于MTU的,所以在网络层不会再分片。此时如果丢了其中一段,那么在重传时,就只传丢失的这一段即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gNpljJob-1661415056505)(image/image-20220825160323998.png)]

好啦,本期更新就到此结束啦。

以上内容部分参考“小林coding”和“小码哥教育”。


http://www.niftyadmin.cn/n/1036368.html

相关文章

Part 13:Cocos2d-x开发实战-Cocos2d-x中使用的数据容器类-关东升-专题视频课程

Part 13&#xff1a;Cocos2d-x开发实战-Cocos2d-x中使用的数据容器类—6104人已学习 课程介绍 介绍了Cocos2d-x中可以使用的数据容器类&#xff0c;还有熟悉Cocos2d-x中两大类——Ref和Value。后重点介绍了__Array、Vector、__Dictionary、Map、ValueVector、ValueMap和Valu…

ajax技术和跨域问题

今天我们来聊聊关于前端圈子的里的一个小技术&#xff0c;ajax技术和跨域问题。 ajax全称&#xff1a;Asynchronous Javascript And XML&#xff08;异步JavaScript和XML&#xff09;。 百度百科说的可能不是很好理解&#xff0c;举个例子&#xff0c;来描述这个ajax究竟在我们…

Part 12:Cocos2d-x开发实战-Cocos中粒子系统-关东升-专题视频课程

Part 12&#xff1a;Cocos2d-x开发实战-Cocos中粒子系统—3827人已学习 课程介绍 熟悉了粒子系统的基本概念。然后我们还介绍了内置粒子系统和自定义粒子系统。课程收益掌握Cocos2D-X开发讲师介绍关东升 更多讲师课程一个在IT领域摸爬滚打20多年的老程序员、软件架构师、培训…

5千字长文,深度总结HashMap底层实现面试题【收藏】

哈喽&#xff0c;大家好&#xff01;&#xff01;&#xff01;今天的主题&#xff1a;HashMap 反观整个Java的集合框架&#xff0c;我们讲了ArrayList、LinkedList、Stack、Queue、Deque、PriorityQueue等等集合&#xff0c;以及它们背后所对应的数据结构&#xff0c;今天我们来…

2019年京东面试题-洗咖啡杯问题【贪心和动态规划】

京东2019年面试题—冲咖啡和洗咖啡杯问题 题目描述&#xff1a; 首先&#xff0c;给你几个数据&#xff1a; 数组arr&#xff1a;表示几个咖啡机&#xff0c;这几个咖啡机生产一杯咖啡所需要的时间就是数组中的值&#xff0c;例如arr[2,3,7]就表示第一台咖啡机生产一杯咖啡需…

Part 11:Cocos2d-x开发实战-游戏音乐与音效-关东升-专题视频课程

Part 11&#xff1a;Cocos2d-x开发实战-游戏音乐与音效—5164人已学习 课程介绍 介绍了Cocos2d-x引擎在不同平台所支持的音频文件格式。我们还介绍了Cocos2d-x中音频引擎CocosDenshion。课程收益掌握Cocos2D-X开发讲师介绍关东升 更多讲师课程一个在IT领域摸爬滚打20多年的老…

Part 10:Cocos2d-x用户事件-关东升-专题视频课程

Part 10&#xff1a;Cocos2d-x用户事件—5448人已学习 课程介绍 了解Cocos2d-x的用户输入事件处理&#xff0c;这些事件包括&#xff1a;触摸事件、键盘事件、鼠标事件、加速度事件和自定义事件等。课程收益掌握Cocos2D-X开发讲师介绍关东升 更多讲师课程一个在IT领域摸爬滚…

截止目前为止,我遇到的最难的一道算法题:计算相邻两个数的最大差值

hello&#xff0c;今天给大家带来一道算法题。这道算法题&#xff0c;是我目前为止&#xff0c;见过最难的一道题。那么到底是怎样的一道算法题呢&#xff1f;如下&#xff1a; 题目&#xff1a;给定一个数组&#xff0c; 求如果排序之后&#xff0c; 相邻两数的最大差值。 要…