草庐IT

TCP 协议特性详解

OAYY 2024-02-20 原文

TCP 协议特性总结

TCP协议特点

TCP协议具有 有连接,可靠传输,面向字节流,全双工的特点

TCP协议段格式


TCP报文=TCP报头(首部)+TCP载荷

  • 源/目的端口号:表示数据是从哪个进程来,到哪个进程去;
  • 32位序号/32位确认号:针对多组数据进行详细区分
  • 4位首部长度:描述TCP报头具体的长度(TCP报头长度可变,UDP报头长度不可变,固定8个字节)

注意:4位首部长度的单位不是字节,而是4字节,所以TCP报头最大长度是15 * 4 = 60字节

  • 6位保留:为了以后的扩展考虑

对于网络协议来说,扩展升级,是一件成本极高的事情,后续TCP引入一些新功能的时候,就可以使用这些保留位字段

  • 6位标志位
    • URG:紧急指针是否有效
    • ACK:确认号是否有效
    • PSH:提示接收端应用程序立刻从TCP缓 冲区把数据读走
    • RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段
    • SYN:请求建立连接;我们把携带SYN标识的称为同步报文段
    • FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段
  • 16位窗口大小:
  • 16位检验和:与UDP检验和作用相同:都是验证数据传输是否正确,但是不能保证数据安全性
  • 16位紧急指针:标识哪部分数据是紧急数据;
  • 选项:选项之前的部分是固定长度(20字节)(公式 :选项长度=首部长度-20字节)

如果首部长度值是5,表示整个TCP报头长度是20字节(5x4字节)(相当于没有选项)
如果首部长度值是15,表示整个TCP报头长度是60字节(15x4字节)(选项相当于是40字节)

TCP原理

确认应答(安全机制)

示例图:
A给B发了个消息,B收到后就会返回一个应答报文(ACK),此时A收到应答之后,就知道刚才发的数据已经顺利被B接收。

考虑更复杂的情况
示例图:
由于网络上可能存在“后发先至”,收到消息的顺序是可能存在变数的,变成了“去吃饭不?:不好”,“去学习不?:好”,这就跟原义不符。

为了解决上述后发先至问题,给传输的数据,和应答报文,都进行编号。
示例图:
这样就可以通过序号来区分当前应答报文是针对那个数据进行的

判断一条报文是否是应答报文,取决于其报头中ACK标志位,如果ACK这个标志位为1,则是应答报文,为0,则不是。

实际上,由于TCP是面向字节流的,TCP的序号也是按照字节来编号的

TCP的字节的序号是依次累加的,每个TCP数据报报头填写的序号只需要写TCP数据的头一个字节的序号即可。
TCP知道了头一个字节的序号,再根据TCP报文长度,就很容易知道每个字节的序号。

确认序号的取值,是收到的数据的最后一个字节的序号+1

例如:确认序号为1001
表示的含义:
1.<1001的数据都已经确认收到了。
2.A接下来应该从1001这个序号开始继续发送(B向A索要1001的数据)

小结:TCP可靠传输能力,最主要就是通过确认应答机制来保证,通过应答报文ACK),就可以让发送方清楚的知道传输是否成功,进一步的引入了序号确认序号,针对多组数据进行详细的区分

超时重传(安全机制)

上述讨论确认应答的时候,只是讨论了顺利传输的情况,并未讨论传输出现问题的情况(例如丢包)
以下是丢包的两种情况

第一种情况:数据丢失

  • 主机A发送数据给B之后,可能因为网络拥堵等原因,数据无法到达主机B;
  • 如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发

第二种情况:ACK丢失

第二种情况重传数据,可能会导致主机B收到很多重复数据。TCP就要对其进行去重以及重新排列。

TCP存在一个“接收缓冲区”这样的存储空间(接收方操作系统内核里的一段内存),每个TCP的socket对象,都有一个接收缓冲区。
主机B收到主机A的数据,其实是B的网卡读到数据,并将这个数据放到B的对应socket的接收缓冲区中,后续应用程序使用getInputStream,进一步使用read从接收缓冲区中读取数据。
TCP使用这个接收缓冲区,根据数据的序列号识别是否有数据重复,如果重复,将后来的数据舍去,并对收到的数据进行重新排序。

小结:由于去重和重新排序机制(都依赖于TCP报头的序号)的存在,发送方只要发现ACK没有按时到达,就会重传数据,即使重复了,顺序乱了,接收方都能很好地处理。

TCP的可靠传输就是通过确认应答+超时重传来进行体现的。
其中确认应答描述的是传输顺利的情况,
超时重传描述的是传输出现问题的情况。

连接管理(安全机制)(面试高频题)

在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接

三次握手

建立连接阶段的几种状态:
1.LISTEN
监听对方建立连接请求,表示服务器已经准备就绪,随时可以有客户端来建立连接,相当于手机开机,信号良好,随时可以接听他人的电话。

2.SYN_SEND:属于请求连接,此时发送的报文段,不能携带数据
3.SYN_RECEIVE:接收到对方的连接建立请求。

4.ESTABLISHED
连接建立完成,接下来可以进行正常通信,相当于拨打电话,对方接通。当客户端在此状态下,发送的ACK报文段可以携带数据,

所谓的三次握手,本质上是“四次”交互。
通信双方,各自要向对方发起一个“建立连接”的请求,同时,再各自向对方回应一个ack。中间两次交互是可以合并成一次交互的,因此就构成了“三次握手”。

问题一:为什么要将中间两次交互合并?
答案:和封装分用相关,封装分用两次比封装分用一次成本更高。

问题二:如果是两次握手能否建立连接的过程?
答案:不可以。
第一次握手:客户端发送网络包,服务端收到。
服务端可知:客户端的发送能力,服务端的接收能力正常。
第二次握手:服务端发送网络包,客户端收到。
客户端可知:客户端的发送能力,接收能力正常。服务端的发送能力,接受能力正常。但是此时服务端并不知道自己的发送能力是否正常。
第三次握手:客户端再次发送网络包,服务端收到。
服务端可知:客户端发送能力,接受能力正常。服务端的发送能力,接受能力正常。
因此,需要三次握手才能确认双方的接收与发送能力是否正常

三次握手的意义
1.让通信双方各自建立对对方的“认同”
2.验证通信双方各自的发送能力和接收能力是否正常
3.在握手的过程中,双方需要协商一些重要的参数,来完成数据的同步。
建立连接阶段

四次挥手

四次挥手和三次握手非常类似,都是通信双方各自向对方发起一个断开连接的请求,在各自给对方一个回应。

建立连接阶段的几种状态
1.FIN_WAIT_1:客户端主动调用close时,向服务器发送结束报文段(FIN),同时进入FIN_WAIT_1;

2.CLOSE_WAIT:(出现在被动发起断开连接的一方)
当客户端主动关闭连接(调用close),服务器会收到结束报文段(FIN),服务器返回确认报文段(ACK)并进入CLOSE_WAIT;

3. FIN_WAIT_2:客户端收到服务器对结束报文段的确认(ACK),则进入FIN_WAIT_2,
开始等待服务器的结束报文段(FIN);
4. LAST_ACK:进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据);当服务器真正调用close关闭连接时,会向客户端发送FIN,此时服务器进入LAST_ACK状态,等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)

5.TIME_WAIT:(出现在主动发起断开连接的一方)
假设是客户端主动断开连接,当客户端进入TIME_WAIT状态的时候,相当于四次挥手已经挥完了,客户端收到服务器发来的结束报文段(FIN),进入TIME_WAIT,并发出LAST_ACK;

【TIME_WAIT -> CLOSED】客户端要等待一个2MSL(报文最大生存时间)的时间,才会进入CLOSED状态。

6.服务器收到了对FIN的ACK,彻底关闭连接,进入CLOSED状态

TIME_WAIT的意义:四次挥手与三次握手一样,也会出现丢包的情况,当服务器未收到最后一个ACK,就会进行重传操作,因此使用TIME_WAIT状态保留一定时间,是为了处理最后一个ACK丢包的情况,能够在收到服务器重传的FIN之后,客户端能够针对这个重传的FIN进行ACK响应。

问题一:为什么三次握手的中间两次j交互能够合并,而四次挥手不能合并?
答案:

  • 三次握手这三次交互过程,是纯内核中完成的,服务器的系统内核收到SYN之后,就会立即发送ACK,也会立即发送SYN,同一时机,所以能够合并。
  • 四次挥手中FIN的发起,不是由内核控制的,而是由应用程序调用socket的close方法(或者进程退出)才会触发FIN,ACK则是由内核控制,当接收到发送方发来的FIN之后,就会立即返回ACK,这两者之间通常情况下会有个时间差,因此无法合并。

问题二:想一想,为什么是TIME_WAIT的时间是2MSL
MSL是TCP报文的最大生存时间,因此TIME_WAIT持续存在2MSL的话
就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启,可能会收到来自上一个进程的迟到的数据,但是这种数据很可能错误的);
同时也是在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失,那么服务器会再重发一个FIN。这时虽然客户端的进程不在了,但是TCP连接还在,仍然可以重发LAST_ACK);

问题三:服务器上出现大量的 CLOSE_WAIT 状态,是什么原因?
答案:服务器没有正确的关闭 socket,导致四次挥手没有正确完成。这是一个 BUG。只需要加上对应的 close 即可解决问题

滑动窗口(效率机制)

上述讨论的确认应答策略,对每一个发送的数据段,都要给一个ACK确认应答。收到ACK后再发送下一个数据段。这样做使得性能较差。

此时就要引用滑动窗口机制来提高性能
具体操作:批量发送,批量等待,使用一份等待时间来等待一组数据的多个ACK,本质上就是降低确认应答等待ack消耗的时间。

窗口大小:无需等待确认应答而可以继续发送数据的最大值,上图窗口大小就是4000;

  • 发送前四个段的时候,不需要等待任何ACK,直接发送;
  • 收到第一个ACK后,滑动窗口向后移动,继续发送第五个段的数据;依次类推;

下面是针对丢包的两种情况进行的讨论
情况一:数据包已经抵达,ACK丢了。

这种情况下,部分ACK丢了并不要紧,因为可以通过后续的ACK进行确认;

情况二:数据包就直接丢了。

  • 当某一段报文段丢失之后,发送端会一直收到1001这样的ACK,是在提示发送端1001-2000的数据并没有接收到,应将对应的数据1001-2000重新发送。
  • 这个时候接收端收到了 1001 之后,再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就已经收到了,被放到接收缓冲区中。

上述机制也被称为“快速重传机制”。

流量控制(安全机制)

流量控制是一种干预发送窗口大小的机制

问题一:为什么要控制窗口大小?

  • 窗口太大,会消耗大量的系统资源
  • .窗口太大,完全不等待ack,就无法保证可靠性
  • .要考虑接收方的处理能力

问题二:TCP协议段格式中,16位窗口大小是否意味着窗口大小最大是64kb呢?
答案:不是,TCP通过在选项部分引入窗口扩展因子M,使得实际窗口大小是 窗口字段的值左移 M 。

流量控制的工作就是根据接收方的处理能力(通过查看接收方接受缓冲区的剩余大小),来协调发送方的发送速率

发送端给接收端发送数据,接收端查看自身接收缓冲区剩余大小,并将这个值通过ACK报文返回给发送端,发送端会根据这个数字来确认下一轮发送的窗口大小。
当窗口大小为0时,发送方就要暂停发送,暂停发送的等待过程中,会给接收端定期发送窗口探测报文,这个报文不携带具体的业务数据,只是为了触发ack,查询窗口大小。

注意:窗口大小是“发送方”的概念,是通过接收方的ack报头里的窗口大小字段来告诉给发送方的。

拥塞控制(安全机制)

流量控制考虑的是接收方的处理能力,接下来讲述的拥塞控制则是考虑传输过程中中间节点的处理能力,二者共同决定发送方的窗口大小(二者较小值)

拥塞控制,本质上就是通过实验的方式,来逐渐找到一个合适的窗口大小。

  • 0轮时窗口大小是1单位,已非常慢的速度发送数据,如果传输顺利,就使窗口大小扩大一倍。
  • 初始阶段,由于初始窗口比较小,每一轮不丢包就会使窗口大小扩大一倍(指数增长)。
  • 当增长速率达到阈值后,此时指数增长,就转化为线性增长(前提是不丢包的情况)。
  • 当传输过程中一旦出现丢包,说明此时发送的速率已经接近网络的极限,这时就把窗口大小一下缩成很小的值(重复上述指数增长和线性增长的过程)
    拥塞窗口不是固定数值,而是一直动态变化的。

TCP是个非常复杂的协议,不仅仅只有上述提到的特性!!!如果想了解更多TCP特性,可以去翻阅RFC标准文档。

有关TCP 协议特性详解的更多相关文章

  1. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  2. ruby - HTTP POST 上的 SSL 错误(未知协议(protocol)) - 2

    尝试通过SSL连接到ImgurAPI时出现错误。这是代码和错误:API_URI=URI.parse('https://api.imgur.com')API_PUBLIC_KEY='Client-ID--'ENDPOINTS={:image=>'/3/image',:gallery=>'/3/gallery'}#Public:Uploadanimage##args-Theimagepathfortheimagetoupload#defupload(image_path)http=Net::HTTP.new(API_URI.host)http.use_ssl=truehttp.verify

  3. 物联网MQTT协议详解 - 2

    一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su

  4. Tcl脚本入门笔记详解(一) - 2

    TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是

  5. 网络实验之RIPV2协议(一) - 2

    一、RIPV2协议简介  RIP(RoutingInformationProtocol)路由协议是一种相对古老,在小型以及同介质网络中得到了广泛应用的一种路由协议。RIP采用距离向量算法,是一种距离向量协议。RIP-1是有类别路由协议(ClassfulRoutingProtocol),它只支持以广播方式发布协议报文。RIP-1的协议报文无法携带掩码信息,它只能识别A、B、C类这样的自然网段的路由,因此RIP-1不支持非连续子网(DiscontiguousSubnet)。RIP-2是一种无类别路由协议(ClasslessRoutingProtocol),支持路由标记,在路由策略中可根据路由标记对

  6. 【详解】Docker安装Elasticsearch7.16.1集群 - 2

    开门见山|拉取镜像dockerpullelasticsearch:7.16.1|配置存放的目录#存放配置文件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/config#存放数据的文件夹mkdir-p/opt/docker/elasticsearch/node-1/data#存放运行日志的文件夹mkdir-p/opt/docker/elasticsearch/node-1/log#存放IK分词插件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/plugins若你使用了moba,直接右键新建即可如上图所示依次类推创建

  7. 【Elasticsearch基础】Elasticsearch索引、文档以及映射操作详解 - 2

    文章目录概念索引相关操作创建索引更新副本查看索引删除索引索引的打开与关闭收缩索引索引别名查询索引别名文档相关操作新建文档查询文档更新文档删除文档映射相关操作查询文档映射创建静态映射创建索引并添加映射概念es中有三个概念要清楚,分别为索引、映射和文档(不用死记硬背,大概有个印象就可以)索引可理解为MySQL数据库;映射可理解为MySQL的表结构;文档可理解为MySQL表中的每行数据静态映射和动态映射上面已经介绍了,映射可理解为MySQL的表结构,在MySQL中,向表中插入数据是需要先创建表结构的;但在es中不必这样,可以直接插入文档,es可以根据插入的文档(数据),动态的创建映射(表结构),这就

  8. 计算机网络笔记:TCP三次握手和四次挥手过程 - 2

    TCP是面向连接的协议,连接的建立和释放是每一次面向连接的通信中必不可少的过程。TCP连接的管理就是使连接的建立和释放都能正常地进行。三次握手TCP连接的建立—三次握手建立TCP连接①若主机A中运行了一个客户进程,当它需要主机B的服务时,就发起TCP连接请求,并在所发送的分段中用SYN=1表示连接请求,并产生一个随机发送序号x,如果连接成功,A将以x作为其发送序号的初始值:seq=x。主机B收到A的连接请求报文,就完成了第一次握手。客户端发送SYN=1表示连接请求客户端发送一个随机发送序号x,如果连接成功,A将以x作为其发送序号的初始值:seq=x②主机B如果同意建立连接,则向主机A发送确认报

  9. 最强Http缓存策略之强缓存和协商缓存的详解与应用实例 - 2

    HTTP缓存是指浏览器或者代理服务器将已经请求过的资源保存到本地,以便下次请求时能够直接从缓存中获取资源,从而减少网络请求次数,提高网页的加载速度和用户体验。缓存分为强缓存和协商缓存两种模式。一.强缓存强缓存是指浏览器直接从本地缓存中获取资源,而不需要向web服务器发出网络请求。这是因为浏览器在第一次请求资源时,服务器会在响应头中添加相关缓存的响应头,以表明该资源的缓存策略。常见的强缓存响应头如下所述:Cache-ControlCache-Control响应头是用于控制强制缓存和协商缓存的缓存策略。该响应头中的指令如下:max-age:指定该资源在本地缓存的最长有效时间,以秒为单位。例如:Ca

  10. IDEA 2022 创建 Spring Boot 项目详解 - 2

    如何用IDEA2022创建并初始化一个SpringBoot项目?目录如何用IDEA2022创建并初始化一个SpringBoot项目?0. 环境说明1.  创建SpringBoot项目 2.编写初始化代码0. 环境说明IDEA2022.3.1JDK1.8SpringBoot1.  创建SpringBoot项目        打开IDEA,选择NewProject创建项目。        填写项目名称、项目构建方式、jdk版本,按需要修改项目文件路径等信息。        选择springboot版本以及需要的包,此处只选择了springweb。        此处需特别注意,若你使用的是jdk1

随机推荐