TCP
引言
- TCP提供面向连接的、可靠的字节流服务
- 在一个TCP连接中,仅有两方进行彼此通信
- TCP通过下列方式提供可靠性
- 应用数据被分割成TCP认为最适合发送的数据块。这和UDP不同,应用程序产生的数据报长度不变。
- 超时重传。TCP发出一个段后,会启动一个定时器,等待目的端确认收到这个报文段,如果不能及时收到一个确认,将重发这个报文段。
- 当TCP收到另一端的数据,他将发送一个确认。这个确认不是立即发送,有延迟。
- TCP将保持首部和数据的校验和。如果接收端的校验和有差错,将丢弃这个报文且不确认收到,从而发送端会超时重传。
- TCP报文段可能失序,如有必要TCP会对接收到数据段进行排序。
- TCP接收端会丢弃重复的报文段
- TCP提供流量控制。TCP连接的每一方都有固定大小的缓冲区,接收端只允许另一端发送接收端缓冲区所能接纳的数据。
TCP的首部
- 32位序号:指发送数据的位置。每发送一次数据,就累加一次该数据字节数的大小。
- 32位确认序号:指下一次应该收到的数据的序列号,也就是目的端期望源端的下一个请求序号
- 4位首部长度:TCP首部长度,一般20字节,最大20 + 40(上图的选项,最大40字节) = 60字节
- 6个标志位:
- URG,该位为1时,表示包中有需要紧急处理的数据。
- ACK,该位为1时,确认应答的字段变为有效,TCP规定除了最初建立连接是SYN包之外该位必须设置为1.
- PSH,该位为1时,表示需要将收到的数据立刻传给应用层;为0时,则不需要立即传而是先进行缓存。
- RST,该位为1时,表示TCP连接中出现异常必须强制断开连接。
- SYN,用于建立连接。该位为1时,表示希望建立连接,并在其序列号的字段进行序列号初始值的设定。
- FIN,该位为1时,表示今后不会再有数据发送,希望断开连接。
- 16位窗口大小:用于通知从相同TCP首部的确认应答号所指位置开始能够接收的数据大小。TCP不允许发送超过此处所示大小的数据。但如果窗口为0,则表示可以发送窗口探测,以了解最新的窗口大小。这个数据必须是1个字节。
- 16位校验和:校验和覆盖了整个TCP报文段(TCP首部 + TCP数据),这是一个强制性字段,一定是由发端计算和存储,收端进行验证。
- 16位紧急指针:只有URG标志位为1时有效。该字段的数值表示本报文段中紧急数据的指针。(从数据部分的首位到紧急指针所示的位置为止为紧急数据,即紧急指针指出了紧急数据的末尾在报文段中的位置)
TCP连接的建立与终止
3次握手
-
客户端发送一个SYN段指明打算连接的服务端端口,以及初始序号ISN(initial sequence number)。发送完成后客户端进入SYN_SEND状态
-
服务端确认。ACK = 客户端SYN + 1, 同时生成自己的SYN和ISN。发送完成后服务端进入SYN_RCVD状态
-
客户端确认。ACK = 服务端SYN + 1。客户端发送完毕后,进入ESTABLISHED状态,服务端接收到这个包,也进入ESTABLISHED状态, TCP握手结束
4次挥手
- 客户端打算关闭连接,向服务端发送FIN报文。客户端进入FIN_WAIT_1状态
- 服务端确认。ACK = 客户端FIN + 1。服务器进入CLOSE_WAIT(等待关闭)状态,此时的TCP处于半关闭状态(下面会说什么是半关闭状态),客户端到服务器的连接释放。客户端收到来自服务器的ACK应答报文段后,进入FIN_WAIT_2状态。
- 服务端打算关闭连接,向客户端发送FIN报文。服务端进入LASK_ACK(最后确认)状态,等待客户端的确认。
- 客户端确认。ACK = 服务端FIN + 1。客户端进入TIME_WAIT(时间等待)状态,服务器收到ACK应答报文段后,服务器就进入CLOSE(关闭)状态,到此服务器的连接已经完成关闭。客户端处于TIME_WAIT状态时,此时的TCP还未释放掉,需要等待2MSL后,客户端才进入CLOSE状态。
半关闭状态:TCP提供了连接的一方在结束它的发送后还能接受来自另一端数据的能力。通俗来说,就是不能发送数据,但是还可以接受数据。
MSL(Maximum Segment LifeTime)是报文最大生成时间,它是任何报文在网络上存在的最长时间,超过这个时间的报文将被丢弃。TIME_WAIT等待时间是2MSL即报文一来一回的最大时间。
滑动窗口
拥塞控制
首先规定几个缩写,在下述文章中出现可以进行对照:
- cwnd:拥塞窗口
- SMSS:TCP报文段的最大长度(仅指数据部分)
- ssthresh:慢启动门限,相当于一个阈值
- RTT:往返时间 (表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认,不包含数据传输时间,总共经历的时间)
慢启动
tcp刚开始并不知道网络的实际情况,需要用一种试探性的方式平滑的增加cwnd的大小。慢启动算法增加了拥塞窗口,可以反应网络的整体情况,而滑动窗口只能反应主机个体情况。
慢启动是指数型的增长模式,初始cwnd为1,再增长为2->4->8->...,最大为ssthresh
拥塞避免
拥塞避免即让cwnd缓慢的增长,在一个RTT时间内,将cwnd的大小增加1,即增加cwnd的初始大小。这样,cwnd的大小就从以前的指数级增长变成现在的线性增长。
当cwnd > ssthresh时启动拥塞避免
快重传
在TCP报文段丢失或者接收端收到乱序的TCP报文段等情况下,发送端都会收到重复的确认报文段。
当发送端连续收到3个重复的确认报文端段的时候,tcp就认为拥塞发生了。然后会立即重传丢失的报文段。
快恢复
快速恢复机制一般和快速重传机制同时使用。快速恢复机制如下:
- 当发送端收到第三个重复确认的报文时,会更新ssthresh的值,然后立即重传丢失的报文段,并且设置:cwnd = ssthresh+3*SMSS,进入拥塞避免阶段。
- 当收到一个重复确认的报文时,设置cwnd = cwnd +SMSS。此时发送端可以发送新的TCP报文(如果新的cwnd允许)
- 当收到新数据的确认时,设置cwnd=ssthresh。进入拥塞避免阶段。