TCP的运输链接管理之三次握手四次挥手
1. 传输控制协议TCP
根据应用进程的不同需求,传输层需要有两种不同的运输协议,即面向连接的传输控制协议TCP和无连接用户数据报协议的UDP。当采用面向连接的TCP协议时,尽管下边的网络是不可靠的(只提供最大努力交付)但这种逻辑通信信道就相当于一条全双工的可靠信道。
1.1 TCP的主要特点
- TCP是面向连接的传输层协议
- 每一条TCP连接只能有两个端点 (一对一)
- TCP提供可靠交付
- TCP提供全双工通信
- 面向字节流
1.2 使用TCP协议的各种应用和应用层协议
应用 | 应用层协议 | 传输层协议 |
---|---|---|
电子邮件 | SMTP(简单邮件传输协议) | TCP |
远程终端接入 | TELNET(远程终端协议) | TCP |
万维网 | HTTP(超文本传送协议) | TCP |
文件传送 | FTP(文件传送协议) | TCP |
1.3 TCP报文段的首部格式
TCP的传送数据单元是报文段,一个TCP报文段分为首部和数据两部分,TCP的全部功能都体现在它首部中各字段的作用。
- 源端口(Source Port): 16位,表示数据从哪个进程来
- 目的端口(Destination Port):16位,表示数据到哪个进程去.
- 序号(Sequence Number): 32位,TCP报文段中的数据部分,每一个字节都有它的序号(递增)。根据控制标志中的SYN是否为1,Sequence Number表达不同的含义:SYN = 1:当前为连接建立阶段,此时的序号为初始序号(ISN)。当数据传输正式开始时,数据的第一个字节的序号为 ISN 1SYN = 0:当前报文段中,数据部分的第一个字节的序号。
- 确认序号(Acknowledgment Number): 32位,当控制标志的ACK为1时,表示发送方希望收到的下一个报文段的序号(Sequence Number)。一旦连接建立成功,ACK值一直为1。
- 数据偏移(Data Offset) 4位,TCP报文段的首部长度,单位是word(4字节)。字面含义是:TCP报文段的数据的起始处,距离TCP报文段的起始处 的偏移量。4个字节最大能表示的数字是15,所以首部最大60字节。
- 保留(Reserved): 6位,预留作为后续用途,必须是0
- 控制标志(Control Bits): 一共有6个控制标志,其中SYN/ACK、FIN/ACK主要用于连接的建立、断开阶段。
- URG: 当置为1时,表示紧急指针(Urgent Pointer)字段有效;
- ACK:确认序号字段(Acknowledgment Number)有效
- PSH:接收方应立即把这个报文段交给应用层;
- RST: 重建连接;
- SYN:同步序号,用于建立连接;
- FIN: 发送端不再发送数据;
- 窗口大小(Window Size):16位,允许对方发送的数据量。告诉对方自己缓冲区还能容纳多少字节,用来控制对方发送数据的速度。
- 检验和(Checksum):16位,发送端对TCP首部、数据进行CRC运算得出的结果。接收端收到数据后,对接收到的TCP报文段的首部、数据进行CRC运算,并跟TCP首部中的校验和进行对比,确保数据在传输过程中没有损坏。
- 紧急指针(Urgent Pointer):16位,仅在URG=1时才生效,它的值是一个偏移量,和序号字段中的值相加得到紧急数据最后一个字节的序号。
2. TCP的运输连接管理
运输连接有三个阶段:建立连接、数据传送和释放连接
2.1 TCP的连接建立(三次报文握手)
TCP连接建立的过程中要解决的三个问题:
- 要使得每一方能知道对方的存在
- 要允许双方协商一些参数(如最大窗口值、是否使用最大窗口扩大选项和时间戳选项以及服务质量等)
- 能够对运输实体资源(如缓存大小、链接表中的项目)进行分配
2.1.1 为什么是三次?两次可以吗?四次可以吗?
TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输。
最后再发送一次确认,主要是为了防止已经失效的连接请求报文突然又传到了B,而产生错误。
假定一种异常情况,A发出的第一个连接请求报文段没有丢失,而是在某些网络节点长时间滞留了。于是A再重新传第一次连接请求,后来收到了确认,建立连接,传输数据,后释放连接。但在某个时间段后,第一次延误的连接到达了B,这本来是一个早已失效的报文段,但是B收到请求以后就会误认为是A又发出一次新的连接请求,于是B就向A发出确认报文段,表示同意建立连接。如果不不进行第三次报文握手,那只要B发出确认,新的连接就建立了。此时A并没有发出建立的请求,也不会理会A,而B一直等待着A发来数据,B的许多资源就浪费了。因此采用三次握手,可以防止上述现象的发生,在上述异常情况中,A不会向B发出确认,B由于收不到确认,就知道A没有建立连接。
B发送给A的报文段也可以拆成两个报文段。可以先发送一个确认报文段(ACK = 1,ack = 1)),然后再发送一个同步报文段(SYN = 1,seq = y),这样的过程就变成了四报文握手,但效果是一样的。由于三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。
2.1.2 建立连接时可以携带数据吗?
TCP标准规定,发送SYN报文段不能携带数据,但要消耗一个序列号,发送ACK报文段可以携带数据,但如果不携带数据则不消耗序列号。因此,第三次握手是可以携带数据的,前两次握手是不可以携带数据的。
2.1.3 什么是半连接队列?
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
2.1.4 什么是SYN攻击
我们都知道 TCP 连接建立是需要三次握手,SYN攻击就是攻击者在短时间内伪造大量不存在的IP地址并向Server不断地发送SYN包,Server则回应发送确认包,并等待Client确认,由于源IP地址不存在,因为Server需要不断重复的发送直至超时,久而久之就会占满服务端的 SYN 接收队列(未连接队列),导至正常的SYN请求因为队列已满而丢弃,使得服务器不能为正常用户服务,从而引起网络拥塞甚至系统瘫痪。
2.2 TCP的连接释放(四次挥手)
2.2.1 为什么A最后需要TIME-WAIT状态?
第一,为了保证A发送的最后一个ACK报文段能够到达B。
最后一个ACK报文有可能丢失,使处于LAST-ACK状态的B收不到A对FIN+ACK的确认,B会超时重传这个FIN+ACK报文段,而A在2MSL时间内收到这个重传的FIN+ACK报文段,接着A重新传一次确认,重新启动2MSL计时器。最后A,B都正常进入状态。
如果,A没有在TIME-WAIT状态等待一段时间,而是在发送完ACK之后立即释放连接,就无法收到B重传的FIN+ACK报文段,因而也不会再发送一次确认报文段,这样B就无法按正常步骤进入CLOSE状态
第二,防止“已失效报文段出现在本连接中”。(防止具有相同「四元组」的「旧」数据包被收到)
假设 TIME-WAIT 没有等待时间或时间过短,在成功释放本次连接之后,可能会收到之前被延误的报文,导致数据错乱等严重问题。在A发送完最后一个ACK报文段之后,经过2MSL,就可以保证本连接持续时间内所有产生的报文都从网络上消失,就可以使下一个新的连接中不会出现这种旧的连接请求报文段。
2.2.2 为什么等待时间是2MSL?
MSL(Maximum Segment Lifetime)可译为“最长报文段寿命”,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。TCP允许不同的实现可以设置不同的MSL值。
2.2.3 挥手为什么要四次?
因为TCP是全双工通信的
- 关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
- 服务器收到客户端的 FIN 报文时,先回一个ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。