1. 简介
TCP提供一种可靠的面向连接的全双工服务,位于传输层。
2. TCP报文段结构
TCP报文段包括首部字段和数据字段,其中数据字段来自于应用层的数据,最大长度为MSS。
首部字段
- 源端口号(16 bit):发送进程所占用的端口号
- 目的端口号(16 bit):接收进程所占用的端口号
- 序号(32 bit):传输方向上对数据字节流中的每一个字节编号,这个序号就是发送方要传输的报文段中数据流的第一个字节的序号。
- 确认号(32 bit):接受方对接受到的报文段作出确认,确认号即是希望接受的下一个报文段数据字段中的第一个字节的编号。
- 首部长(4 bit):标识首部的大小以多少个4字节为单位,最大为15,即60字节。
- 标志位(6 bit):
- URG:表示紧急指针是否有效。
- ACK:表示确认号是否有效。
- PSH:表示接收方应立即从缓冲读走数据,将数据传给上层。
- RST:表示要求对方重新建立连接。
- SYN:表示请求建立一个连接。
- FIN:表示关闭连接。
- 接受窗口(16 bit):用于告知接收方自己还有多少缓存空间可用,因为TCP是全双工通信,双方都维持一个接受窗口。
- 检验和(16 bit):接收端用检验和检验报文段有无损坏。
- 紧急数据指针(16 bit):当URG位为1时,此紧急数据指针指向紧急数据的最后一个字节。
- 选项字段:该字段是可选和变长的字段,可用于发送方与接收方协商最大报文段长度(MSS)。
3. 可靠性实现
连接建立(三次握手)
- 第一次:客户端发送SYN报文请求建立连接,然后进入SYN_SEND状态。
- 第二次:服务器收到SYN报文,确定建立连接并发送SYN + ACK报文,然后进入SYN_RECV状态。
- 第三次:客户端收到SYN + ACK报文,并对服务器的请求进行确认,发送ACK报文,然后进入ESTABLISH状态。
为什么要三次握手?
现在考虑两次握手的情况:<<计算机网络>>谢仁希版里面说防止已失效的连接请求报文段,意思是TCP第一次握手客户端发给服务器的SYN报文段出现延迟,然后客户端发现超时重传SYN报文段,这一次服务器收到并回应一个ACK报文,服务器端的连接建立,收到ACK报文的客户端也成功建立了连接。然而此时第一次发出的已失效的SYN报文此时到达了服务器,服务器以为发现是客户端的连接建立请求,同一建立起连接,然后发回一个ACK报文,客户端收到后不理睬,那服务器白白浪费TCP通信资源。但采用三次握手可以解决这个问题。
连接拆除(四次挥手)
- 第一次:客户端发送FIN+ACK报文,进入FIN_WAIT_1状态,表示没有数据要发送了。
- 第二次:
- 服务器收到了FIN+ACK报文,知道了断开请求,发送一个ACK报文,然后服务器进入CLOSE_WAIT状态,表示可能还有数据要发送。
- 客户端收到了服务器的ACK报文进入了FIN_WAIT_2状态。
- 第三次:服务器向客户端发送FIN+ACK报文,然后进入LAST_ACK状态等待客户端的回应。
- 第四次:客户端收到FIN+ACK报文,知道了断开连接的请求,接着客户端发送ACK报文然后进入TIME_WAIT状态,等待2MSL时间服务器没有在响应就最终进入CLOSE状态。
为什么要等待2MSL时间?
- MSL是一个IP数据报在网络中的最大生存时间,如果客户端不等待2MSL而是直接进入CLOSED状态,服务端可能没有接收到最后一次ACK包会在超时重传FIN包,此时因为客户端已经进入CLOSED状态,所以服务端就不会收到ACK报文而是收到RST报文。所以等待2MSL时间是防止最后一次握手ACK报文没有到达对方而触发重传FIN准备的。
- 让前一次使用这个端口的连接传输的数据到达接收方或消失,避免与新建立的连接数据混淆。
流量控制
TCP是全双工的通信协议,在通信两端都维持有一个发送窗口和接受窗口,对于一个发送方和一个接收方来说,接收方的接收窗口大小受到接收缓存大小的限制,如果发送方发送窗口大小持续增大导致发送速率增加,而接受缓存过快填满而导致接收窗口大小减小,结果数据可能溢出。所以动态调整接收窗口就变得非常重要,可以通过TCP报文的窗口字段告知发送方本方还有多少缓存空间可用,这也就是流量控制。
拥塞控制
拥塞控制是对于整体网络(包括路由器、交换机)出现拥塞的进行控制, 不同于流量控制的点对点控制,TCP的拥塞控制由4个核心算法组成。
慢启动(Slow Start)
在发送方维持一个额外的拥塞窗口变量cwnd(congestion window),这个拥塞窗口的大小取决于网络的拥塞程度,而流量控制的窗口取决于接收方的接受缓存,最终发送方的发送窗口大小应该为两者中的最小值。
- 一开始,拥塞窗口的大小设置为一个MSS大小,即允许发送一个报文段
- 发送完窗口所允许发送的报文段后,接收到一个对该报文段ACK报文段后,cwnd翻倍(cwnd = cwnd * 2)
- 接着再发送完所有允许发送的2个报文段后,接收到两个ACK报文段后cwnd再次翻倍
- 直到网络出现拥塞
拥塞避免(Congestion Avoidance)
上面说到慢启动的过程持续到网络出现拥塞,即出现超时还未收到ACK报文,此时就要进行拥塞避免:
- 将慢启动阀值
ssthresh
设置为当前拥塞窗口cwnd的一半 - 将cwnd的大小设置为1个MSS,重新执行慢启动算法
- 当cwnd的大小达到
ssthresh
后的增量变成1,即只增加1个MSS大小
快速重传(Fast Retransmit)
快速重传的目的是想让发送方在超时之前快速重传丢失的报文段。当发送方连续收到3个冗余的ACK就会执行快速重传。
快速恢复(Fast Recovery)
连续收到3个冗余的ACK其实也表示网络出现拥塞导致丢包,这时执行与拥塞避免的类似操作:
- 将慢启动阀值
ssthresh
设置为当前拥塞窗口cwnd的一半 - 将cwnd的大小也设置为当前拥塞窗口cwnd的一半,执行拥塞避免算法
第一步与拥塞避免的第一步相同,但cwnd不从1个MSS大小开始执行慢启动指数增长,而是减半执行拥塞避免线性增长,进行快速恢复。
4. 最后
现在总结下TCP的可靠性具体表现在:
- 连接建立与拆除的可靠性实现
- 确认与重传机制
- 数据校验
- 流量控制
- 拥塞控制
网友评论