一、网络模型
1.七层模型
网络七层由下往上分别为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
2.五层模型
二、TCP
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
1.TCP建立连接
三次握手:为了对每次发送的数据量进行跟踪与协商,确保数据段的发送和接收同步,根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系,并建立虚连接。
第一次握手:客户端发送建立TCP连接的请求报文,其中报文中包含seq序列号,是由发送端随机生成的,并且将报文中的SYN字段置为1,表示需要建立TCP连接。(SYN=1,seq=x,x为随机生成数值);
第二次握手:服务端回复客户端发送的TCP连接请求报文,其中包含seq序列号,是由回复端随机生成的,并且将SYN置为1,而且会产生ACK字段,ACK字段数值是在客户端发送过来的序列号seq的基础上加1进行回复,以便客户端收到信息时,知晓自己的TCP建立请求已得到验证。(SYN=1,ACK=x+1,seq=y,y为随机生成数值)这里的ack加1可以理解为是确认和谁建立连接;
第三次握手:客户端收到服务端发送的TCP建立验证请求后,会使自己的序列号加1表示,并且再次回复ACK验证请求,在服务端发过来的seq上加1进行回复。(SYN=1,ACK=y+1,seq=x+1)。
2.断开连接
由于 TCP 连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
第一次挥手:客户端发送断开TCP连接请求的报文,其中报文中包含seq序列号,是由发送端随机生成的,并且还将报文中的FIN字段置为1,表示需要断开TCP连接。(FIN=1,seq=x,x由客户端随机生成);
第二次挥手:服务端会回复客户端发送的TCP断开请求报文,其包含seq序列号,是由回复端随机生成的,而且会产生ACK字段,ACK字段数值是在客户端发过来的seq序列号基础上加1进行回复,以便客户端收到信息时,知晓自己的TCP断开请求已经得到验证。(FIN=1,ACK=x+1,seq=y,y由服务端随机生成);
第三次挥手:服务端在回复完客户端的TCP断开请求后,不会马上进行TCP连接的断开,服务端会先确保断开前,所有传输到A的数据是否已经传输完毕,一旦确认传输数据完毕,就会将回复报文的FIN字段置1,并且产生随机seq序列号。(FIN=1,ACK=x+1,seq=z,z由服务端随机生成);
第四次挥手:客户端收到服务端的TCP断开请求后,会回复服务端的断开请求,包含随机生成的seq字段和ACK字段,ACK字段会在服务端的TCP断开请求的seq基础上加1,从而完成服务端请求的验证回复。(FIN=1,ACK=z+1,seq=h,h为客户端随机生成)
至此TCP断开的4次挥手过程完毕。
三、UDP
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议。
UDP是一个无连接协议,传输数据之前源端和终端不建立连接。由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。
UDP协议与TCP协议一样用于处理数据包,在OSI模型中,两者都位于传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。
当强调传输性能而不是传输的完整性时,如:音频和多媒体应用,UDP是最好的选择。在数据传输时间很短,以至于此前的连接过程成为整个流量主体的情况下,UDP也是一个好的选择。
1.报文格式
UDP报头由4个域组成,其中每个域各占用2个字节,具体包括源端口号、目标端口号、数据包长度、校验值。
端口
UDP协议使用端口号为不同的应用保留其各自的数据传输通道。UDP和TCP协议正是采用这一机制实现对同一时刻内多项应用同时发送和接收数据的支持。UDP端口号指定有两种方式:由管理机构指定端口和动态绑定的方式。
长度
数据报的长度是指包括报头和数据部分在内的总字节数。因为报头的长度是固定的,所以该域主要被用来计算可变长度的数据部分(又称为数据负载)。
校验值
UDP协议使用报头中的校验值来保证数据的安全。校验值首先在数据发送方通过特殊的算法计算得出,在传递到接收方之后,还需要再重新计算。如果某个数据报在传输过程中被第三方篡改或者由于线路噪音等原因受到损坏,发送和接收方的校验计算值将不会相符,由此UDP协议可以检测是否出错。这与TCP协议是不同的,后者要求必须具有校验值。
四、TCP、UDP对比
信息的可靠传递方面不同
TCP协议中包含了专门的传递保证机制,当数据接收方收到发送方传来的信息时,会自动向发送方发出确认消息;发送方只有在接收到该确认消息之后才继续传送其它信息,否则将一直等待直到收到确认信息为止。
UDP协议并不提供数据传送的保证机制。如果在从发送方到接收方的传递过程中出现数据包的丢失,协议本身并不能做出任何检测或提示。因此,通常人们把UDP协议称为不可靠的传输协议。
- TCP 是面向连接的传输控制协议,而UDP 提供了无连接的数据报服务;
- TCP 具有高可靠性,确保传输数据的正确性,不出现丢失或乱序;
- UDP 在传输数据前不建立连接,不对数据报进行检查与修改,无须等待对方的应答,所以会出现分组丢失、重复、乱序,应用程序需要负责传输可靠性方面的所有工作;
- UDP 具有较好的实时性,工作效率较 TCP 协议高;
- UDP 段结构比 TCP 的段结构简单,因此网络开销也小;
- TCP 协议可以保证接收端毫无差错地接收到发送端发出的字节流,为应用程序提供可靠的通信服务。对可靠性要求高的通信系统往往使用 TCP 传输数据。
五、TCP/IP
TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。
六、TCP 流量控制
TCP 连接的双方主机都会为该 TCP 连接分配缓存和变量。当该 TCP 连接收到正确、按序的字节后,就将数据放入接收缓存。上层的应用进程会从该缓存中读取数据,但不必是数据一到达就立即读取,因为此时应用程序可能在做其他事务。而如果应用层读取数据相对缓慢,而发送方发送得太多、太快,发送的数据就会很容易地使该连接的接收缓存溢出。
所以,TCP 为应用程序提供了流量控制服务(flow-control service),以消除发送方使接收方缓存溢出的可能性。
流量控制是一个速度匹配服务,即发送方的发送速率与接收方应用程序的读取速率相匹配。
作为全双工协议,TCP 会话的双方都各自维护一个发送窗口和一个接收窗口(receive window)的变量来提供流量控制。而发送窗口的大小是由对方接收窗口来决定的,接收窗口用于给发送方一个指示--该接收方还有多少可用的缓存空间。
发送窗口
发送方的发送缓存内的数据都可以被分为 4 类:
- 已发送,已收到 ACK
- 已发送,未收到 ACK
- 未发送,但允许发送
- 未发送,但不允许发送
则 2 和 3 属于发送窗口
发送窗口只有收到发送窗口内字节的 ACK 确认,才会移动发送窗口的左边界。
接收窗口
接收方的缓存数据分为3类:
- 已接收
- 未接收但准备接收
- 未接收而且不准备接收
则 2 属于接收窗口(这里的接收指接收数据并确认)
接收窗口只有在前面所有的报文段都确认的情况下才会移动左边界。当在前面还有字节未接收但收到后面字节的情况下,会先接收下来,接收窗口不会移动,并不对后续字节发送 ACK 确认报文,以此确保发送端会对这些数据重传。
我们定义以下变量:
LastByteRead
:接收方应用程序读取的数据流的最后一个字节编号。可以得知,这是接收缓存的起点
LastByteRcvd
:从网络中到达的并且已放入接收缓存中的数据流的最后一个自己的的编号。
可以得知:LastByteRcvd - LastByteRead <= RcvBuffer(接收缓存大小)
那么接收窗口 rwnd =RcvBuffer - (LastByteRcvd - LastByteRead)
rwnd
是随时间动态变化的,如果 rwnd
为 0,则意味着接收缓存已经满了。
接收端在回复给发送端的 ACK 中会包含该 rwnd
,发送端则会根据 ACK 中的接收窗口的值来控制发送窗口。
有一个问题,如果当发送 rwnd
为 0 的 ACK 后,发送端停止发送数据。等待一段时间后,接收方应用程序读取了一部分数据,接收端可以继续接收数据,于是给发送端发送报文告诉发送端其接收窗口大小,但这个报文不幸丢失了,我们知道,不含数据的 ACK 是不会超时重传的,于是就出现发送端等待接收端的 ACK 通知||接收端等待发送端发送数据的死锁状态。
为了处理这种问题,TCP 引入了持续计时器(Persistence timer),当发送端收到对方的 rwnd=0
的 ACK 通知时,就启用该计时器,时间到则发送一个 1 字节的探测报文,对方会在此时回应自身的接收窗口大小,如果结果仍为 0,则重设持续计时器,继续等待。
七、拥塞控制
TCP 除了可靠传输服务外,另一个关键部分就是拥塞控制。
TCP 让每一个发送方根据所感知到的网络拥塞程度来限制其能向连接发送流量的速率。
可能有三个疑问:
TCP 发送方如何感知网络拥塞?
TCP 发送方如何限制其向连接发送流量的速率?
发送方感知到网络拥塞时,采用何种算法来改变其发送速率?
这就是 TCP 的拥塞控制机制。
前边说到,TCP 连接的每一端都是由一个接收缓存、一个发送缓存和几个变量(LastByteRead
、LastByteRcvd
、rwnd
等)组成。而运行在发送方的 TCP 拥塞控制机制会跟踪一个额外的变量,即拥塞窗口 cwnd
(congestion window)。它对一个 TCP 发送方能向网络中发送流量的速率进行了限制。
发送方中未被确认的数据量不会超过 cwnd
和 rwnd
的最小值: min(rwnd,cwnd)
。
1.TCP 发送方如何感知网络拥塞
冗余 ACK(duplicate ACK):就是再次确认某个报文段的 ACK,而发送方先前已经收到对该报文段的确认。
冗余 ACK 的产生原因:
- 当接收端接收到失序报文段时,即该报文段序号大于下一个期望的、按序的报文段,检测到数据流中的间隔,即由报文段丢失,并不会对该报文段确认。TCP 不使用否定确认,所以不能向发送方发送显式的否定确认,为了使接收方得知这一现象,会对上一个按序字节数据进行重复确认,这也就产生了一个冗余 ACK。
- 因为发送方经常发送大量的报文段,如果其中一个报文段丢失,可能在定时器过期前,就会收到大量的冗余 ACK。一旦收到 3 个冗余 ACK(3 个以下很可能是链路层的乱序引起的,无需处理),说明在这个已被确认 3 次的报文段之后的报文段已经丢失,TCP 就会执行快速重传,即在该报文段的定时器过期之前重传丢失的报文段。
将 TCP 发送方的丢包事件定义为:要么出现超时,要么收到来自接收方的 3 个冗余 ACK。
当出现过度的拥塞时,路由器的缓存会溢出,导致一个数据报被丢弃。丢弃的数据报接着会引起发送方的丢包事件。那么此时,发送方就认为在发送方到接收方的路径上出现了网络拥塞。
2.TCP 发送方如何限制其向连接发送流量的速率
- 当出现丢包事件时:应当降低 TCP 发送方的速率。
- 当对先前未确认报文段的确认到达时,即接收到非冗余 ACK 时,应当增加发送方的速率。
3.发送方感知到网络拥塞时,采用何种算法来改变其发送速率
即 TCP 拥塞控制算法(TCP congestion control algorithm)
包括三个主要部分:慢启动、拥塞避免、快速恢复,其中快速恢复并非是发送方必须的,慢启动和拥塞避免则是 TCP 强制要求的
(1)慢启动
当一条 TCP 连接开始时,拥塞窗口 cwnd
的值通常置为一个 MSS
的较小值,这就使初始发送速率大约为 MSS/RTT(RTT:往返时延,报文段从发出到对该报文段的确认被接收之间的时间量)。
而对 TCP 发送方来说,可用带宽可能比 MSS/RTT 大得多,TCP发 送方希望迅速找到可用带宽的数量。因此,在慢启动状态,cwnd
以一个MSS
的值开始并且每当收到一个非冗余 ACK 就增加一个 MSS
。
如图,最初
cwnd
值为 1MSS
,发送一个报文段 M1
。收到 M1
的确认后,cwnd
增加为 2MSS
,这时可以发送两个报文段 M2
,M3
。收到这两个报文段的确认后,cwnd
则增加为 4MSS
,可以发送四个报文段,以此类推...
因此,TCP 虽然发送速率起始慢,但在慢启动阶段以指数增长。
这种指数增长很显然不是无限制的,那么何时结束呢?
如果出现丢包事件,TCP 发送方将 ssthresh
(慢启动阈值)设置为 cwnd/2
- 发生由超时引起的丢包事件,并将
cwnd
重置为1MSS
,重启慢启动 - 当 TCP 发送方的
cwnd
值达到或超过ssthresh
,再继续翻倍显然不合适。这时将结束慢启动转移到拥塞避免模式。 - TCP 发送方检测到 3 个冗余 ACK,会结束慢启动,并快速重传,即在该报文段的定时器过期之前重传丢失的报文段。且进入快速恢复状态。
(2)拥塞避免
一旦进入拥塞避免状态,cwnd
的值大约是上次遇到拥塞时的值的一半,即距离拥塞并不遥远。因此,TCP 无法每过一个 RTT 就将 cwnd
翻倍。而是每个 RTT 只增加 1MSS
,即每收到一个非冗余 ACK,就将 cwnd
增加 1/cwnd
。即假如此时 cwnd
为 10MSS
,则每收到一个非冗余 ACK,cwnd
就增加 1 /10MSS
,在 10 个报文段都收到确认后,拥塞窗口的值就增加了 1MSS
。
那么何时结束拥塞避免的线性增长(每 RTT 1MSS)呢?
和慢启动一样,如果出现丢包事件,TCP 发送方将 ssthresh
(慢启动阈值)设置为 cwnd/2
(加法增大, 乘法减小)
- 发生由超时引起的丢包事件,拥塞避免和慢启动处理的方式相同。即 TCP 发送方将
ssthresh
(慢启动阈值)设置为cwnd/2
,并将cwnd
重置为1MSS
,重启慢启动 - TCP 发送方检测到 3 个冗余 ACK,
cwnd
为原来的一半加上3MSS
,进入快速恢复状态。
(3)快速恢复
快速恢复是由 3 个冗余 ACK 引起的。
在快速恢复中,对引起 TCP 进入快速恢复状态的缺失报文段,对收到的每个冗余 ACK,cwnd
增加 1 个 MSS
。最终,当对丢失报文段的一个 ACK 到达时,TCP 在降低 cwnd
后进入拥塞避免状态。
如果出现超时,和之前一样,即 TCP 发送方将 ssthresh
(慢启动阈值)设置为 cwnd/2
,并将 cwnd
重置为 1MSS
,重启慢启动
快速恢复并非是必须的。
TCP 的拥塞控制是:每个 RTT 内 cwnd
线性(加性增)增加 1MSS
,然后出现 3 个冗余 ACK 事件时 cwnd
减半(乘性减),因此 TCP 拥塞控制常被称为加性增,乘性减拥塞控制方式。