数通面试第三篇 ~
今天来聊聊传输层的东西 , 其实对我们网工来说无异于 TCP / UDP 2种协议以及端口号的相关内容
对于不太靠谱的三层IP(尽力而为模型)来说 , TCP 完成了很多 IP协议无法完成的事情
先来简单的问题当个开胃菜
为什么需要TCP ?
IP 层是「不可靠」的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据的完整性。TCP 是一个工作在传输层的可靠数据传输的服务,它能确保接收端接收的网络包是无损坏、无间隔、非冗余和按序的。
对于往上封装过程中 IP中的协议字段 6 /17 决定了4层是TCP(6)还是UDP(17)
TCP和UDP有什么区别
这个问题相对来说还是比较简单的
TCP是面向链接的 --> 我们可以理解为打电话 我们直接有一个会话的关系 ,
- TCP是一个1对1的情况 , 同时在开始传输数据之前一定需要进行三次握手
- TCP很可靠 你可以及时和我沟通(确认机制 / 重传机制 / 拥塞控制) , 没有数据丢失
- TCP的头部较为复杂 因为需要实现各种复杂的功能 你可以继续理解打电话 通知100个人 就会很麻烦
- 分片处理 , TCP协议中的数据包大小超过最大报文段长度(MSS),TCP在传输层进行分片。
好 我们再来看看UDP
UDP 是无连接的 --> 相较于打电话 这里我们可以理解为 对讲机 (电视剧里见过吧? 保安掏出来就是喊)
- UDP是一个1对多的情况 , 当然也支持1对1 多对多 总之没有限制 开始传输数据之前也不需要建立链接
- UDP不可靠 , 当然也不是他的问题 UDP会尽量的去完成 (可以类比IP)
- UDP的头部比较简单 就是 源目端口号 + 包长度(注意TCP的是首部长度) + 校验和
- 分片处理 , UDP协议包 如果超过了MTU 则会交给ip协议去分片 (他太简单了)
为什么UDP头部是包长度 , 而TCP头部是首部长度?
UDP的包长度:
UDP头部的"包长度"字段指的是整个UDP用户数据报的长度,这包括了UDP头部和UDP数据载荷。由于UDP是一种简单的面向数据报的协议,它不将数据切分成多个部分进行发送;每个UDP数据报都是独立的,并且包含了全部的传输信息。因此,"包长度"字段是必要的,它告诉接收端这个数据报总共有多长,以便正确地从IP数据包中提取UDP数据报。
TCP的首部长度:
TCP头部的"首部长度"(也称为"数据偏移")字段是指TCP头部的长度,不包括TCP数据载荷。由于TCP是一种流式协议,它可以将数据切分成多个部分进行发送,而且每个部分可能会有不同的选项和大小的头部。TCP的"首部长度"字段告诉接收端在这个TCP段中头部有多长,这样接收端就知道从哪里开始读取实际的数据。这个字段是变长的,因为TCP头部可以包含多种不同的选项,如最大报文段大小(MSS)、窗口缩放因子、选择性确认(SACK)选项等。 TCP 有可变长的「选项」字段
TCP和UDP的 应用场景
TCP :
- FTP --> 需要保证文件数据的完整性和正确性
- http/https --> 浏览网页,依赖TCP提供的可靠性和顺序保证。
- SMTP(电子邮件) / SSH --> 依赖TCP来保证邮件内容不丢失、不损坏 以及可靠连接。
UDP :
- VoIP -->(语音通信)或实时视频会议,UDP因为其低延迟特性而被选
- DNS / SNMP:域名系统(DNS)查询通常使用UDP 也有小部分TCP,因为它们需要快速得到响应,且数据包通常很小。
- 广播或多播应用:UDP适用于发送广播或多播消息,如某些类型的视频广播。
重点关注一下TCP
先来看看 TCP协议的报文 , 里面具体有哪些东西
重点关注一下 Seq 和Ack 值的理解 , 以及他们对应的Flags置位 ,
Sequence 序列号 | 报文循序的排列 对端可以检测丢失 请求重传 如这次Seq = a , TCP载荷 x个字节 本端下次发送就是a+x (x是上次发送内容的字节数 也就是对端 回复的ACK) 在三次握手的情况下 没有数据 x就是1 假设有1个字节 |
Ack 确认号 | 本端确认号= 接收到的对端Seq+x (TCP载荷) (x: 我收到了你发送的x字节) 1.我收到你seq为b的报文 2.告诉你可以发送b+x的报文了 |
Flags 标记 (1字节 共8个flag) |
Flags的内容 , 其中6个是常用的 2个不常用
ACK , SYN , FIN需要重点学习一下
SYN=1(就是等于Flags 的SYN置位了)表示这是一个连接请求或连接接受请求。
在一个正常的TCP会话中 SYN只会被使用2次 -->三次握手中双方各自的第一次数据包中
在TCP所有的会话中 有且只有第一个包(通常是客户端发送的) , Flags只置位了SYN
其余所以的包中Flags都会多一个AKC 意思是 ACK只在>=2的包中出现
简单的理解一下
第一个包Flags置位(SYN)
第二个包FLags置位(SYN+ACK)
第三个包和后续所有的包Flags都不会出现SYN 但必定都有ACK
这样就多一个面试场景 比如说一条防火墙命令 设置了一个ACL 规则是只允许ACK置位的包通过
这是什么意思呢 ?
其实不难 ACK不在一个包出现 这样子设置 如果墙外服务主动访问墙内(第一个包没有ACK)
此时就会被这条规则拒绝 , 只有里面发起才可以建立会话 防火墙才允许 --> 是不是很像DMZ区域的设计?
TCP三次握手的过程
先从Flags置位的角度来看 (上面已经详细阐述过了)
SYN |
|
| SYN+ACK |
ACK |
|
再从Seq序列号和ack确认值(注意值和flags置位的区分)的角度看
会话的双方各自维护了一个序列号 , 个人认为这个理解是很重要的 什么叫做各自维护?
Seq : A ACK : 没有ACK |
|
| Seq : B ACK = A+1 (ACK的A就是对端Seq的值 , 加对端TCP载荷的值 , 但是三次握手没有具体数据 , 所以为1 ) |
Seq : A+1 (seq = 本端上次Seq+ 本端上次数据载荷) ACK : B+1 (对端Seq的值+ 对端TCP载荷) |
|
简单理解一下 Seq是自己和自己算(+=载荷)的 因为三次握手是没有载荷数据的 默认为1 所以看起来会混淆
(双方的TCP载荷可能是不一样的 , 比如我这边只做确认没有发送数据 本端Seq增值就很慢)
ACK是确认收到对方的seq 以及 对方的载荷 , 2个值加起来就是ACK了
为什么链接是三次断开是四次
三次链接:
比如说我们来模拟建立会话 2次的情况下
A : 你好 , 我需要建立链接(Seq)
你好 , 我需要建立链接(Seq) , 我准备好了(ACK) : B
这样是不是感觉很奇怪 B服务端是没办法得知 客户端A有没有准备好
因为只有收到了A的ACK B才能确认A收到了B发送的确认
虽然从理论上说,两次握手也能建立起一个连接,但实际上,这会大大降低连接的可靠性和稳定性
这也会导致另外一个问题 :
如果一个失效的连接请求(例如,由于网络延迟而晚到的旧SYN报文)到达服务器,两次握手会使得服务器错误地认为这是一个新的连接请求,并建立连接。这可能导致服务器资源的浪费,并可能打开一条不再需要或不再期望的连接。
四次挥手:
老样子 我们来模拟一下 断开会话 断开么 我直接走人不行么?
A : 你好 , 再见~
…………. : B
是不是看上去没啥问题? 但如果B还有话说呢 ?
首先明确一个观点
这个会话关闭是基于双方的
我发如果信息发送完毕 但是对方还有信息还需要发送呢?
我结束 发送FIN置位 --> 对端发送ACK确认知晓我要离开
对端结束 发送FIN置位 <-- 我发送ACK确认知晓对端要离开
至此 TCP连接断开
但是实际环境中 并不总会抓到4次完整挥手 , 这是另外一个情况了 , 基于设计 可能没有第四个ACK , 也可能等半天没反应就释放资源断开会话了 都存在
TCP累加确认机制
当然实际环境中不可能是一句一确认的
(想想一下你和你领导打电话 你领导说一句你附和一句 "好 , 知道 " 这也太舔狗了 领导也嫌你烦)
实际场景是多个TCP后 , 回复一下 (seq+多个包总载荷) , 这就是累加确认 , 比如我连续发3个载荷为1000的包
然后你确认了ack为 Seq = a+4000
累加确认
连续3个载荷 x =1000
Seq = a+(1000) -->
Seq = a+(2000) --> (是不是很难理解连续三个载荷1000 不是3个a+1000? , 回想一下序列号的作用)
Seq = a+(3000) -->
<-- Seq = a+(4000)
实际应该是5-7个包回复一次 , 如果 回复的ACK值不等于a+4000 , 这说明有TCP需要重传了
因为收到的载荷数量对不上 , 此时的重传机制就是到之前你的回复节点起 开始重传
(有比较牛x的技术可以精确具体到重传你丢失的某个包 或者从丢失点开始重传 , 这里不做展开讨论)
TCP的滑动窗口机制
window字段 , 之前不是讨论了累加确认的机制么 , 有没有想过这么一个问题
如果我这边很忙 , 但是对端还是源源不断的快速发送一些数据来让我处理 , 这样子就容易造成拥塞 所以
滑动窗口机制帮助进行流量控制,确保发送方不会因发送过多数据而淹没接收方或网络。
果接收方的窗口大小变为零(即没有可用的缓冲区),它会通知发送方停止发送数据。当接收方准备好接收更多数据时,它会更新窗口大小并通知发送方。
RTT 超时时间动态调整技术
重传的可能性可以分为三种 :
去的时候丢了
回的时候丢了
超时 --> 我们来重点讨论一下超时
字面理解类似ICMP , 我等待一段时间没有收到你的回复你的ACK 我不知道你是丢了还是正在路上 , 但是我也不可能无限制的等待下去 , 这里你可以说 那不简单 , 设置一个常见的数值不就行了 , 比如大于多少微妙就算超时 .
那么你访问外国的节点的呢? 跨越几千公里的场景下延迟必然高 , 你不能说你来得慢我就不等你了 人家还在路上呢
所以这个超时时间如何设置是大有学问的 , 这里就引出我们的主角 RTT (Round-Trip Time)
TCP(传输控制协议)中的超时时间动态调整技术主要是基于往返时间(Round-Trip Time, RTT)的测量。RTT是指一个数据包从发送方发送到接收方,并且接收方发送确认(ACK)返回给发送方所需的总时间。动态调整超时时间是TCP可靠性和效率的关键因素之一。
网工不比拘泥这些细节的实现 , 了解即可
SRTT = SRTT + α (RTT – SRTT) :计算平滑RTT;
DevRTT = (1-β)*DevRTT + β*(|RTT-SRTT|) :计算平滑RTT和真实的差距(加权移动平均);
RTO= μ * SRTT + ∂ *DevRTT : 加权平均公式。
结尾照例放出一些面试题 仅供参考
- TCP 与 UDP 的区别是什么?请举例说明在什么场景下会选择使用它们。
这个问题考察应聘者对两个主要传输层协议的理解和实际应用能力。 - 描述 TCP 的三次握手和四次挥手过程。为什么是三次握手而不是两次或四次?
这一问题旨在检验应聘者对 TCP 连接建立和终止过程的深入理解。 - 什么是 TCP 拥塞控制?请解释 TCP 的拥塞控制算法,例如慢启动、拥塞避免、快重传和快恢复。
此题目考查应聘者对 TCP 性能优化和网络流量管理的知识。 - 在 TCP 连接中,发生丢包时会怎样?TCP 如何检测和恢复丢失的数据包?
这个问题测试对 TCP 的可靠性机制的理解。 - 解释什么是 TCP 窗口缩放和选择确认(SACK)。它们是如何改进 TCP 性能的?
这一问题探讨 TCP 协议的高级特性及其对数据传输性能的影响。 - 描述一个你遇到的关于传输层的复杂问题,以及你是如何解决的。
这个问题旨在了解应聘者的实际工作经验,特别是在问题解决和故障排除方面的能力。 - 在面对网络拥堵时,UDP 和 TCP 分别如何表现?在这种情况下,如何优化 TCP 传输性能?
这个问题考察应聘者对网络状况变化时协议表现的理解,以及对性能调优的能力。