1.TCP基本认识
在回答三次握手与四次挥手之前我们首先对TCP有一定的理解。如上图所示,该图为TCP头部的组成。
- 序列号:在建立连接时由计算机生成的随机数作为其初始值,通过SYN包传给接受端主机,每发送一次数据,就累加一次该数据字节数的大小,主要是用来解决网络包乱序问题。
- 确认应答号:指下一次期望收到的数据的序列号,发送段接收这个确认应答以后可以认为在这个序列之前的数据都被正常接收了,主要用来解决不丢包的问题。
控制位:
- ACK:该位为1时,确认应答的字段变为有效,TCP规定戳最初建立连接时SYN包之外,该位必须置为1。
- RST:该位为1时,表示TCP连接中出现异常必须强制断开连接。
- SYN:该位为1时,表示希望创建连接,并在其序列号的字段进行序列号初始值的设定。
- FIN:该位为1时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换FIN位为1的TCP段。
2.三次握手
- 一开始的时候,服务器与客户端都处于CLOSED状态。先是服务端主动监听某个端口,处于LISTEN状态。
- 客户端会随机初始化序号(client_isn ),将此序号置于TCP首部的序号字段,同时把SYN标志设置为1,表示SYN报文。接着把第一个SYN报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于SYN-SENT状态。
- 服务端接收到客户端的SYN报文后,首先服务端也会随机初始化自己的序号,并且将此序号填入TCP首部的序号字段中,其次把客户端发送过来的SYN报文中的序号读取出来并加1(即client_isn+1),然后填入TCP首部中的确认应答字段。接着把SYN和ACK标志位设置为1,最后把报文发送到客户端,之后服务端处于SYN-RCVD状态。
- 客户端接收到服务端的报文后,还要向服务端回应最后一个应答报文,首先将该应答报文ACK标志位设置为1,其次把服务端发送过来的报文中的序号读取出来并加1(即server_isn + 1),然后填入TCP中的确认应答字段,并且将ACK为置为1,最后将报文发送到服务端,之后客户端处于ESTABLISHED状态。
- 服务器收到客户端的应答报⽂后,也进⼊ ESTABLISHED 状态。
之后,客户端与服务端就建立起了连接,但在客户端与服务端建立起连接时为什么要三次握手,两次不行吗?其实很明显,当进行两次握手时,客户端的起始序列号可以确定,但服务端的起始序列号将得不到确认。
3.四次挥手
- 客户端打算关闭连接时,会向服务端发送一个首部FIN标志被置为1的报文,即FIN报文,之后客户端进入FIN_WAIT_1状态。
- 服务端接收到该报文后,就会向客户端发送一个ACK应答报文,接着服务端就进入CLOSED_WAIT状态。
- 客户端接收到服务端发送过来的ACK应答报文后,进入FIN_WAIT_2状态。
- 等待服务端处理完数据后,也会向客户端发送FIN报文,之后服务端进入LAST_ACK状态。
- 客户端接收到服务端发送的FIN报文后,回一个 ACK应答报文,之后进入TIME_WAIT状态。
- 服务端接收到ACK报文后,就进入CLOSED状态。支持服务端就进入CLOSED状态,至此服务端已经完成连接的关闭。
- 客户端在经过2MSL一段时间后,自动进入CLOSED状态,至此客户端也完成连接的关闭。
为什么挥手需要四次呢?
当关闭连接时,客户端会向服务端发送FIN时,表示客户端不再发送数据了,但还是能接收数据。而服务端接收到FIN报文后,先回一个ACK应答报文,这时的服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才会发送FIN报文给客户端来表示同意现在关闭连接。