您现在的位置是:首页 > 正文

TCP协议面试常问知识点,倾心总结

2024-04-01 04:15:09阅读 1

TCP协议段格式

首先一点必须知道TCP协议三个特点:面向连接、可靠传输、面向字节流。可靠传输是有确认应答机制、超时重传机制、滑动窗口机制、拥塞避免控制机制、捎带应答机制和延时应答机制保障的,下文将详细说明。
TCP全称为 “传输控制协议(Transmission Control Protocol”). 人如其名, 要对数据的传输进行一个详细的控制;
在这里插入图片描述
16位源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去,都是2字节,uint_16的整数;
16位校验和: 发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含TCP首部, 也
包含TCP数据部分.
16位紧急指针: 标识哪部分数据是紧急数据;

32位序号:保存的是消息发送方维护的序号;
32位确认号: 期望对端发送数据的时候从哪一个序号开始;
4位首部长度: 含义是4个比特位,最大值是15,但这并不是真实的TCP报头的长度,而是一个数值,真正的TCP报头长度 = 4位首部长度计算出来的值 * 4(单位字节) 也就是说最大值为60
6位标志位:

  • URG: 紧急指针是否有效;
  • ACK: 确认号是否有效;
  • PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走;
  • RST: 对方要求重新建立连接; 我们把携带RST标识的称为复位报文段;
  • SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段;
  • FIN: 通知对方, 本端要关闭了, 我们称携带FIN标识的为结束报文段;

16位窗口大小: 讲滑动窗口详细说;
40字节头部选项: 可以加上一些选项,例如MSS:最大报文段长度;

三次握手和四次挥手

三次握手须知 : 1 数据包名称 2 双方连接状态 3 包序管理;连接状态在后文讲述。
四次挥手须知 : 1 双发包名称 2 双方连接状态;连接状态在后文讲述。
在这里插入图片描述

在TCP连接中客户端和服务端各维护一套序号,范围都是:(0~2^32),在三次握手的时候,起始序号都是随机的;
包序管理:

  1. TCP连接双发总共维护两套序号,客户端一套,服务端一套;
  2. 客户端在发送数据的时候,消耗的是客户端维护的序号,在回复ACK的时候,是确认服务端的序号;
  3. 服务端在发送数据的时候,消耗的是服务端维护的序号,在回复ACK的时候,是确认客户端的序号;
  4. 纯ACK数据包不消耗序号。

1. 三次握手:

在这里插入图片描述
第一次:SYN(seq=0):首先客户端告诉服务端自己的起始序号是从0开始的,并发送给服务端一个SYN报文,并且客户端消耗掉了0;
第二次:ACK(ack=1)+SYN(seq=0):ack=1,服务端确认收到了客户端发送的SYN报文,而客户端发送SYN报文的序号为0,确认的时候告诉客户端,你维护的序号为0的数据我收到了,seq=0,并且服务端告诉客户端自己的起始序号是从0开始的,也就是消耗掉了0,下次期望你的序号从1开始发送;
第三次:ACK(ack=1,seq=1):ack=1,客户端告诉服务端确认序号为0的数据包,并且告诉接下里期望服务端给自己发送的序号从1开始。seq=1,客户端维护的序号是1,由于发送纯ACK报文不消耗序号,所以并没有消耗掉这个序号。

2. 发送数据

在这里插入图片描述
第一次:PSH(seq=1,ack=1),seq=1是客户端发送数据的起始序号,客户端发送一条数据为i am client,数据长度位11字节。
第二次:ACK(seq=1,ack=12),seq=1是服务端发送数据的起始序号,ack=12是因为服务端收到了客户端发送的前11个字节的数据,期望客户端下次发送数据的时候序号是从12开始的。
第三次:PSH(seq=1,ack=12),因为发送纯ACK不消耗序号,因此这次服务端给客户端发送的序号和上次一样。但是发送了数据i am server,数据长度是11。
第四次:ACK(seq=12,ack=12), seq=12是客户端给服务端回复的,ack=12是服务端希望客户端下次发送数据的序号。

3. 四次挥手

在四次挥手描述的时候,一定不要说客户端和服务端,要说主动断开连接方和被动断开连接方。
第一次:主动断开连接方发送一个断开连接报文(FIN)给被动断开连接方。
第二次:被动断开连接方发送一个确认应答报文(ACK)给主动断开连接方。
第三次:被动断开连接方发送一个断开连接报文(FIN)给主动断开连接方。
第四次:主动断开连接方发送一个确认应答报文(ACK)给被动断开连接方。

确认应答(ACK)机制

当发送方发送一个报文的时候,需要带上序号,当我们接收发收到这个报文的时候,需要对该报文进行确认;确认的具体做法是给发送方发送一个确认报文ACK,而确认报文当中的确认序号就是告诉发送方,自己期望的下一个序号是多少。
在这里插入图片描述

超时重传机制

当消息发送方,发送一条消息之后,机会开启一个重传计时器,用来计算消息发送出去的时间,当消息发送的时间大于RTO的时候,还没有收到确认的报文,则重传该报文。
一般有两种情况会触发超时重传机制:应答丢失的情况和发送方数据丢失。不论是数据丢失还是接收方发送的确认报文丢失,对于消息的发送方而言都没有收到确认报文,所以在RTO时间之后会进行重传,图例如下:
在这里插入图片描述
RTO(超时重传时间)是动态计算 = RTT(cur) * i + RTT(prev) * (1 - i):tcp中默认情况下i=0.9;
RTT(报文往返时间):从发送报文开始计算,直到收到确认应答,所经历的时间被称为报文往返时间。图例如下:
在这里插入图片描述

连接管理机制

在正常情况下, TCP要经过三次握手建立连接, 四次挥手断开连接。
在这里插入图片描述
服务端状态转化:

  • [CLOSED -> LISTEN] 服务器端调用listen后进入LISTEN状态, 等待客户端连接;
  • [LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送SYN确认报文;
  • [SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进入ESTABLISHED状态, 可以进行读写数据了.
  • [ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用close), 服务器会收到结束报文段, 服务器返回确认报文段并进入CLOSE_WAIT;
  • [CLOSE_WAIT -> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用close关闭连接时, 会向客户端发送FIN, 此时服务器进入LAST_ACK状态, 等待最后一个ACK到来(这个ACK是客户端确认收到了FIN);
  • [LAST_ACK -> CLOSED] 服务器收到了对FIN的ACK, 彻底关闭连接.

客户端状态转化:

  • [CLOSED -> SYN_SENT] 客户端调用connect, 发送同步报文段;
  • [SYN_SENT -> ESTABLISHED] connect调用成功, 则进入ESTABLISHED状态, 开始读写数据;
  • [ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close时, 向服务器发送结束报文段, 同时进入FIN_WAIT_1;
  • [FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入FIN_WAIT_2, 开始等待服务器的结束报文段;
  • [FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出LAST_ACK;
  • [TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入CLOSED状态.

理解TIME_WAIT状态

TCP协议规定,主动断开连接方要处于TIME_ WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态。MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同, 在Centos7上默认配置的值是60s;可以通cat/proc/sys/net/ipv4/tcp_fin_timeout 查看msl的值;
为什么是TIME_WAIT的时间是2MSL?
MSL是TCP报文的最大生存时间,TIME_WAIT的状态是为了等待连接上所有的分组的消失。单纯的想法,发送端只需要等待一个MSL就足够了。这是不够的,假设现在一个MSL的时候,接收端需要发送一个应答,这时候,我们也必须等待这个应答的消失,这个应答的消失也是需要一个MSL,所以我们需要等待2MSL。

理解CLOSE_WAIT状态

什么情况下,连接处于CLOSE_WAIT状态呢?
在被动关闭连接情况下,在已经接收到FIN,但是还没有发送自己的FIN的时刻,连接处于CLOSE_WAIT状态。 通常来讲,CLOSE_WAIT状态的持续时间应该很短,正如SYN_RCVD状态。但是在一些特殊情况下,就会出现连接长时间处CLOSE_WAIT状态的情况。出现大量close_wait的现象,主要原因是某种情况下对方关闭了socket链接,但是我方忙与读或者写,没有关闭连接。代码需要判断socket,一旦读到0,断开连接,read返回负,检查一下errno,如果不是AGAIN,就断开连接。
小结: CLOSE_WAIT状态只有被动断开连接方有这种状态,对于服务器上出现大量的 CLOSE_WAIT 状态, 原因就是服务器没有正确的关闭 socket, 导致四次挥手没有正确完成. 这是一个 BUG。只需加上对应的close即可。

滑动窗口

对每一个发送的数据段,都要给一个ACK确认应答。收到ACK后在发送下一个数据段,这样的缺点就是性能比较差,尤其是数据往返的时间比较长的现象。既然这样一发一收的方式性能较低, 那么我们一次发送多条数据, 就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了)。
在窗口的数据是已经发送到网络上,但是还没有完成确认分组的集合。相对于之前学到的确认应答机制,滑动窗口机制的引入,不必让发送方等待一个报文的确认到达之后,再发送下一个报文,而是允许发送多个报文到网络上。这样的话双方就提高了发送数据的效率。
窗口大小=允许不接收到确认应答就可以发送到网络上的分组的数量。窗口可以是动态变化的,是根据网络转发能力决定的,网络良好,窗口就会变大,数据发送也就会快;网络比较差,窗口变小,数据发送的慢。窗口大小一般是15,TCP连接开始的时候取值为8。对于TCP通信双方来说都维护了一套窗口,发送窗口和接受窗口,发送窗口保存的是没有确认的报文,发送缓冲区的一部分,接收窗口等同于接受缓冲区。
在这里插入图片描述

窗口移动时,一定要收到最早分组的确认应答之后,才可以向后进行滑动。
窗口大小是在三次握手期间进行协商的 win=43690字节 = Window size value(342)* 窗口平衡因子(2^7=128)

那么如果出现了丢包, 如何进行重传? 这里分两种情况讨论
情况一: 数据包已经抵达, ACK被丢了
在这里插入图片描述
这种情况下, 部分ACK丢了并不要紧, 因为可以通过后续的ACK进行确认;
情况二: 数据包就直接丢了
在这里插入图片描述
当某一段报文段丢失之后, 发送端会一直收到 1001 这样的ACK, 就像是在提醒发送端 "我想要的是 1001"一样;如果发送端主机连续三次收到了同样一个 “1001” 这样的应答, 就会将对应的数据 1001 - 2000 重新发送;这个时候接收端收到了 1001 之后, 再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就已经收到了, 被放到了接收端操作系统内核的接收缓冲区中;这种机制被称为 “高速重发控制”(也叫 “快重传”).

拥塞控制

拥塞控制机制要点:慢启动、拥塞避免、快重传、快恢复

1. 慢启动和拥塞避免

在这里插入图片描述
当双方建立连接后,一开始不要发送大量的数据,而是先发送少量的数据,特侧网络中的拥塞程度,当网络中情况比较好时,再逐渐增大发送的数据量。慢启动之后有一个慢开始门限ssthresh,当拥塞窗口大小小于慢开始门限的时候,执行慢开始算法;超过慢开始门限之后则执行拥塞避免算法(随着传输轮次的增加,拥塞窗口的大小依次加1);

2. 拥塞窗口的大小

在发送发有发送数据的发送窗口,还需要考虑拥塞窗口,一般情况下拥塞窗口等于发送窗口;当拥塞窗口小于发送窗口时,按照拥塞窗口的大小发送数据。

3. 快重传和快恢复

当执行慢开始算法或者拥塞避免算法的时候,一旦有丢包现象,则触发TCP执行快恢复算法。新的慢开始门限 = 拥塞窗口 / 2,然后继续执行拥塞避免算法。
在这里插入图片描述

延时应答

前提:

  1. 接收方在恢复数据的时候,会通知发送方自己的接受能力;
  2. 发送方通过接受方的接收能力,调整发送窗口大小(假设网络情况良好,意味着要先排除拥塞窗口的干扰);
  3. 接收方通告的接收能力越大,发送窗口越大,也就是意味着传输效率越高,反之,发送窗口越小。
  4. 接收方的能力大小,其实取决于应用层的接受程序的能力,应用层接受的越快,TCP接收缓冲区空闲的越多,通告发送方自己接收能力的时候就越大,促使发送方的发送窗口越大。

延时应答:TCP接收方在回复确认ACK的时候,稍微等一小会(200ms),再回复ACK(本质就是等应用层的程序从接受缓冲区将数据读走)。

捎带应答

捎带应答的前提是双方都想给对方发送数据,并且发送数据比较频繁。捎带应答机制指的是在发送数据的时候捎带着回复AC给对端。例如下图所示:
在这里插入图片描述

面向字节流

创建一个TCP的socket, 同时在内核中创建一个发送缓冲区和一个接收缓冲区;

  • 调用write时, 数据会先写入发送缓冲区中;
  • 如果发送的字节数太长, 会被拆分成多个TCP的数据包发出;
  • 如果发送的字节数太短, 就会先在缓冲区里等待, 等到缓冲区长度差不多了, 或者其他合适的时机发送出去;
  • 接收数据的时候, 数据也是从网卡驱动程序到达内核的接收缓冲区;然后应用程序可以调用read从接收缓冲区拿数据;
  • 另一方面, TCP的一个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这一个连接, 既可以读数据, 也可以写数据。这个概念叫做全双工。

由于缓冲区的存在, TCP程序的读和写不需要一一匹配, 例如:

  • 写100个字节数据时, 可以调用一次write写100个字节, 也可以调用100次write, 每次写一个字节;
  • 读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以一次read 100个字节, 也可以一次read一个字节, 重复100次;

粘包问题

首先要知道,粘包问题中的指的是应用层的数据包。在TCP的协议头中, 没有如同UDP一样的 “报文长度” 这样的字段, 但是有一个序号这样的字段.站在传输层的角度, TCP是一个一个报文过来的。按照序号排好序放在缓冲区中。站在应用层的角度, 看到的只是一串连续的字节数据.那么应用程序看到了这么一连串的字节数据, 就不知道从哪个部分开始到哪个部分, 是一个完整的应用层数据包。

那么如何避免粘包问题呢? 归根结底就是一句话, 明确两个包之间的边界
对于定长的包, 保证每次都按固定大小读取即可; 例如上面的Request结构, 是固定大小的, 那么就从缓冲区从头开始按sizeof(Request)依次读取即可;对于变长的包, 可以在包头的位置, 约定一个包总长度的字段, 从而就知道了包的结束位置;对于变长的包, 还可以在包和包之间使用明确的分隔符(应用层协议, 是程序猿自己来定的, 只要保证分隔符不和正文冲突即可。

TCP保活机制

  1. 当连接空闲2小时(当前双方都没有给对方发送数据),就会触发TCP保活机制,每隔75秒发送一个保活探测包,总共发10次;
  2. 如果当前10个保活探测包都没有确认应答,则认为对端状态不对,则关闭该连接。
  3. 不管是客户端还是服务端在闲置2小时,都会给对端发送保活探测包;
  4. 当我们发送一个数据之后,就会启动保活计时器,当收到应答,则重置保活计时器;或者当收到对端发送的数据的时候,也会重置保活计时器。

0号窗口

0号窗口时告诉对端,当前自己的接收能力为0,不需要对端再给我发送数据了。导致这样的原因是接收方没有调用recv函数,当前接收方的接收缓存区已经满了,就会导致接收方给发送方发送0号窗口。在这里插入图片描述

网站文章

  • docker(七)容器监控(CAdvisor+InfluxDB+Granfana)

    docker(七)容器监控(CAdvisor+InfluxDB+Granfana)

    CAdvisor+InfluxDB+Granfana进行容器监控

    2024-04-01 04:15:02
  • 洞道干燥及计算机控制实验报告,化工原理洞道干燥实验报告模版.doc

    化工原理洞道干燥实验报告模版洞道干燥附件 1. 调试实验的数据见表2, 表中符号的意义如下: S─干燥面积, [m2] GC─绝干物料量, [g] R─空气流量计的读数, [kPa] To─干燥器进口...

    2024-04-01 04:14:24
  • iSlide系列教程视频简介——PPT的简化神器

    iSlide系列教程短视频完整版【-1】PPT基础操作-迅速告别PPT小白身份:http://t.cn/RdO3zEL【00】全局化设计思维与PPT主题:http://t.cn/RdO3zEA01.PPT智能模板工具iSlide插件安装教程:http://t.cn/RdO3zRd02.主题库+图示库,给你开挂的PPT设计体验:http://t.cn/RdO3zEU03.色彩库带你玩转P...

    2024-04-01 04:14:16
  • 优质壁纸网站 awesome wallpaper sites

    wallhaven

    2024-04-01 04:14:08
  • mysql char 空白_MySQL中CHAR and VARCHAR

    MySQL版本:8.0版本CHAR和VARCHAR类型相似,但在存储、检索方式、最大长度和是否保留末尾空格四个方面存在差异。长度:CHAR(0-255)类型为CHAR的列的长度是固定的,可以在创建表时...

    2024-04-01 04:13:30
  • MyBatis原理分析手写持久层框架

    MyBatis原理分析手写持久层框架

    目录1 JDBC操作数据库问题分析2 JDBC问题分析和解决思路3 自定义持久层框架_思路分析3.1 使用JDBC和使用持久层框架区别3.2 核心接口/类重点说明3.3 项目使用端3.4 自定义框架本身3.5 最终手写的持久层框架结构参考4 自定义持久层框架_编码5 自定义持久层框架优化

    2024-04-01 04:13:22
  • 软件测试期末考试复习--性能测试大题详解

    软件测试期末考试复习--性能测试大题详解

    我有好多题,刷刷刷、哈哈哈。。。。。。。 第一题 【说明】 性能测试在系统质量保证中起重要作用。某项目组对一个电子政务平台系统执行了负载压力性能测试,重点评估其效率质量特性中的时间特性和资源利用性两个质量子特性。性能需求可以概括为:业务成功率达到 100%;响应时间在 8 秒之内;内存页面交换速率低于80pagein/s;服务器资源利用合理。测试环境逻辑部署图如下图。 【问...

    2024-04-01 04:13:14
  • 【必看】机器学习人才必备 —— TensorFlow 开发者证书

    【必看】机器学习人才必备 —— TensorFlow 开发者证书

    在当今的 AI 世界中,越来越多的公司正在寻求与聘请机器学习方面的人才,与此同时,越来越多的学生和开发者也正在寻求获取和展示 ML 知识的渠道。 除了在线课程和学习资源之外,我们希望帮助开发者展示自身...

    2024-04-01 04:13:07
  • redis 性能优化管理

    内存碎片是由操作系统低效的分配/回收物理内存导致的(不连续的物理内存分配)。当达到设置的最大阀值时,需选择一种key的回收策略,默认情况下回收策略是禁止删除的。使用LRU算法从已设置过期时间的数据集合...

    2024-04-01 04:12:26
  • oracle savepoint

    Oracle之savepoint什么是savepoint?Use the SAVEPOINT statement to identify a point in a transaction to which you can later roll back.例如: SQL> SELECT * FROM SCOTT.DEPT  ;DEPTNO DNAME

    2024-04-01 04:11:35