三次握手
握手前
客户端和服务端都是处于连接关闭状态
服务器调用socket()后使用bind()方法绑定IP和Port
服务端进入listen状态监听端口,等待客户端连接
客户端调用socket()使用connect()函数发起连接
1.第一次握手
客户端向服务端发送一个SYN(synchronize)包
标志位:SYN,表示请求建立连接
序列号为 Seq = x(x 一般为随机数)
客户端进入SYN-SENT 阶段
等待响应,若不能连接进入CLOSED状态
2.第二次握手
服务端收到SYN包
对该包进行确认
结束 LISTEN 阶段并返回一段 TCP 报文
标志位为 SYN 和 ACK:表示能正常接收客户端发送的数据,并同意创建新连接
序号为 Seq = y,将自己的初始序列号同步给客户端
确认号为 Ack = x + 1,告诉客户端自己接收的Seq没错
进入 SYN-RECV(同步接收) 阶段
当客户端和服务端同时发送请求进入SYN-SENT,客户端会转为SYN-RECV
3.第三次握手
客户端收到SYN + ACK 包
结束SYN-SENT,返回最后一段报文
标志位为 ACK:确认收到服务器端同意连接的信号
序号为 Seq = x + 1:收到服务器端的确认号 Ack,并将其值作为自己的序号值
确认号为 Ack= y + 1:表示收到服务器端序号 seq,并将其值加 1 作为自己的确认号 Ack 的值。
进入ESTABLISHED状态
一个数据传输状态,等待数据传输
握手后
服务端结束SYN-RECV 阶段,进入 ESTABLISHED 阶段,三次握手结束
为什么要三次握手
第一次握手:确认客户端可以正常发送数据
第二次握手:确认客户端可以正常发送数据,确认服务端可以正常接收数据。
第三次握手:确认客户端可以正常发送数据,确认服务端可以正常接收数据,确认服务端可以正常发送数据,服务可以正常接收数据。
四次挥手
挥手前
客户端和服务端都处于连接状态(ESTABLISHED)
客户端调用close函数,关闭其套接字
服务器recv()函数处理close请求,进入四次挥手
第一次挥手
客户端向服务器发送一段 TCP 报文表明其想要释放 TCP 连接
标记位为 FIN,表示请求释放连接
序号为 Seq = u
客户端进入 FIN-WAIT-1 阶段,即半关闭阶段
客户端停止向服务端发送通信数据
第二次挥手
服务器接收到客户端请求断开连接的 FIN 报文
结束 ESTABLISHED 阶段,进入 CLOSE-WAIT 阶段并返回一段 TCP 报文
标记位为 ACK,表示接收到客户端释放连接的请求
序号为 Seq = v
确认号为 Ack = u + 1,表示是在收到客户端报文的基础上,将其序号值加 1 作为本段报文确认号 Ack 的值。
服务器开始准备释放服务器端到客户端方向上的连接
客户端收到服务器发送过来的 TCP 报文
客户端结束 FIN-WAIT-1 阶段,进入 FIN-WAIT-2 阶段
第三次挥手
服务器端会将遗留的待传数据传送给客户端
待传输完成后再次向客户端发出一段 TCP 报文
标记位为 FIN 和 ACK,表示已经准备好释放连接了
序号为 Seq = w
确认号 Ack = u + 1表示是在收到客户端报文的基础上,将其序号 Seq 的值加 1 作为本段报文确认号 Ack 的值。
随后服务器端结束 CLOSE-WAIT 阶段,进入 LAST-ACK 阶段
停止向客户端发送数据
第四次挥手
客户端收到从服务器发来的 TCP 报文
客户端结束 FIN-WAIT-2 阶段,进入 TIME-WAIT 阶段
客户端向服务器发送一段报文
标记位为 ACK表示接收到服务器准备好释放连接的信号;
序号为 Seq= u + 1,表示是在已收到服务器报文的基础上,将其确认号 Ack 值作为本段序号的值;
确认号为 Ack= w + 1,表示是在收到了服务器报文的基础上,将其序号 Seq 的值作为本段报文确认号的值。
挥手后
客户端开始在 TIME-WAIT 阶段等待 2 MSL
服务器端收到从客户端发出的 TCP 报文
服务器结束 LAST-ACK 阶段,进入 CLOSED 阶段。
客户端等待完 2 MSL 之后,结束 TIME-WAIT 阶段,进入 CLOSED 阶段
为什么要四次挥手
确认双方都得知双方都没有要传输的数据。
第一次挥手:客户端向服务端请求关闭连接。
第二次挥手:服务端收到客户端的请求,并且告知客户端等我处理完毕数据。
第三次挥手:服务端处理完毕数据,告知客户端,服务端数据处理完毕。
第四次挥手:客户端得知服务端数据处理完毕,双方数据都处理完毕,可断开连接。