TCP的可靠性
TCP提供了一种面向连接的、可靠的字节流服务。TCP的可靠性主要有下面方式所保证的。
- 应用数据被分割成TCP认为最适合发送的数据快。而UDP的数据报长度将保持不变。由TCP传递给IP的信息单位称为报文段。(可靠性体现在哪了?)
- 当TCP发出一个段后,它将启动一个定时器,等待目的段确认收到这个段后。如果不能及时收到一个确认,将重发这个报文段。
- 当TCP收到来自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常推迟几分之一秒。(为什么?)
- TCP将保持它首部和数据的检验和(首部正常20个字节,最多60个字节)。这是一个端到端的检验和,目的是检测数据在传输过程中的变化。如果收到的段的检验和有差错。TCP将丢弃这个报文段和不确认收到。(希望发送端超时和重传) Q:为何不去纠正而是选择重传?
- TCP报文段传输中可能会失序,如有必要的话,TCP会对收到的失序数据重新排列后交给应用层。
- TCP如果接受到重复的数据后,会丢弃它。
- TCP还能提供流量控制,TCP连接的每一方都有一个固定大小的缓冲空间。TCP只允许另一端最多发送接受端缓冲区大小的数据。这将防止发送端发的快而接受端接受的慢而造成的缓冲区溢出。
三次握手

当一端建立连接而发送它的SYN时,会为连接选择一个初始序号。ISN会随着时间而变化,因此每个连接会有不同的ISN。ISN可以看做一个32位的计数器,每4ms加1。这样可以防止在网络中延迟的分组以后又被传送,从而导致某个连接的一方对它作出错误的解释。
为什么TCP建立连接是要三次握手?而不是两次或者四次?
很多面试官喜欢问这个问题。为什么一定要三次?因为三次是建立一个可靠连接的最少所需次数。为什么两次不行呢?
TCP可靠传输的精髓在哪里?就在与建立连接的双方最开始需要将自己的初始序号告知了对方,并确保对方一定收到。以后发送和ACK确认都是在最开始的初始序号上增加,每发送一个字节,序号增加1。如果只有两次握手的话,我们来看看会发生什么。
第一次握手:执行主动连接的客户端发送自己的SYN,ISN序号过去。
第二次握手:服务端收到后,知道客户端的初始序号。发送ACK回应,同时发送自己的SYN , ISN序号。
到此两次握手结束。此时只有服务端可以确保收到客户端的初始ISN,而客户端并不一定收到服务端的初始ISN。如果服务端一方向客户端一方发送数据了怎么办?由于不知道服务端的初始ISN,客户端就无法对收到的数据ACK确认,就不能进行数据的传输了。
那为什么不能四次握手呢?因为不需要,四次握手中的第二,第三次可以合并成一次。
那为什么要四次挥手呢?四次挥手的二三两次难道不能合并吗?因为TCP支持半关闭。当一端发送FIN后执行关闭后,另一端没有关闭,那么执行关闭的一方依然可以接受到数据,要牢记TCP是全双工的。如果只有三次挥手,那么一方FIN后,另一方发送FIN,ACK,两边就都关闭了。就无法支持半关闭了。
四次挥手

TIME_WAIT等待状态
TIME_WAIT要等待一个2MSL时间,MSL是任何报文段被丢弃到网络中最大生存时间。这个时间是有限的,因为TCP报文段是以IP数据段在网络中传输的,而IP有限制其生存的时间的TTL字段。通常MSL为30秒,1分钟或者2分钟。
为什么需要等待2MSL呢?因为最后一个ACK可能会在网络传输中丢失。如果发送了最后一个MSL就立刻关闭连接的话,此时若ACK丢失,那么服务端将会一直超时重传而一直得不到回应。有了等待2MSL时间,如果最后一个ACK丢失,服务器第一次超时重传,这时客户端由于还没有关闭,就能发送ACK回应了。
TCP的状态变迁图

网友评论