1 运输层
1.1 运输层的定义
运输层是 OSI 七层参考模型的第四层,主要功能为应用层提供通信服务,它即是面向通信的最高层,也是用户功能的最底层。
在计算机网络中,真正进行数据通信的是两个主机的进程,由于一个主机中有多个进程同时在通信。而运输层只有一个,故运输层需要有复用与分用的功能,复用指的是多个进程只使用一个运输层来传输数据,分用指的是运输层在收到数据后能够根据端口号准确地将相应的数据给相应的进程。
1.2 运输层与网络层的区别
- 网络层为不同主机提供通信服务,传输层为不同主机的不同进程提供通信服务。
- 网络层只对报文头部进行差错检测,传输层对整个报文进行差错检测。
- 网络层的数据单元为数据报,传输层的数据单元为报文段。
2 UDP 协议
2.1 UDP 协议简介
UDP,即 User Datagram Protocol,为用户数据报协议。它几乎没有做什么工作,除了复用/分用功能以及差错检测之外,它几乎没在网络层之上增加一些别的东西。
2.2 UDP 协议的特点
- 无连接
- 不可靠:尽力交付,并不保证每一个数据报都能送达。
- 面向报文:UDP 数据传输的单位是报文,而且不会对数据进行拆分和拼接。
- 不会进行拥塞控制:UDP 会以恒定的速率发送数据,不会考虑网络拥塞情况调整发送速率。这种方法在网络拥塞情况下可能会造成报文丢失,故 UDP 是不可靠的,但在一些允许报文丢失且对实时性要求很高的情况下(直播,语音通话),UDP 还是有价值的。
- 支持一对一、一对多、多对多、多对一通信
- 与 TCP 首部20字节起步相比,UDP 首部只有8字节,开销小
2.3 UDP 报文段结构
UDP 首部只有4个字段,源端口号,目的端口号,长度和校验和,每个字段由两个字节组成。
- 源端口号:在返回信息的时候使用
- 目的端口号:将数据交给运行在目的端系统中的相应进程
- 长度:包括首部在内的 UDP 报文段长度,以字节为单位
- 校验和:检查报文段中是否存在差错
3 TCP 协议
3.1 TCP 协议简介
TCP,即 Transmission Control Protocol,传输控制协议。
3.2 TCP 协议的特点
- 面向连接
- 提供可靠交付服务:TCP 发送的数据无重复、无丢失、无错误、与发送端顺序一致
- 面向字节流:TCP 以字节为单位,在传输过程中为了方便传输,会将数据划分成一个个数据报,但接收端最终接受到的数据与发送端的数据一模一样
- 全双工通信:TCP 的两端既可以作为发送端,也可以作为接收端
- 与 UDP 可以任意方式通信不同,TCP 只支持一对一通信
- 一条 TCP 连接的两端是两个套接字,而套接字就是 IP 地址 + 端口号
3.3 TCP 报文段结构
TCP 首部长度有20字节的固定部分,选项部分长度不定,但最多40字节,因此 TCP 头部在20-60字节之间。
- 源端口号:在返回信息的时候使用
- 目的端口号:将数据交给运行在目的端系统中的相应进程
- 序列号码:TCP 数据报数据部分的第一个字节的序号。由于 TCP 是面向字节的,它会对发送的每一个字节进行编号,而且不同数据报之间是连续编号的。
- 确认号码:当前主机作为接收端时,期望接收的下一个字节的编号是多少。通俗的说,确认号码 = 当前主机已经正确接收的最后一个字节序号 + 1。
- 报文长度:数据报头部的长度。
- 标识符:TCP 有6种标识符,用于表示 TCP 报文的性质。它们只能为0或1。
6.1 URG:置1时表示本数据报的数据部分包含紧急信息,此时紧急指针有效。紧急数据一定位于当前数据包数据部分的最前面,紧急指针标明了紧急数据的尾部。
6.2 ACK:置1后确认号字段才有效。TCP 规定,在连接建立后传送的所有报文段都必须把 ACK 置1。
6.3 PSH:置1表示接收方立即将数据交付给应用程序,而不会等到缓冲区满后再提交,用于降低命令的响应时间。
6.4 RST:置1时表示当前 TCP 连接出现严重问题,必须要释放重连。
6.5 SYN:在建立连接时使用,若 SYN=1,ACK=0,表示当前报文段是一个连接请求报文。 若 SYN=1,ACK=1,表示当前报文段是一个同意建立连接的应答报文。
6.6 FIN:置1时表示此报文段是一个释放连接的请求报文。 - 接收窗口大小:表示当前接收方的接收窗口的剩余容量,用于实现 TCP 的流量控制。
- 检验和:接收端检验整个数据包在传输过程中是否出错。
- 紧急指针:标识紧急数据的尾部。
- 选项:可选,长度可变,最长40字节。
3.4 TCP 的三次握手与四次挥手
3.4.1 三次握手
- 第一次握手:客户端将 SYN 置为1,ACK 置为0(表示该报文段为连接请求报文),随机产生一个值 seq=J(J 为本次 TCP 通信的字节流的初始序号),并将该数据包发送给服务器,客户端进入SYN_SENT 状态,等待服务器确认。
- 第二次握手:服务器收到数据包后由标志位 SYN=1 知道客户端请求建立连接,服务器将标志位 SYN 和 ACK 都置为1(该报文段为同意连接的应答报文),ack=J+1(服务端希望下一个数据报发送序号从 J+1 开始的字节),随机产生一个值 seq=K(服务端作为发送者时,发送字节流的初始序号),并将该数据包发送给客户端以确认连接请求,服务器进入 SYN_RCVD 状态。
- 第三次握手:客户端收到确认后,检查数据是否正确,如果正确则将标志位 ACK 置为1,ack=K+1,seq=J+1,并将该数据包发送给服务器,服务器检查数据是否正确,如果正确则连接建立成功,客户端和服务器进入 ESTABLISHED 状态,完成三次握手,随后客户端与服务器之间可以开始传输数据了。
通俗的讲,三次握手可以简化为:
- 我要和你建立链接
- 你真的要和我建立链接么
- 我真的要和你建立链接,成功
3.4.2 四次挥手
- 第一次挥手:客户端发送 FIN=1(该报文段是一个连接释放请求),seq=u (u-1是客户端向服务器发送的最后一个字节的序号)的报文,用来关闭客户端到服务器的数据传送,客户端进入 FIN_WAIT_1 状态。
- 第二次挥手:服务器收到请求后,发送 ACK=1,seq=v(v-1 是服务器向客户端发送的最后一个字节的序号),ack=u+1 (希望收到从第 u+1 个字节开始的报文段,并且已经成功接收了前 u 个字节)的报文给客户端,服务器进入 CLOSE_WAIT 状态,客户端收到该应答后进入 FIN-WAIT-2 状态,等待服务器发送连接释放请求。此时 TCP 链接处于半关闭状态,即客户端已经没有要发送的数据了,但服务端若发送数据,则客户端仍要接收。
- 第三次挥手:当服务器向客户端发完所有数据后,向客户端发送连接释放请求。服务器发送 FIN=1,ACK=1,seq=w,ack=u+1 的报文,用来关闭服务器到客户端的数据传送,服务器进入 LAST_ACK 状态。
- 第四次挥手:客户端收到请求后,发送一个确认应答给服务器,客户端进入 TIME_WAIT 状态,该状态会持续 2MSL 时间,若该时间段内没有服务器的重发请求的话,就进入 CLOSED 状态。当服务器收到确认应答后,会进入 CLOSED 状态,完成四次挥手。
通俗的讲,四次挥手可以简化为:
- 我要和你断开链接
- 好的,断吧
- 我也要和你断开链接
- 好的,断吧
3.4.3 为什么 TCP 链接需要三次握手,两次不可以么,为什么?
这是为了防止已失效的链接请求报文突然又传送到了服务端,因而产生错误。
![](/qrcode.jpg)
如果客户端发出的连接请求报文并未丢失,而是在某个网络节点长时间滞留了,以致延误到链接释放以后的某个时间才到达服务器。这是,服务器误以为这是客户端发出的一个新的链接请求,于是就向客户端发送确认数据包,同意建立链接。若不采用“三次握手”,那么只要服务器发出确认数据包,新的链接就建立了。由于客户端此时并未发出建立链接的请求,所以其不会理睬服务器的确认,也不与服务器通信;而这时服务器一直在等待客户端的请求,这样服务器就白白浪费了一定的资源。若采用“三次握手”,在这种情况下,由于服务器端没有收到来自客户端的确认,则就会知道客户端并没有要求建立请求,就不会建立链接。
3.4.4 为什么客户端要先进入 TIME-WAIT 状态,等待 2MSL 时间后才进入 CLOSED 状态?
为了保证服务器能收到客户端的确认应答。 若客户端发完确认应答后直接进入 CLOSED 状态,那么如果该应答丢失,服务器等待超时后就会重新发送连接释放请求,但此时客户端已经关闭了,不会作出任何响应,因此服务器永远无法正常关闭。
3.5 TCP 的可靠传输
TCP 会具有可靠性的,它向应用层提供的数据是 无差错的、有序的、无丢失的,即 TCP 最终递交给应用层的数据和发送者发送的数据是一模一样的。
TCP 采用了流量控制、拥塞控制、连续 ARQ 等技术来保证它的可靠性。
3.5.1 连续 ARQ 协议
连续 ARQ 协议,又被称为滑动窗口协议。发送者拥有一个发送窗口,可以在没有得到应答的情况下连续发送窗口中的分组。
3.5.1.1 累计确认
在连续 ARQ 协议中,接收者也有一个接收窗口。为了节省流量,它并不需要每收到一个分组就返回一个应答,可以连续收到分组之后统一返回一个应答。
TCP 头部的 ack 字段用于累计确认,它表示已经确认的字节序号+1,也表示期望发送者发送的下一个分组的起始字节号。
3.5.1.2 发送窗口与接收窗口
我们先了解一下以下前提:
- TCP 协议的两端分别为发送者和接收者,它们分别维护着一个独立的发送缓冲区和接收缓冲区。
- 所谓的发送窗口是发送缓存中的一部分,是可以被 TCP 协议发送的那部分,其实应用层需要发送的所有数据都被放进了发送者的发送缓冲区。
- 发送窗口包含四种数据:已发送并收到确认的数据(不在发送窗口之内)、已发送但未收到确认的数据(位于发送窗口之中)、允许发送但尚未发送的数据以及发送窗口外发送缓冲区内暂时不允许发送的数据。
我们接下来看看滑动窗口协议是如何执行的。
- TCP 在建立连接的初始,接收者会告诉发送者自己的接收窗口大小,比如为20,这将决定发送窗口大小(事实上发送窗口的大小会根据接收窗口的剩余大小与当前网络拥塞情况发生变化)
- 此时我们假设发送窗口为字节31-50
- 发送者在发送11个字节后,发送窗口位置不变,接收者接收到了乱序的数据分组
- 只有当发送者成功发送了数据,即发送的数据得到了接收者的确认之后,才会移动滑动窗口离开已发送的数据;接收者收到的字节会存入接收窗口,并会对已经正确接收的有序字节进行累计确认,发送完确认应答后,接收窗口就可以向前移动指定字节。如果某些字节并未按序收到,接收者只会确认最后一个有序的字节,从而乱序的字节就会被重新发送。
3.5.1.3 注意点
- 同一时刻发送窗口的大小并不一定和接收窗口一样大。
- TCP 标准并未规定未按序到达的字节的处理方式。但 TCP 一般都会缓存这些字节,等缺少的字节到达后再交给应用层处理。这比直接丢弃乱序的字节要节约带宽。
- TCP 标准规定接收方必须要有累计确认功能。接收方可以对多个 TCP 报文段同时确认,但不能拖太长时间,一般是0.5S以内。
3.5.2 流量控制
3.5.2.1 什么是流量控制?
如果发送者发送过快,接收者来不及接收,那么就会有分组丢失。为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制。流量控制的根本目的是防止分组丢失,它是构成 TCP 可靠性的一方面。
3.5.2.2 如何实现流量控制?
通过滑动窗口协议实现流量控制,滑动窗口协议既保证了分组无差错、有序接收,也实现了流量控制。
3.5.2.3 流量控制引发的死锁以及解决方案
当发送者收到了一个窗口为0的应答,发送者便停止发送,等待接收者的下一个应答。但是如果这个窗口不为0的应答在传输过程丢失,发送者一直等待下去,而接收者以为发送者已经收到该应答,等待接收新数据,这样双方就相互等待,从而产生死锁。
为了避免流量控制引发的死锁,TCP 使用了持续计时器。每当发送者收到一个零窗口的应答后就启动该计时器。时间一到便主动发送报文询问接收者的窗口大小。若接收者仍然返回零窗口,则重置该计时器继续等待;若窗口不为0,则表示应答报文丢失了,此时重置发送窗口后开始发送,这样就避免了死锁的产生。
3.5.3 拥塞控制
3.5.3.1 为什么要使用拥塞控制?
为了缓解网络压力以及保证分组按时到达。
3.5.3.2 拥塞控制和流量控制的区别?
- 拥塞控制:拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况
- 流量控制:流量控制是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收
3.5.3.3 拥塞控制的方法
- 慢启动:不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小,其增长幅度为指数级别。(若发送窗口 < 慢开始门限,则使用慢启动算法,若发送窗口 > 慢开始门限:使用拥塞避免算法)
- 拥塞避免:拥塞避免算法让拥塞窗口缓慢增长,即每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加1,而不是加倍,这样拥塞窗口按线性规律缓慢增长。无论现在使用的是慢启动算法还是拥塞避算法,当发送方出现超时重传时,表明网络出现拥塞,此时将慢开始门限设为当前发送窗口的一半,然后将发送窗口设为1,最后启用慢启动算法。
- 快重传:慢开始算法和拥塞避免算法能保证网络出现拥塞时进行相应的处理,而快重传和快恢复是一种拥塞预防的方式。此时网络可能尚未出现拥塞,但已经有拥塞的征兆,因此得作出一些预防措施。快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。
- 快恢复:快重传配合使用的还有快恢复算法,当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把 ssthresh 门限减半,但是接下去并不执行慢开始算法:因为如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将 cwnd 设置为 ssthresh 的大小,然后执行拥塞避免算法。
3.6 TCP 协议如何来保证传输的可靠性?
- 数据包校验:目的是检测数据在传输过程中的任何变化,若校验出包有错,则丢弃报文段并且不给出响应,这时 TCP 发送数据端超时后会重发数据;
- 对失序数据包重排序:既然 TCP 报文段作为 IP 数据报来传输,而 IP 数据报的到达可能会失序,因此 TCP 报文段的到达也可能会失序。TCP 将对失序数据进行重新排序,然后才交给应用层;
- 丢弃重复数据:对于重复数据,能够丢弃重复数据;
- 应答机制:当 TCP 收到发自 TCP 连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒;
- 超时重发:当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段;
- 流量控制:TCP 连接的每一方都有固定大小的缓冲空间。TCP 的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。TCP 使用的流量控制协议是可变大小的滑动窗口协议。
- 拥塞控制: 当网络拥塞时,减少数据的发送。