TCP三次握手
- 刚开始客户端和服务端都处于
CLOSED
状态,然后服务端开始监听某个端口,进入LISTEN
状态 - 第一次握手,客户端主动发起连接,发送
SYN
,自己变成了SYN-SENT
状态- 首部的同部位SYN = 1,初始序号seq=x,SYN=1的报文不能携带数据,但需要消耗一个序列号
- 第二次握手,服务端接收到客户端发送的
SYN
, 返回SYN
和ACK
(对应客户端发来的SYN,把客户端的序列号ISN+1作为ack的值),自己变成了SYN-REVD
- 报文中SYN=1,ACK=1,确认号ack=x+1,初始序列seq=y
- 第三次握手,客户端再发送
ACK
(将服务端的ISN+1作为ACK的值)给服务端,自己变成了ESTABLISHED
状态,服务端收到ACK
之后,也变成了ESTABLISHED
状态。此时双方的连接已经建立。 - 注意:SYN是需要消耗一个序列号的,下次发送对应的ACK序列号要加1。
凡是需要对端确认的,一定消耗TCP报文的序列号
- webSocket中执行connect()将触发三次握手
为什么不是两次握手
根本原因:无法确认客户端的接收能力
握手的目的
- 第一次握手,客户端发包,服务端收到了,此时是为了确认客户端的发送能力和服务端的接收能力正常
- 第二次握手,服务端发包,客户端收到了,此时是为了确认客户端的接收能力和服务端的发送能力正常,但服务端并不能确认客户端的接收能力正常
- 第三次握手,客户端发包,服务端收到了,确认客户端的接收能力。
两次握手的弊端
如果是两次,你现在发了 SYN 报文想握手,但是这个包滞留在了当前的网络中迟迟没有到达,TCP 以为这是丢了包,于是重传,两次握手建立好了连接。
看似没有问题,但是连接关闭后,如果这个滞留在网路中的包到达了服务端呢?这时候由于是两次握手,服务端只要接收到然后发送相应的数据包,就默认建立连接,但是现在客户端已经断开了。
为什么不是四次
可以是四次,但是三次握手就能确认握手的目的是确认双方发送和接收能力。
三次握手过程中可以携带数据么
第三次握手的时候,可以携带,前两次握手不能携带数据。
第三次握手的时候,客户端和服务端都能确认具有收发能力,可以携带数据。
如果前两次握手能携带数据,那么一旦有人想攻击服务器,那么只需要在第一次握手中的SYN报文中大量数据,那么服务器势必会消耗更多的时间和内存空间去处理这些数据,增大了服务器被攻击的风险。