三次握手
首先需要客户端Init状态,服务端LISTEN状态
过程
- 客户端向服务端询问是否可以建立连接(中途可能因为某些原因导致SYN包在网络节点中滞留)
- 服务端接收之后,如果可以建立连接则返回SYN+ACK包
- 客户端接收到SYN+ACK包之后,将ACK包发送给服务端之后,客户端变成ESTABLISHED状态
- 服务端接收到ACK包之后,状态变成ESTABLISHED状态
流程图
如果只有2次握手
首先需要客户端Init状态,服务端LISTEN状态
过程
- 客户端向服务端询问是否可以建立连接,发送SYB-1-1包
- SYN-1-1包可能因为某些原因导致在某个网络节点之中阻塞
- 为了建立连接,客户端会重发SYN-1-1包(为了区分,后面叫做SYN-1-2包)
- 服务端接收到SYN-1-2包之后,这次SYN包发送正常,服务端接收之后,发送SYN+ACK包之后就建立连接
- 这个时候在某个阶段阻塞的SYN-1-1包突然恢复,然后服务端接收到SYN-1-1包之后,服务端会认为客户端又发起了一个新的连接
- 就会导致客户端认为和服务端只有一个连接,而服务端认为和客户端有2个连接,最后造成了状态不一致
- 如果在三次握手中,服务端接收不到ACK包,就不会建立连接
导致的问题:客户端和服务端连接数量不一致
数据传输状态
因为TCP协议,需要在不可靠的网络信道上保证可靠的连接
并且一包,可能会拆解成多包数据,也有可能产生乱序问题
数据丢失和连续问题
针对以上问题TCP协议会简历一个发送缓冲区
- 发送缓冲区: 从建立连接后,需要发送的报文第一个字节的下标为0,以后字符依次+1
- 发送报文: 每次发送报文的时候,都会在TCP协议中附带【序列号】+【长度】+【内容】
- 确认回复: 每次收到消息后,【消息接收方】会向【消息发送方】回复确认收到【ACK】包(此【ACK】包为下一包起始序列号) = 【消息发送方给的序列号】+【消息发送方给长度】,从而保证数据被接收方确认收到
(【消息发送方】也可以连续发送多包数据,【消息接收方】只需要回复一次【ACK】 包就行了) - 切割发送: 【消息发送方】把数据可以拆解成多包数据,在接收后,【消息接收方】根据【消息发送方给的序列号】+【消息发送方给长度】来重构完整的数据(如果其中丢失了某些数据,【消息接收方】可以根据【ACK】 向【消息发送方】申请重新发送数据)
上述描述,不区分服务端和客户端
四次挥手
流程图
步骤
前提:客户端和服务端处于连接状态
- 【客户端】想服务端发送【FIN】包,通知【服务端】关闭连接,【客户端】发送完FIN包之后,进入【终止等待-1】
- 【服务端】接收到【客户端】的【FIN】包之后,向【客户端】发送【ACK】包,进入【等待关闭】,但是服务端依旧可以发送未发送完的数据包
- 【服务端】发送完未发送完的数据包之后,【服务端】向【客户端】发送【FIN】包,【服务端】进入【确认关闭】状态
- 【客户端】接收到【服务端】发送的【FIN】包之后,向【服务端】 发送【ACK】包,【客户端】发送完【ACK】之后,进入【等待超时】状态
- 【服务端】接收到【ACK】之后,进入【关闭】状态
- 【客户端】过了【等待超时】状态的超时时间之后,进入【关闭】
为什么【客户端】有【等待超时】状态: 如果【服务端】最后未接收到【客户端】发送的【ACK】包、【服务端】则会重新发送【FIN】包给【客户端】,【客户端】在【等待超时】状态则会从新发送【ACK】让【服务端】的连接状态【关系】(如果【客户端】没有【等待超时】,【服务端】未接收到【ACK】包则会一直处于【确认关闭】状态)