三次握手
首先客户端、服务端都处于closed状态。假设开启tcp服务,服务端会主动监听某个窗口,状态为LISTEN
客户端随机初始化一个序列号,然后SYN位设为1,状态为SYN-SENT。
服务端收到了就会应答,服务端也初始化自己的序列号,并在确认应答号上填写客户端序列号+1,然后SYN和ACK位都设为1,状态为SYN-RCVD
客户端收到后还要回一个确认报文,确认应答号是服务端序列号+1,ACK位设为1,这次报文就可以带数据了,状态为ESTABLISHED
服务端收到后,状态为ESTABLISHED
为什么是三次握手
避免历史连接(主要原因)
假设一开始客户端发一个SYN(seq = 90)报文,然后客户端宕机了,而且这个 SYN 报文还被网络阻塞了,服务端并没有收到,接着客户端重启后,又重新向服务端建立连接,发送了 SYN(seq = 100)报文:
假设只有两次握手,那么服务端收到第一个SYN就得建立连接了,直接ESTABLISHED,回SYN ACK,虽然后续客户端会发现回的SYN ACK不是他想要的,会发送RST报文终止tcp,但是这平白无故浪费了服务端资源去建立了一个无用tcp,甚至可能都开始发数据了
三次握手才可以同步双方的初始序列号
理论上四次握手可以达到同步,也就是
1、客户端告诉服务端序列号
2、服务端SYN ACK
3、然后服务端告诉客户端序列号
4、客户端SYN ACK
但是第2、3步可以和一起
为什么每次序列号都是随机初始化的
避免之前建立的tcp连接有历史数据留在网络拓扑里了,然后后来新建立tcp后,这个历史数据传到服务端了,结果服务端以为是这次tcp传来的数据。出现错乱了
某次握手丢失怎么办
反正就记住一个规则,只可能重传SYN不可能重传ACK(第二次握手算作SYN)
四次挥手
客户端完成最后的通信任务了,就会发一个tcp,FIN位设为1,进入FIN_WAIT_1状态
服务端收到后,发ACK,进入CLOSE_WAIT状态
客户端收到ACK,进入FIN_WAIT_2状态
等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态
客户端收到后,发ACK,进入TIME_WAIT状态(等一段时间自己关闭)
服务端收到ACK,进入CLOSE状态,服务端完成关闭
客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭
为什么需要四次挥手
因为服务端回ACK适合可能还有数据要处理,不能合并FIN和ACK