1. 三次握手
第一次握手都由客户端发起
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
注意三次握手只是用来建立连接用的,和TCP可靠稳定没有关系,TCP的可靠是通过重传和检错等机制实现的。
默认创建一个socket后,只拥有主动连接的能力(客户机)。要想拥有服务器接收外来的连接的能力,服务器必须准备好接受外来的连接,必须通过调用socket
、bind
和listen
函数来完成,称为被动打开(passive open)。
初始时客户端和服务器都处于CLOSED状态,当服务器应用程序创建一个监听套接字时,服务器处于LISTEN状态。
一旦服务器进入监听状态,就会创建一个三次握手的服务队列,等待接收客户端的连接请求。
1.1 过程
三次握手的流程如下所述:
- 第一次握手:客户通过调用connect进行主动打开(active open)。这引起客户TCP发送一个SYN(表示同步)分节(SYN=J),它告诉服务器客户将在连接中发送到数据的初始序列号。并进入SYN_SEND状态,等待服务器的确认。
- 第二次握手:服务器必须确认客户的SYN,同时自己也得发送一个SYN分节,它含有服务器将在同一连接中发送的数据的初始序列号。服务器以单个字节向客户发送SYN和对客户SYN的ACK(表示确认),此时服务器进入SYN_RECV状态。
- 第三次握手:客户收到服务器的SYN+ACK。向服务器发送确认分节,此分节发送完毕,客户服务器进入ESTABLISHED状态,完成三次握手。
第一次握手:客户端发送SYN握手包(seq:a),进入等待服务器应答的状态(SYN_SEND)
第二次握手:服务器在收到客户端发送的握手包之后,给客户端回复一个ACK(ack:a+1),还有一个握手包SYN(seq:b),进入等待接收的状态(SYN_RECV)
第三次握手:客户端在收到服务器发送的握手包以及确认包之后,给服务器再回复一个确认包ACK(seq:a+1,ack:b+1)
类比打电话的过程:
第一次握手:喂,能听见我说话吧?
第二次握手:能听见你说话,你能听见我说话不?
第三次握手:能听见
开始通话
需要注意的是:第一次握手和第二次握手都只是消耗掉一个序号,但不能携带数据;第三次握手可以携带数据。
发送一次数据都要有序列号,但是不一定有应答号,只有这一次的数据中有应答包时才会有应答号。
未连接队列:在三次握手协议中,服务器维护一个未连接队列,该队列为每个客户端的SYN包(syn=j)开设一个条目,该条目表明服务器已收到SYN包,并向客户发出确认,正在等待客户端确认包。这些条目所标识的连接在服务器处于SYN_RECV状态,当服务器收到客户端确认包时,删除该条目,服务器进入ESTABLISHED状态。
1.2 为什么需要三次握手
三次握手的作用:
(1)确认双方的接受能力、发送能力是否正常。
(2)指定自己的初始化序列号,为后面的可靠传送做准备。
三次握手的目的是什么?
第一次握手:客户端给服务器发送一个报文,告知服务器:“我客户端想和你建立连接”。
服务器收到第一段报文后得出结论:客户端发送功能正常,服务器接收功能正常。
第二次握手:服务器收到报文后给客户端回复一个报文,告知客户端:“我服务器收到了你的请求,同意和你建立连接”。
客户端收到第二段报文后得出结论:客户端发送和接收功能都正常,服务器的发送接收功能也都正常。(但此时服务器不能确认客户端的接收功能和自己的发送功能是否正常)。
第三次握手:客户端收到第二段报文后给服务器回复一个报文,告知服务器:“我客户端收到了你的回复,知道你同意连接,那我们开始连接吧!”
服务器收到第三段报文后得出结论:客户端的接收功能和服务器的发送功能也都正常。
所以当服务器收到第三个报文后,两边就建立起了TCP连接。
两次握手为什么不行?
那么两次握手为什么不行就显而易见了,只有前两次握手的话,服务器就不能确认自己回复的报文段是否被客户端接收到,也就不知道自己的发送功能和客户端的接收功能是否正常。、
两次握手只能保证单向连接是畅通的。因为TCP是一个双向传输协议,只有经过第三次握手,才能确保双向都可以接收到对方的发送的数据。
2. 四次挥手
四次挥手既可以由客户端发起,也可以由服务器发起
四次挥手也就是客户端与服务器断开连接时,需要一共发送四个报文段来完成断开TCP连接。
1.第一次挥手:客户端发送一个FIN报文段,报文段中指定序号seq=u。此时客户端处于FIN_WAIT_1状态。
2.第二次挥手:服务器收到FIN报文后,立即发送一个ACK报文段,确认号为ack=u+1,序号设为seq=v。表明已经收到了客户端的报文。此时服务器处于CLOSE_WAIT状态。
在第二次挥手和第三次挥手之间的时间段内,由于只是半关闭的状态,数据还是可以从服务器传送到客户端的。
3.第三次挥手:如果数据传送完毕,服务器也想断开连接,那么就发送一个FIN报文,并重新指定一个序号seq=w,确认号还是ack=u+1,表明可以断开连接。
4.第四次挥手:客户端收到报文后,一样发出一个ACK报文段做出应答,上一次客户端发送的报文段序号为u,那么这次序号就是seq=u+1,确认号为ack=w+1。此时客户端处于TIME_WAIT状态,需要经过一段时间确保服务器收到自己的应答报文后,才会进入CLOSED状态。
类比挂电话的过程:
第一次挥手:我说完了,我要挂了
第二次挥手:好的,我知道了,但是你先别急,等我把话说完
第三次挥手:好了,我说完了,咱们可以挂电话了
第四次挥手:好的,挂了吧