> 文章列表 > Java EE|TCP/IP协议栈之TCP协议工作机制上

Java EE|TCP/IP协议栈之TCP协议工作机制上

Java EE|TCP/IP协议栈之TCP协议工作机制上

文章目录

    • 前言
    • 一、确认应答
    • 二、超时重传
    • 三、连接管理
      • 三次握手
      • 四次挥手

前言

前边,我们已经大概交代了TCP的报文结构。但是仍有一些字段我们不确定到底怎么理解,这里就分析TCP的内部工作机制了。

TCP的内部很复杂,有很多机制,这里我们只讨论比较核心的10个机制。

本篇,我们先介绍前3个。

一、确认应答

对于这个机制,我们需要了解以下几点:

  1. TCP中,确认应答是实现可靠传输的核心机制。
  2. 这里的可靠传输,不是说我们发的报文一定传输过去了,而是说对于报文发送成功与否,发送方都会收到一个信号,告诉我们。
  3. 这里的信号就是我们前边提到的六个标志位其一——ack(acknowledge)。它是由接收方发送的。倘若报文带有这条标志,那么我们就可以认为我们发送成功了。此时这个报文也叫做应答报文。
  4. 特殊情况:短时间内连续发送消息,可能出现后发先至的情况。原因是两个主机之间存在多条线路,转发效率也会有所不同。
  5. 如何规避后发先至:给传输的数据和应答报文都进行编号,即使乱了也知道如何进行排序。这里的功能就是通过我们的32位序号和32位确认序号来实现的。

下边,我们就后发先至的规避做进一步的解释:

  • 任何数据都有序号,而确认序号只有应答报文的有效。

  • TCP是面向字节流的,所以这里的编号不是按照第一条、第二条……的方式编号的,实际上也是按照字节流进行编号的。

    这里可能会比较抽象,我们图解一下。
    在这里插入图片描述

为了加深印象,我们这里举个小例子

Java EE|TCP/IP协议栈之TCP协议工作机制上

小结:TCP可靠传输能力,最主要的就是通过应答机制保证通过应答报文,就可以让发送方清楚的知道,传输是否成功,进一步通过序号和确认序号对应答报文的顺序进行说明。

二、超时重传

上边的例子里边我们是基于发送成功的前提下进行讨论的,倘若发送失败了呢?TCP采取怎样的策略应对呢?这也就是我们接下来要说的超时重传。

这里我们需要知道一下几个点

  1. 发送失败即丢包,有两种情况。一是发的数据包丢了,二是接收方返回的ack丢了。这里发送方看到的效果就是结果丢了,它会一视同仁,认为是丢包了。
  2. TCP重传引入了一个时间阈值。发送后就会等待ack,进行计时。具体时间根据业务而定。
  3. 重传机制是在丢包后会重新发送n次同样的数据。但是这里的n也不会太大,太大也没有意义。因为连续重传都丢,概率很低(乘法公式)
  4. 重传达到一定次数,不会继续重传,会认为是网络出现故障,接下来TCP会尝试断开重连,若重置还失败就彻底断开。
  5. **对于重传由特殊处理——去重。**TCP存在“接收缓冲区”和发送缓冲区这样的存储空间。主机B收到主机A的数据,其实是B的网卡读到了数据,把这个数据放到了socket/网卡的接收缓冲区【优先级阻塞队列】中。根据数据的序号,TCP很容易识别当前接收缓冲区里的两条数据是不是重复【根据序号进行排序,若相同就去重】。若重复,则把后来这份data丢弃了,保证app调用read读取的数据一定是不重复的。

小结:由于去重和重新排序发送方只发现ack未按时到达,就会触发重传机制。即使重复发送了也没关系,接收方能处理好,去重和排序都依赖于TCP报头的序号。

确认应答和超时重传机制两者相互配合,共同支撑了可靠传输。

注:不是说只有这两个,而是说这两个是最重要的,是支柱一样的存在。

三、连接管理

这里的连接是connection,不是链接link。注意进行区分。前者是AB建立连接,互相记录对方的信息(例如端口号),后者是快捷方式。

Java EE|TCP/IP协议栈之TCP协议工作机制上

注意:这里虽然网络层的ip协议是在传输层下边,但ip的获得跟位置无关,因为它相当于是经过了一个u型的过程。

这里的管理描述了连接如何创建,如何断开。也就是我们经常说的三次握手四次挥手。这也是我们这里要讨论的超级重重点内容!!!

三次握手

Java EE|TCP/IP协议栈之TCP协议工作机制上
所以实际的例子效果应该是这样滴

Java EE|TCP/IP协议栈之TCP协议工作机制上

  • 这里我们有一个问题,不合并可以不?

    答:不可以,因为封装分用(一条报文从发送到接收)有开销,合并后成本降低,OS也不是冤大头。

  • 那么问题又来了,怎么确定合并了呢?

    答:合并后接收方收到的效果是一条,只不过有两个作用。具体细节略过。

  • 可以只两次握手吗?

    答:不可以,这个确认是双方的,双方的发送能力、接受能力都需要被确认!!

相信通过这个例子,我们已经能理解个七七八八了,下边我们就看看教科书上的真正的三次握手的过程。

Java EE|TCP/IP协议栈之TCP协议工作机制上

对于这里的状态,我们不做过多讨论,只记住几个常见的即可。其中established(已连接的)、listen(服务器状态)表明服务器已准备就绪,随时可与客户端建立连接。

三次握手的意义:

  1. 让通信双方各自建立对对方的认同
  2. 验证通信双方各自发送和接受能力是否正常
  3. 通信双方协商一些重要参数

小结

所谓的三次握手本质上是四次交互,通信双方各自向对方发起一个建立连接的请求,同时再向对方发一个ack。

三次握手的流程(一般是进行图解)

三次握手的意义

四次挥手

三次握手就是建立连接,与之对应的,四次握手就是断开连接。
Java EE|TCP/IP协议栈之TCP协议工作机制上

下边我们基于这个图,具体来讨论四次挥手的过程及作用。

对于服务器:

ESTABLISHED -> CLOSE_WAIT: 当客户端主动关闭连接(调用close),服务器会收到结束报文段,服务器返回确认报文段并进入CLOSE_WAIT;
CLOSE_WAIT -> LAST_ACK:进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据);当服务器真正调用close关闭连接时,会向客户端发送FIN,此时服务器进入LAST_ACK状态,等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)
LAST_ACK -> CLOSED: 服务器收到了对FIN的ACK,彻底关闭连接。

对于客户端:

已连接到FIN_WAIT1状态:客户端主动调用close时,向服务器发送结束报文段,同时进入FIN_WAIT_1 。

FIN_WAIT_1 -> FIN_WAIT_2 :站在客户端角度,客户端收到服务器对结束报文段的确认,则进入FIN_WAIT_2,开始等待服务器的结束报文段 。

FIN_WAIT_1 -> TIME_WAIT:客户端收到服务器发来的结束报文段,进入TIME_WAIT,并发出LAST_ACK。

TIME_WAIT -> CLOSED :客户端要等待一个2MSL(Max Segment Life,报文最大生存时间)的时间,才会进入CLOSED状态 。避免中间出现意外。

____________________________________

这里的TIME_WAIT是额外工作的保障,一定程度上解决了丢包这样的情况。

____________________________________

【中间流程,状态只是中间流程的结果】

试想,这个和三次握手的四次交互不是挺像的吗?这里不可以中间合并吗?如果不能合并,为什么?

不能。原因是ACK的发送是由内核控制的,FIN的发送是由应用调用socket的close方法,进程退出才会触发FIN。

两者的发送很大概率不是同一时机。所以绝大多数情况下是不会同时发送。所以我们将其认为是不可合并的。

这里的TIME_WAIT约定的时间是2MSL,具体是多长?不会太短了吗?

TIME_WAIT这个数值的含义是互联网上两个节点之间数据传输消耗的最大时间。

而这里的2MSL并不是不变的,MSL是可以自己设定的,但是实际开发过程中我们一般把它设置成一个经验值——60秒,那么对于这里的2MSL就是120秒。

小结:

TCP作为一个有连接的协议,需要建立连接和断开连接,其中建立连接时三次握手,断开连接时四次挥手。

三次握手的意义:双方建立认同感;确认双方发送接收能力没有问题;协商通信过程的一些关键参数。

四次挥手不可以合并成三次挥手的原因。

TIME_WAIT意义和作用。