最全的TCP/UDP 协议知识点整理

关于计算机网络的基础知识,我前面写的两篇文章是入门文章,可以帮你构建一个计算机网络的基础架构,有了这个基础架构,后面的学习会很简单。下面是两篇文章的连接~~

计算机网络体系结构与参考模型(1)
计算机网络体系结构及参考模型(2)

1.传输层中的TCP

  传输层中一定要知道端口号的概念。
  数据链路和 IP 中的地址,分别指的是 MAC 地址和 IP 地址。前者用来识别同一链路中不同的计算机,后者用来识别 TCP/IP 网络中互连的主机和路由器。在传输层也有这种类似于地址的概念,那就是端口号。端口号用来识别同一台计算机中进行通信的不同应用程序。因此,它也被称为程序地址。

 1.1 TCP(Transmission Control Protocol)
  • TCP提供一种面向连接的、可靠的字节流服务。
  • 在一个TCP连接中,仅有两方进行彼此通信。广播和多播不能用于TCP
  • TCP使用校验和,确认和重传机制来保证可靠传输
  • TCP给数据分节进行排序,并使用累计确认保证数据的顺序不变和非重复
  • TCP使用滑动窗口机制来实现流量控制,通过动态改变窗口的大小进行拥塞控制
  • TCP提供全双工通信。(发送缓存和接收缓存)

注意:TCP 并不能保证数据一定会被对方接收到,因为这是不可能的。TCP 能够做到的是,如果有可能,就把数据递送到接收方,否则就(通过放弃重传并且中断连接这一手段)通知用户。因此准确说 TCP 也不是 100% 可靠的协议,它所能提供的是数据的可靠递送或故障的可靠通知。

 1.2 TCP数据报文格式

在这里插入图片描述
比较重要的几个点,都是三次握手/四次挥手中会用到的

  • 32位序号(Sequence Number):它表示本报文段所发送数据的第一个字节的序号。当某个主机开启一个TCP会话时,他的初始序列号(Seq)是随机的,可能是0和4,294,967,295之间的任意值,这个序号的范围是0 — 2^32−1之间,而且序号的生成也是随机的,通常是一个很大的数值,也就是说每个tcp连接使用的序号也是不一样的。在 TCP 连接中,所传送的字节流的每一个字节都会按顺序编号。当SYN标记不为1时,这是当前数据分段第一个字母的序列号;如果SYN的值是1时,这个字段的值就是初始序列值 ——initial sequence number(ISN),用于对序列号进行同步。这时,第一个字节的序列号比这个字段的值大1,也就是ISN加1。
  • 32位确认序号(ACK Number): ACK flag 置 1 时才有效,期望收到对方下一报文段的第一个数据字节的序号。若确认号为N,则证明到序号N-1为止的所有数据都已正确接收。
  • 4位首部长度:以32位字为单位,作为一个4位的字段,TCP被现实为只能带60字节的头部。不带选项(最大段大小、时间戳、窗口缩放等),大小是20字节。
  • 6个标志位(新的TCP理解中有8个):
    (1)CWR:拥塞窗口减(发送方降低它的发送速率)
    (2)ECE:ECN回显(发送方接收到一个更早的拥塞通告)
    (3)URG(Urgent):表示本报文段中发送的数据是否包含紧急数据。URG=1 时表示有紧急数据,很少被使用
    (4)ACK:表示前面的确认号字段是否有效。ACK=1 时表示有效,只有当 ACK=1 时,前面的确认号字段才有效,连接建立后一般都是启用状态
    (5)PSH(Push):告诉对方收到该报文段后是否立即把数据推送给上层。如果值为 1,表示应当立即把数据提交给上层,而不是缓存起来
    (6)RST:表示是否重置连接。如果 RST=1,说明 TCP 连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接
    (7)SYN:在建立连接时使用,用来同步序号。当 SYN=1,ACK=0 时,表示这是一个请求建立连接的报文段;当 SYN=1,ACK=1 时,表示对方同意建立连接。SYN=1 时,说明这是一个请求建立连接或同意建立连接的报文。只有在前两次握手中 SYN 才为 1。
    (8)FIN:FIN=1,标记该报文段的发送方已经结束向对方发送数据,希望断开连接
  • 16位窗口大小:它表示从 Ack Number 开始还可以接收多少字节的数据量,也表示当前接收端的接收窗口还有多少剩余空间。窗口大小是字节数,这是一个十六位的字段,限制了窗口大小到65536个字节,从而限制了TCP的吞吐量性能。当然,可通过窗口缩放选项来对这个值进行缩放
  • 16位校验位:它用于确认传输的数据是否有损坏。发送端基于数据内容校验生成一个数值,接收端根据接收的数据校验生成一个值。两个值必须相同,才能证明数据是有效的。如果两个值不同,则丢掉这个数据包。Checksum 是根据伪头 + TCP 头 + TCP 数据三部分进行计算的。
  • 紧急指针(Urgent Pointer):仅当前面的 URG 控制位为 1 时才有意义。它指出本数据段中为紧急数据的字节数,占 16 位。当所有紧急数据处理完后,TCP 就会告诉应用程序恢复到正常操作。即使当前窗口大小为 0,也是可以发送紧急数据的,因为紧急数据无须缓存。
 1.3. 三次握手

  所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。
  三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 时。将触发三次握手。

  • 第一次握手(SYN=1,ACK=0, seq=J)
    客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号 J(随机的),保存在包头的序列号(Sequence Number)字段里。发送完毕后,客户端进入 SYN_SEND 状态。
  • 第二次握手(SYN=1,ACK=1,seq=K,ack=J+1)
    服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己序列号K(随机的),放到 Sequence Number中,同时将确认序号(Acknowledgement Number)设置为客户的 ISN(初始序号) 加1,即J+1。 发送完毕后,服务器端进入 SYN_RCVD 状态。
  • 第三次握手(SYN=0,ACK=1,seq=J+1,ack=K+1)
    客户端再次发送确认包(ACK),SYN 标志位为0ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手结束。

三次握手的过程的示意图如下:

在这里插入图片描述

 1.4 数据传输

  TCP报文送达确认ACK机制。由于通信过程的不可靠性,传输的数据不可避免的会出现丢失、延迟、错误、重复等各种状况,TCP协议为解决这些问题设计了一系列机制。这个机制的核心,就是发送方向接收方发送数据后,接收方要向发送方发送ACK(回执)。如果发送方没接收到正确的ACK,就会重新发送数据直到接收到ACK为止。比如:发送方发送的数据序号是seq,那么接收方会发送seq + 1作为ACK,这样发送方就知道接下来要发送序号为seq + 1的数据给接收方了。

在这里插入图片描述
  接收方在接收到数据后,不是立即会给发送方发送ACK的。这可能由以下原因导致:

  1. 收到数据包的序号前面还有需要接收的数据包。因为发送方发送数据时,并不是需要等上次发送数据被ack就可以继续发送TCP包,而这些TCP数据包到达的顺序是不保证的,这样接收方可能先接收到后发送的TCP包(注意提交给应用层时是保证顺序的)。
  2. 为了降低网络流量,ACK有延迟确认机制。
  3. ACK的值到达最大值后,又会从0开始。

  接收方在收到数据后,并不会立即回复ACK,而是延迟一定时间。一般ACK延迟发送的时间为200ms,但这个200ms并非收到数据后需要延迟的时间。系统有一个固定的定时器每隔200ms会来检查是否需要发送ACK包。这样做有两个目的。

  • 这样做的目的是ACK是可以合并的,也就是指如果连续收到两个TCP包,并不一定需要ACK两次,只要回复最终的ACK就可以了,可以降低网络流量。
  • 如果接收方有数据要发送,那么就会在发送数据的TCP数据包里,带上ACK信息。这样做,可以避免大量的ACK以一个单独的TCP包发送,减少了网络流量。

  一些情况的处理:

  • 数据丢失或延迟:发送方发送数据seq时会起一个定时器,如果在指定时间内没有接收到ack = seq + 1,就把数据seq再发一次。
  • 数据错:每一个TCP数据都会带着数据的校验和。接收方收到数据seq + 3以后会先对校验和进行验证。如果结果不对,则发送ACK seq + 3,让发送方重新发送数据。
  • 数据重复:接收方直接丢弃重复的数据即可。

  TCP协议应当保证数据报按序到达接收方。如果接收方收到的数据报文没有错误,只是未按序号,这种现象如何处理呢?TCP协议本身没有规定,而是由TCP协议的实现者自己去确定。通常有两种方法进行处理:一是对没有按序号到达的报文直接丢弃,二是将未按序号到达的数据包先放于缓冲区内,等待它前面的序号包到达后,再将它交给应用进程。后一种方法将会提高系统的效率。例如,发送方连续发送了每个报文中100个字节的TCP数据报,其序号分别是1,101,201,…,701。假如其它7个数据报都收到了,而201这个数据报没有收到,则接收端应当对1和101这两个数据报进行确认,并将数据递交给相关的应用进程,301至701这5个数据报则应当放于缓冲区,等到201这个数据报到达后,然后按序将201至701这些数据报递交给相关应用进程,并对701数据报进行确认,确保了应用进程级的TCP数据的按序到达。

 1.5 四次挥手
  • 第一次挥手(FIN=1,ACK=1,seq=x,ack=y)
    假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。发送完毕后,客户端进入 FIN_WAIT_1 状态。
  • 第二次挥手(FIN=0,ACK=1,seq=y,ack=x+1)
    服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。
  • 第三次挥手(FIN=1,ACK=1,seq=p,ack=x+1)服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。(这里要注意,当第二次挥手完成后,服务端有可能因为之前的数据没有发送完毕,可能会接着发送数据,直到数据发送完毕才会进行第三次握手
  • 第四次挥手(FIN=0,ACK=1,seq=x+1,ack=p+1)
    客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。
    在这里插入图片描述

 1.6 注意点

  关于seq的值,在三次挥手结束后,进行第一次传输时,seq的值不会变;开始四次挥手,第一次的挥手的seq的值不会变。

2. TCP是如何保证可靠传输的

  1. 确认和重传:接收方收到报文就会确认,发送方发送一段时间后没有收到确认就重传。
  2. 数据校验
  3. 数据合理分片和排序
  4. 流量控制:当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。
  5. 拥塞控制:当网络拥塞时,减少数据的发送。

下面就来分别讲讲这些机制的具体过程。

 2.1 滑动窗口

  为什么要使用滑动窗口呢?因为发送端希望在收到确认前,继续发送其它报文段。比如说在收到0号报文的确认前还发出了1-3号的报文,这样提高了信道的利用率。但可以想想,0-4发出去后可能要重传,所以需要一个缓冲区维护这些报文,所以就有了窗口。

接收窗口
在这里插入图片描述

  • “接收窗口”大小取决于应用、系统、硬件的限制。图中,接收窗口是31~50,大小为20。
  • 在接收窗口中,黑色的表示已收到的数据,白色的表示未收到的数据。
  • 当收到窗口左边的数据,如27,则丢弃,因为这部分已经交付给主机;
  • 当收到窗口右边的数据,如52,则丢弃,因为还没轮到它;
  • 当收到已收到的窗口中的数据,如32,丢弃;
  • 当收到未收到的窗口中的数据,如35,缓存在窗口中。

发送窗口:
在这里插入图片描述

  • 发送窗口的大小swnd=min(rwnd,cwnd)。rwnd是接收窗口大小,cwnd用于拥塞控制。
  • 图中分为四个区段,其中P1到P3是发送窗口。
 2.2 重传与确认

  什么时候发确认:这是一个复杂的策略(这里只是讲一下概念,具体的有兴趣可以自己搜索)。我们这里先简单地认为每收到一个报文就发一个确认。

累计确认
情况1:发送ack=31(为什么这个也要发,这个确认可以用于后面的拥塞控制)在这里插入图片描述
情况2:发送ack=34,并把接收窗口左边缘设置成34,右边缘设置成53
在这里插入图片描述
  累计确认的好处:情况1中ack=31比描述收到32和33简单;坏处:可能要重传已经接收的数据。

发送方收到确认时怎么处理
在这里插入图片描述
情况1:收到ack=31,什么都不做,或者说继续发送可用窗口中的内容,如42~50

情况2:收到ack=34,发送窗口窗口的左边缘设置成34,右边缘设置成53

  什么时候重传:因为每个报文都有超时计数器,超时才重传。超时重传时间的选择也是一个策略。包括重传的方式的选择也是一个策略(包括选择性重传、拉回重传等)。

  • tcp缓存和窗口的关系:窗口是缓存的一部分。
  • 发送缓存=发送窗口+ P3右边的一部分。
  • 接收缓存=接收窗口+部分已确认但主机还没处理完的数据。
 2.3 流量控制

  TCP的滑动窗口是动态的,我们可以想象成小学常见的一个数学题,一个水池,体积V,每小时进水量V1,出水量V2。当水池满了就不允许再注入了,如果有个液压系统控制水池大小,那么就可以控制水的注入速率和量。这样的水池就类似TCP的窗口。应用根据自身的处理能力变化,通过本端TCP接收窗口大小控制来对对对端的发送窗口流量限制。

  应用程序在需要(如内存不足)时,通过API通知TCP协议栈缩小TCP的接收窗口。然后TCP协议栈在下个段发送时包含新的窗口大小通知给对端,对端按通知的窗口来改变发送窗口,以此达到减缓发送速率的目的。

 2.3 拥塞控制

  拥塞控制:拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况;常用的方法就是:

  • 慢开始、拥塞避免
  • 快重传、快恢复。

(1)慢开始算法:
  发送方维持一个叫做拥塞窗口cwnd(congestion window)的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口,另外考虑到接受方的接收能力,发送窗口可能小于拥塞窗口。

  慢开始算法的思路就是,不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小。
  一个传输轮次所经历的时间其实就是往返时间RTT,而且没经过一个传输轮次(transmission round),拥塞窗口cwnd就加倍

  为了防止cwnd增长过大引起网络拥塞,还需设置一个慢开始门限ssthresh状态变量。ssthresh的用法如下:
当cwnd<ssthresh时,使用慢开始算法。
当cwnd>ssthresh时,改用拥塞避免算法。
当cwnd=ssthresh时,慢开始与拥塞避免算法

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

  无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有按时收到确认,虽然没有收到确认可能是其他原因的分组丢失,但是因为无法判定,所以都当做拥塞来处理),就把慢开始门限ssthresh设置为出现拥塞时的发送窗口大小的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。
在这里插入图片描述
“乘法减小”指的是无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞,就把慢开始门限ssthresh设置为出现拥塞时的发送窗口大小的一半,并执行慢开始算法,所以当网络频繁出现拥塞时,ssthresh下降的很快,以大大减少注入到网络中的分组数。“加法增大”是指执行拥塞避免算法后,使拥塞窗口缓慢增大,以防止过早出现拥塞。常合起来称为AIMD算法。

注意:“拥塞避免”并非完全能够避免了阻塞,而是使网络比较不容易出现拥塞。

(3)快重传算法
  快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方,可提高网络吞吐量约20%)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。如下图:
在这里插入图片描述
(4)恢复算法
  快重传配合使用的还有快恢复算法,有以下两个要点:

当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半(为了预防网络发生拥塞)。但是接下去并不执行慢开始算法
考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh减半后的值,然后执行拥塞避免算法,使cwnd缓慢增大。如下图:TCP Reno版本是目前使用最广泛的版本。
在这里插入图片描述
注意:在采用快恢复算法时,慢开始算法只是在TCP连接建立时和网络出现超时时才使用

3. 传输层中的UDP

在这里插入图片描述
16位UDP长度指:指首部字段+数据字段的长度

  • UDP是一个非连接的协议,传输数据之前源端和终端不建立连接, 当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、 计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
  • 由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等, 因此一台服务机可同时向多个客户机传输相同的消息,并且低延时。
  • UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。
  • 吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、 源端和终端主机性能的限制。
  • UDP使用尽最大努力交付,即不保证可靠交付, 因此主机不需要维持复杂的链接状态表(这里面有许多参数)。
  • UDP是面向报文的。发送方的UDP对应用程序交下来的报文, 在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。

4.TCP与UDP的对比总结

UDPTCP
无连接,减少开销和时延面向连接
支持一对一、一对多、多对一 、多对多的交互通信每一条TCP连接只能有两个端点EP,只能是一对一通信
对应用层交付的报文添加首部后,直接打包 (面向报文)面向字节流
尽最大努力交付,也就是不可靠;不使用流量控制和拥塞控制可靠传输,使用流量控制和拥塞控制
首部开销小,仅8字节首部最小20字节,最大60字节

  TCP一般用于文件传输(FTP、HTTP对数据准确性要求高,速度可以相对慢),发送或接收邮件(SMTP,对数据准确性要求高),远程登录(对数据准确性有一点高要求,有连接概念)

  UDP适用于实时应用。用于即时通信(QQ、微信等对数据准确性和丢包要求比较低,但速度必须快),在线视频(保证视频连续,偶尔花了一个图像帧,人们还是能接受的),网络语音电话(需要高速发送,偶尔断音或串音也没问题)

5. 总结

  文章总结了常见的UDP/TCP的面试问题,都是一些概念性的东西。TCP协议本身也会有不足,例如:粘包和拆包现象。这因为这些不足,所以针对性的在TCP协议之上发展出了其他的一些专用协议。
  了解TCP/UDP协议,要从底层开始了解,对于许多协议来说,TCP/UDP是其基础,所以学好TCP协议对很多其他协议很有帮助。





参考文章:

https://zhuanlan.zhihu.com/p/37379780
https://blog.csdn.net/wuzhiwei549/article/details/105965493
  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值