TCP的全双工通信
TCP提供的全双工是可以一端读另一端写的,如何实现的,实际上服务端到客户端是一条通道,同时客户端到服务端又是另一条通道,首先明白这一点,然后再来看下面。
三次握手
回顾三次握手
三次握手建立连接,客户端在创建socket网络套接字后,会通过三次握手这个过程来进行连接:
- 调用connect向服务端发起连接请求,发送了一个SYN,阻塞等待服务端回复(第一次握手)
- 服务端收到客户端发送的SYN,为了让客户端知道他这准备好了,于是回了一个ACK告诉客户端我准备好了,并且发了一个SYN问客户端准备好没(第二次握手)
- 客户端收到服务端回复的ACK,进入ESTABLELISHED状态,准备就绪,并回了一个ACK给服务端说我也准备好了,服务端收到ACK确认了对方状态,于是也进入ESTABLELISHED状态,连接建立(第三次握手)
为什么是三次握手而不是两次或四次?
三次肯定是有道理的,存在即合理,三次可以让双方都确定连接到对方后能收到对方的回复,双方都准备好了。
如果是两次,那么看下面过程,仔细对比上面的三次握手:
- 客户端调用connect,发送了一个SYN,然后服务端接收这个SYN(第一次握手)
- 服务端接收之后就会返回一个ACK,那么客户端就进入ESTABLELISHED状态(第二次握手)
这其中有一个问题,那就是服务端并不知道,如果服务端发送一个消息,客户端会不会回复,如果客户端不回复,那么这个连接就是不可靠的,我服务端给你发数据,你居然不回我你收到没,那服务端怎么可能知道客户端是收到还是没收到?????
也就是说当我两次握手的时候,首先,客户端知道他到服务端的那条通道已经通了,但是服务端到客户端的那条通道,服务端不知道通没通,所以服务端也要回一个SYN,而不是光返回一个ACK,由客户端回复的ACK确认服务端到客户端的通道是否是通的。
所以要一开始就需要第二次握手服务端在返回ACK时,同时返回一个SYN,来确定客户端会回我服务端的消息,那我才能确定连接成功了。
至于四次,我三次就能建立连接成功了,还来一次握手,要是哪天客户端来个第四次握手,那我估计服务端要骂客户端傻逼了。。。。
四次挥手
回顾四次挥手
如果客户端没有请求了,主动关闭,那么便会调用close关闭连接
- 客户端调用close,发送了一个FIN包给服务端,告诉服务端要断开了(第一次挥手)
- 服务端收到FIN后,告诉客户端我知道了要断开连接了,于是发了一个ACK给客户端,同时recv(或read)会返回0(第二次挥手)
- recv和read返回0,于是服务端也调用了close关闭套接字问价,并给客户端发了一个FIN包,告诉客户端我也要关了(第三次挥手)
- 客户端收到FIN,回了一个ACK,说我知道了,断了吧(第四次挥手)
为什么是四次挥手,不是三次或五次?
首先,主动关闭方是会先发送FIN包给被动关闭方的,这个主动关闭方可能是客户端也可能是服务端,只不过大部分的情况都是客户端主动关闭。
那为啥是四次???我们以客户端主动关闭举例
首先我们已经知道了TCP的连接是全双工的,有两条通道,这两条通道,主动关闭方发送FIN,告诉被动方我要断了,被动方回一个ACK,主动方收到后就断开了,那么客户端到服务端这条通道就算断开了。
但是被动方也就是服务端仍然可以给主动方发消息的,也就是说服务端到客户端那条通道没有断开,等到服务端这一端数据发完了,这条通道也就需要关闭了,所以服务端也发了一个FIN包,告诉客户端我工作做完了,我也要关了,等到服务端收到客户端的ACK或者超出等待时间那么就断开连接。
三次的话如果类比三次握手,在第二次挥手的时候直接发FIN + ACK明显不合理,因为被动方可能没有数据发送完,你这么关太草率了,所以需要四次,至于五次,四次就能断开了,还来五次。。。多此一举。。