一、三次握手
TCP三次握手是一个经典的面试题,它指的是TCP在传递数据之前需要进行三次交互才能正式建立连接,并进行数据传递。(客户端主动发起的)TCP之所以需要三次握手是因为TCP双方都是全双工的。
什么是全双工?
TCP任何一段既是发送数据方,又是接收数据方。因此就要求TCP双方既要保证自己的发送能力,又要保证自己的接收能力。这就好像打电话的过程:
- 我:喂!可以听到吗?
- 对方:可以听到,你能听到我说话吗?
- 我:能听到,才开始说事情
TCP的三次握手也是同样的道理,每次握手证明的能力详情如下:
三次握手的流程
- 客户端发送一个SYN给服务器,表示希望建立连接
- 服务器接收到消息之后,返回一个SYN和ACK(确认应答)给客户端
- 客户端收到SYN报文之后返回一个ACK报文
问题:为什么是三次握手,不能是四次或者两次?
四次?可以但是没有必要,分开传输降低效率,不如合在一起
两次?不行,意味着缺少最后一次此时客户端这边关于发送接收能力正常的情况是完整的,但是服务器这边是残缺的。服务器不知道自己的发送能力是否OK,也不知道客户端的接收能力怎么样。就像下面这张图:
二、四次挥手
建立一个连接需要三次握手,而终止一个连接要经过四次挥手(也有将四次挥手叫做四次握手的)。这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
四次挥手可能值客户端主动发起,也可能是服务器主动发起,中间不能合并主要原因是:
B发送ACK和发送FIN的时机是不同的
四次挥手中B给A发送的ACK是内核负责的,但是B给A发送的FIN是用户代码负责。(B中的代代码调用了关闭方法,才会触发FIN)。收到FIN内核立即返回ACK如果两者之间时间差比较大就不能合并了。如果时间差比较小,可能合并
认识两个重要的状态
CLOSE_WAIT
:四次挥手两次之后的状态,这个状态就是在等待代码当中调用socket.close
方法,来进行后续的挥手过程!正常情况下一个服务器上不应该存在大量的CLOST_WAIT
状态,如果大量存在大概率是代码的bug,关闭方法没有被执行到TIME_WAIT
:谁主动发起FIN,谁就进入该状态。起到的效果就是最后一次ACK提供重传的机会。表面看起来A发送ACK之后就没有A的事情了,按理来说A应该销毁释放资源。但是并没有直接释放而是进入TIMT_WAIT
状态。该状态等待一段时间之后,再来释放资源。等这一段时间是为了防止最后一个ACK丢包。如果最后一次ACK丢包,就意味着B过一会就要重传FIN。这也正是四次挥手需要等待2MSL的原因
三、总结
TCP需要三次握手,是因为双方都是全双工的,所以要经历三次握手才能够真正建立连接如果是两次的话,不能证明服务器的发送能力和客户端的接收能力。而需要四次挥手,是TCP的半关闭状态造成的挥手过程中会造成两个重要的状态。