1. 三次握手
三次握手:建立连接 四次挥手:释放连接
1.三次握手
- 开始前:客户端处于close状态,服务端属于listen状态
- 开始:
- 第一次握手:客户端给服务端发送syn报文,并指定客户端的初始化序列号ISN(客户端处于SYN_SENT状态)
- 第二次握手:服务端接收到客户端报文,并生成SYN报文,指定服务端的初始化序列号,给客户端发送SYN报文、初始化序列号、ACK值(使用客户端的序列号+1)(服务端处于SYN_RCVD接收状态)
- 第三次握手:客户端接收到SYN报文后,会发送SYN报文、ACK值(服务器的序列号值+1),表示已收到服务端请求,此时ACK报文段可携带请求数据,不携带数据则不消耗序号。
1.1 为什么需要三次握手,两次不行吗?
(1)第一次握手:客户端发网络包,服务端收到(证明客户端发送能力、服务端接受能力没问题)
(2)第二次握手:服务端发网络包,客户端收到(服务端发送能力,客户端接受能力没问题,但是此时服务端不知道客户端的接受能力是否正常)
(3)第三次握手:客户端发网络包,服务端收到(客户端、服务端接收发送能力均正常)
1.2试想如果是用两次握手,则会出现下面这种情况
客户端发出请求,但是请求报文丢失,客户端此时重新发送报文、服务端正常接受确认链接,正常交易。但是第一个丢失的报文段只是在某个网络节点滞留,等第二次请求连接释放后才到达服务端,此时服务端以为客户端发送两次请求,导致服务端再次发送请求给客户端,但是客户端忽略(浪费资源)
1.3 什么是半连接队列?
服务端第一次接受客户端的SYN后,服务端处于SYN_RCVD状态,此时双方还没有完全建立其连接,此时的连接会被放到半连接队列,三次握手结束后,会把连接放入到全连接队列
1.4 三次握手过程中可以携带数据吗?
其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据
为什么这样呢?大家可以想一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。
也就是说,第一次握手不可以放数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。
2. 四次挥手
(1)开始前:服务端、客户端均属于确认状态
(2)第一次挥手:客户端发起关闭请求,客户端发送FIN报文及序列号(客户端此时处于FIN_WAIT状态)
(3)第二次挥手:服务端收到FIN报文,发出确认报文ACK值为序列号+1(服务端此时处于CLOSE_WAIT 状态)
(4)第三次挥手:服务端发起关闭请求,服务端发送FIN报文及序列号(服务端处于最后确认状态)
(5)第四次挥手:客户端收到FIN报文,客户端发送ACK报文、序列号+1回应,服务端收到后关闭连接(服务端此时处于关闭状态)
TCP 连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户端或服务端均可主动发起挥手动作。
2.1 挥手为什么需要四次?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。