一、TCP的概念和特点
1、TCP的概念
TCP全称传输控制协议,是一种面向连接的、可靠的、面向字节流的传输层通信协议。
面向连接: 指的是数据传输之前,收发双方需要先建立一条逻辑通路。
无面向连接:指的是数据可以自由传输,无需建立逻辑通路。
TCP 是在不可靠的 IP 层之上,实现可靠的数据传输能力。 数据有序、无丢失、不重复 。
2、TCP的特点
TCP提供全双工通信
发送缓存:
1、存放发送应用程序传输给发送方TCP准备发送的数据。
2、存放TCP已发送但是尚未收到确认的数据。
接收缓存
1、不按序到达的数据。
2、按序到达,但未被应用程序接收的数据。
TCP和上层应用进程的交互方式是面向字节流的
TCP和上层应用进程的交互方式:
1、发送方可以发送不同大小的数据块到发送缓存。
2、先会对发送缓存内的数据分段,打包成 TCP 数据包再发送。
3、在接收一侧,数据包会先进入接收缓存区。
4、当一定数量的数据包全部到达,重排、组装,以数据流方式吐给接收方。
TCP报文段 :
虽然 TCP 是面向字节流的,但是 TCP 所处理的数据单元却是面向报文段。
tcp既可以运载数据,又可以用来建立连接、释放连接和应答。
1、TCP首部信息,最短20字节
2、序列号:
可以理解为字节流的编号。每发送一个字节的数据,序列号+1
3、确认序列号:
是收到的报文的序列号+收到的数据部分字节大小
确认机制:没收到一个发送方发出的数据,都需要回复一个确认报文。
1、表明接收方期望收到发送方发送的下一个字节的序号。
2、代表接收方已经收到了确认序列号之前的所有字节数据。
累计确认
4、数据偏移:
TCP报文段的数据起始处距离TCP报文段的起始处的距离。其本质是在描述TCP首部大小。
5、紧急指针:
与控制位中的URG字段共同使用,当URG=1时,紧急指针有效。
紧急数据会被TCP放置在数据部分的最前方,即从第0个字节开始,而紧急指针是为了表明紧急数据的结束位置。
例如:紧急指针为70,则紧急数据位置为0字节到 69 字节。
6、选项字段:
最大报文段长度MSS;窗口扩大银子;时间戳;选择确认机制。安全摘要选项。
3、TCP标志位
紧急位URG:
报文段中包含紧急数据,是高优先级的数据,应尽快传输,不再缓存队列中排队。
确认位ACK:
当确认位置位1,则确认序列号有意义。 在连接连接以后所有传输的报文段都必须把ACK置位1 。
推送位PSH:
接收方应尽快将数据交付给应用程序,不再等待缓存填满再向上提交。
复位RST:
表明TCP连接中出现错误,必须释放连接,然后重新建立连接。
同部位SYN:
表明这是一个连接请求报文。
终止位FIN:
表明发送方数据已完全发送,要求释放连接。
补充: 四元组 :是用来建立一个完整的TCP连接。(源IP、源端口、目IP、目端口) 套接字 :IP+端口
二、TCP的可靠性
确认、重传、排序、流控。
1、确认机制
是TCP保障可靠性的核心点。
TCP协议保证对方能够收到本端发送的数据段的方式,就是让对方回复一个确认报文段。这是确认 机制的做法 。
确认报文是唯一一种不需要被确认的数据段信息。
(1)SACK机制---选择确认机制
TCP在可选项字段中,添加了一个变量。 该变量中携带的就是自己已经收到的数据信息。 TCP的确认是累积确认机制,正确接收失序的报文段是不会被接收方逐个确认的。因此,发送方在 重传的时候,需要将冗余ACK报文及之后的报文段都重新发送一遍。 ---- 导致资源浪费。 选择确认机制,不是所有运行TCP协议的设备都支持的。该机制会在TCP三次握手的前两次SYN报文 中进行协商。
2、 重传机制
RTT/RTO
(1)超时重传----当超过一定时间未收到确认报文,则触发重传机制。
超时重传的判断时间依据 RTT( 往返时间 ) 参数 来判断。 RTO 被称为超时重传时间 。 RTO取值应该略大于RTT,但是也不能太大。RTT并非是固定数值,他是动态变化的数值。( PS:RTT---指的是发送端将数据发出后,到他接收到对端反馈的确认报文之间的这段时间。)
(2) 超时间隔加倍机制
当连续多次未收到确认报文,设备会认为是网络拥塞过大,将重传时间加倍, 因为如果按照原本的重传时间发送报文,很可能造成网络拥塞的加剧。
(3)快速重传机制
在TCP中,发送方可以通过接收方的反馈,在超时时间到达前,意识到数据包丢失的现象,并进行 重传。这种情况一般出现在接收端收到一个失序报文的情况下。 快速重传机制不是因为RTO时间到达而触发,这种重传机制是以数据包为驱动的一种重传机制。 当接收方意识到自己所期望的报文段丢失,服务器不能调取失序报文,并且不能确认这些报文信息 。 因为TCP协议无法直接发送一个否认确认报文(没有办法直接发送一个数据报文段,告诉对端自己哪个报文没有收到),所以, TCP 将采用冗余 ACK 的方式来完成缺失报文通告。
3、排序机制
最大字节数由MSS控制。该参数是需要在TCP连接握手的过程中,通过前两次SYN报文段来进行参数协商。 如果双方的MSS 数值不同,则选择 数值较小 的作为传输标准。
MSS 受到 MTU的限制。 (1) MTU:最大传输单元,指的是数据链路层在封装成帧时所允许携带的最大数据量,在以太网当中, MTU数值为1500字节。
(2)MSS:数据段中携带的数据字节数。
MSS===MTU-IP首部-TCP首部
4、流量控制协议
是属于 TCP 的传输效率问题。
(1)滑动窗口
TCP 头部中的 ” 窗口值 “ 是 TCP 实现流控的核心参数。 窗口的大小是可以指定的,该参数的大小指的是无需等待确认应答,而可以继续发送数据包的最大
量 。
窗口的大小,其实体现的就是接收缓存区的大小 。
TCP 要求发送方依据对方的接收窗口 (rwnd) 来控制数据的发送量 。最初, TCP 的接口窗口 === 接收缓存区大小。接口窗口会随着时间的增长而动态变化。
(2) 窗口关闭
窗口的大小是接收端根据自己的缓存空间的剩余量来决定的一个动态变化的数值,那么这个剩余量 就有归0 的可能性。也就代表此时接收方所有缓存空间均已占用并且没能及时处理里面的资源。 所以,当接收方反馈窗口值为0 时,那其实就是在通知发送方,别再发送数据,处理不过来。 该机制存在风险:接收方通过确认 ACK 报文来通知发送方自己的窗口大小。理论上,如果接收方将自己的缓存里的数据清空后,将反馈一个窗口值非0 的报文来通知对端,可以继续发送数据了。但是如果这个非0 的 ACK 报文在重传过程中丢失。 ---- 会引发风险, 因为确认报文丢失不会触发重传机制 。所以,客户端依然处于窗口关闭状态,不会发送数据,在等待服务器的响应。而服务器也在等待客户端发送数据。此时,两者进入到死锁状态 。
解决方式:客户端周期性发送窗口探测报文,该报文只包含TCP 首部信息。通过触发 TCP 确认机制, 来让服务端发送确认报文,从而告知客户端,此时的窗口大小。打破死锁现象。
窗口大小仅仅是实现了将 TCP 数据传输的效率提高(不需要确认);但是并没有看到所谓的流量控
制,而真正的流量控制是由窗口关闭机制实现的 。
(3)窗口扩大因子
TCP选项字段中的窗口扩大因子,可以解决首部中窗口值过小的问题。因为首部中窗口值大小仅为16bit,最大值为 65536 。 窗口扩大因子占据 3 字节大小。取值仅为 0-14 。是用来将 TCP 的窗口的值左移的位数,使得原本的窗 口值加倍 。
窗口扩大因子,只能出现在同步报文段中,否则将被忽略 。
5、TCP的拥塞控制机制
中间链路的处理能力--->拥塞控制机制
网络中对资源需求量超过了资源的可用量的情况,被称为拥塞。
如果出现了拥塞情况。--->分组丢失。重传--->网络的拥塞情况加剧 。
流量控制是为了让接收方能够来得及接收,而拥塞控制是为了降低整个网络的堵塞程度 。
TCP将连接中出现的丢包行为,视为拥塞的表现。
1、数据包确认超时。
2、收到来自接收方发送的三个冗余ACK报文。
TCP如何来控制数据的发送量
拥塞窗口--->跟接收窗口一样,都可以对发送的字节数大小进行限制。
发送方,发出未收到确认的报文的字节数,必须小于或等于拥塞窗口和接收窗口的最小值 。
拥塞窗口的数值是依靠 TCP 拥塞控制算法得出。 TCP 是在保证能够支持的最大传输效率的情况下,来保证没有拥塞发生。被称为自计时 。 ---> 通过收到的确认报文来增加拥塞窗口。
拥塞控制算法--->慢启动,拥塞避免,快速恢复 。
慢启动 ---> 通常在开始传输数据时,拥塞窗口会被设置的很小。一般等于一个 MSS 数值。即一次只能 发送一个数据报文段。 每收到一个新的ACK 确认报文,就会增加一倍 MSS 的大小。
TCP会设定一个慢启动门限 来评判。评判是否要停止慢启动的机制。
1、当拥塞窗口<门限,继续使用慢启动算法
2、当拥塞窗口>门限,此时将慢启动算法切换为拥塞避免算法。
3、当拥塞窗口=门限,两者均可使用。
拥塞避免
在一个RTT时间线内,拥塞窗口只增加一个 MSS 。
拥塞避免算法,不是说直接避免拥塞,而是通过降低窗口的增大速率而使得网络不容易出现拥
塞 。
快速恢复
如果网络中没有发生拥塞,那么拥塞窗口就会无时无刻的增长下去。 但是如果出现了拥塞,那么这个增长必须停止。
三、TCP的建立和释放
1、TCP的三次握手
TCP 规定 SYN 被设置为 1 的报文段不能携带数据,但是要消耗一个序号 。
(1)TCP连接的建立条件:
1、TCP 建立的双方都需要知晓对方的存在
2、要允许双方协议参数协商
3、设备可以为 TCP 连接分配相应资源(缓存空间)
(2)过程:
1、第一次握手:客户端将标志位SYN置为1,随机产生一个值序列号seq=x,并将该数据包发送给服务端,客户端进入SYN_SEND状态,等待服务端确认。
2、第二次握手:服务端收到数据包后由标志位SYN=1知道客户端请求建立连接,服务端将标志位SYN和ACK都置为1,然后ack=x+1,随机产生一个值seq=y,并将该数据包发送给客户端以确认连接请求,即SYN+ACK包,此时服务器进入SYN_RECV状态。
3、第三次握手:客户端收到确认后检查,如果正确则将标志位ACK为1,ack=y+1,并将该数据包发送给服务端,服务端进行检查如果正确则连接建立成功,客户端和服务器进入ESTABLISHED状态,完成三次握手,随后客户端和服务端之间可以开始传输数据了。
2、TCP的序号绕回问题
1、重复序号:当序号绕回后,之前已经使用过的序号可能会再次出现,导致接收方错误的将重复的报文段当做新的报文段处理。从而丢弃正常的报文。
2、延迟确认:因为延迟确认是收到一定数量的数据后才发送,而序号绕回会导致延迟确认的触发时间延后,从而降低数据传输的效率。
解决思路:使用时间戳选项来增加序号的有效范围 。
时间戳 :
TCP 时间戳 ---> 记录数据报文发送的时间,其中有两个字段,分别为 发送方时间 ; 回显时间 。
1、发送方发送数据时,将本地时间记录在 发送方时间 中。
2、接收方收到数据报文后,将收到的时间戳原封不动的返回给发送方,并在其中记录自己发送报文的时间。
3、发送方收到回应报文后,根据报文中的 回显时间字段 来判断该报文是否是正确的报文,如果是,则根据该时间计算RTT 数值,并计算 RTO 数值。
时间戳是双向选择,需要在TCP连接建立阶段进行协商。
3、TCP的四次挥手
Time-Wait 状态:客户端的倒数第二个状态。
在等待 2MSL 时间以后,客户端切换状态,进入关闭状态。 MSL 是最长报文段寿命 。默认建议时间为2分钟。
过程:
1、刚开始双方处于ESTABLISHED状态。
2、客户端要断开了,向服务器发送 FIN 报文。发送后客户端变成了FIN-WAIT-1状态。注意, 这时候客户端同时也变成了half-close(半关闭)状态,即无法向服务端发送报文,只能接收。
3、服务端接收后向客户端确认,变成了CLOSED-WAIT状态。
4、客户端接收到了服务端的确认,变成了FIN-WAIT2状态。
5、随后,服务端向客户端发送FIN,自己进入LAST-ACK状态,
6、客户端收到服务端发来的FIN后,自己变成了TIME-WAIT状态,然后发送 ACK 给服务端。
这个时候,客户端需要等待2 个 MSL(报文最大生存时间), 在这段时间内如果客户端没有收到服务端的重发请求,那么表示 ACK 成功到达,挥手结束,否则客户端重发 ACK。