本篇会加入个人的所谓鱼式疯言
❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言
而是理解过并总结出来通俗易懂的大白话,
小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.
🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!
引言
想象一下,如果没有可靠的数据传输机制,我们的网络世界将会怎样?信息可能会丢失,邮件可能无法送达,在线交易可能无法完成。幸运的是,TCP协议为我们提供了一种确保数据完整性和顺序的通信方式。它不仅确保了数据的准确传输,还通过一系列核心机制优化了网络性能。
目录
-
延时应答
-
捎带应答
-
面向字节流
-
异常情况处理
一. 延时应答
1. 延时应答的初识
小伙伴应该知道,确认应答是返回一个
ACK = 1
, 且带有 确认序号 , 没有载荷 的报文。
而延时应答则是在
确认应答
和流量控制
的基础上, 进行了 优化了 。
之前是一收到发送方发来的数据, 就立即
返回 ACK
。
但是延时应答的是: 等待一段时间 ,等 应用程序 消耗了
接收缓冲区
一定的数据之后, 再返回ACK
。
2. 延时应答的大体流程
如上图:
上面是一个 接收缓冲区
假设这个缓冲区的空间为 100KB
, 原有数据 40KB
, 然后新发送(写) 缓冲区数据 20KB
, 还剩下 40KB空间大小 。
如果说,按照 确认应答机制实施 , 接收方一收到这个 20KB数据 , ACK
就返回接收缓冲区剩余40KB数据的信息 , 这样的话,
从上一篇我们学习过的 流量控制的角度 , 我们知道滑动窗口的窗口大小就是根据接收缓冲区的剩余大小来衡量的, 如果接收缓存区 剩余空间越小
, 发送方 设置的窗口就越小 , 发送速度就越低, 效率就越低效。
但是我们假设设置一个 100ms 的等待时间 ,
让应用程序在这 100 ms
内尽可能的消耗 尽可能的消耗接收缓冲区 的数据, 可能 消耗了20KB
当 ACK 等待了100ms 后返回, 就会从之前返回剩余40KB 变成
返回60KB
的信息。
同时发送方就会调整为
更大的窗口大小
, 从而 加快传输速度 。
可能小伙伴们还听的不是很清楚吧
下面小编举个栗子说明一下吧
小编是在一所高校上学的, 可能平常又很懒,几乎不写作业~
然后老师也 看不下去
了,就发个消息提醒我。
老师: 同学, 你作业好多没写, 快把你作业补一补吧!
这时小编有两种策略:
策略一: 小编立即回复:
我: 老师, 最近有点忙,抱歉哦, 我尽快把作业补完。
这时我就指不定什么时候能够补完了, 说是马上去补,肯定是去哈皮咯, 好比 确认应答机制 。
策略二: 小编先 不急着回复老师消息 , 而是先一顿 狂补八九次作业 , 最后只 剩下两次 , 然后我再去回复老师。
我: 老师, 我这个作业已经快写完了, 我只剩下两次作业了,分分钟搞定了。 就好比: 延时应答机制
这上面的两次策略就对应两种不同的应答, 确认应答机制 和 延时应答机制
我们就可以看出, 我
立即补作业
和 过会再写作业 的方案的效率是不一样
的,过会写作业还指不定什么时候开始补
呢, 但是现在开始补就相当于 延时一点时间 , 让我不断消耗现有作业的量
, 从中体现 延时应答机制 更能体现出 提高效率 。
鱼式疯言
总结补充:
- 延时应答其实本质上就是 多消耗接收缓冲区数据, 多加快传输速率 ,
提高效率
, 减少Tcp因可靠传输而造成的性能的影响。
如果要保证在延时应答的机制下, 缓冲区的数据是 尽可能被消耗而不是增加 的, 就要确保以下两点
应用程序
是不断 源源不断的消耗着缓冲区的数据的
- 发送方不会有 新的数据 发送过来 。
二. 捎带应答
1. 捎带应答的初识
捎带应答是什么?
捎带应答可以认为就是 在原本是 三次握手中中间一次的发送过程 , SYN
和 ACK
同时合并 捎带一起发送
, 也是 一种提高效率 , 减少Tcp可靠传输的对性能的损耗 。
鱼式疯言
捎带应答不用可以是 同一个源头发送的数据合并, 也可以是 不同的源头发送的数据合并 。
下面我们以四次挥手合并成三次挥手为栗子来说明:
2. 捎带应答的大体流程
在之前的文章中, 小编讲过 四次挥手
的全过程, 如果还有点模糊的小伙伴记得回顾哦 ❣️ ❣️ ❣️ ❣️
三次握手, 四次挥手详解
这次从四次挥手的中间两次来介绍捎带应答的大体流程
首先, 按照一般的情况来说, 中间两次挥手是不能合并的, ACK是系统内核返回到,只要一收到发送方发送FIN 就会立即返回 ACK, 而 FIN
是 应用程序 发送的, 只要执行到 close()
才会发送。
从正常情况考虑, 两个报文的发送时间是 不同的 , 所以很难 同时一起发送
。
但是因为Tcp有 延时应答的机制,就可以让 快一点的ACK 经可能的 慢点发送, 直到应用程序执行到
close()
方法后 , ACK 就和 FIN 一起同时发送, 从而提高效率
, 这就是 捎带应答机制。
什么是捎带应答机制, 可能主编这边讲的还不是很通俗易懂, 下面来举个小栗子吧 ❣️ ❣️ ❣️ ❣️
比如我室友是特别懒的一位, 就在我旁边的床位, 平常要不是上课就根本不想动, 就整天躺在床上刷视频。
他经常看着看着就口渴了, 这时他因为太懒了, 根本不想动, 那么他就会等等…
等到什么时候呢?
等到他要上厕所了, 就会 下床先去上厕所 , 然后就 顺便去喝水
。
我室友的这种方式就完美的诠释了什么叫做
捎带应答
, 他等的过程就相当于ACK
等待FIN 相似
, 直到 FIN 需要发送了 然后再 顺便发送ACK ,从而 提高传输的效率 。
鱼式疯言
总结补充:
对于 相同的发送源头 ,
Tcp
可以直接实现使用 捎带应答 ;
对于 不同的发送源头 ,
TCP
就需要在 延时应答 的基础上使用捎带应答
。
三. 面向字节流
1. 黏包问题
在前面的文章中, 谈及Tcp 必然谈及Tcp 的特点之一——面向字节流
关于前面Tcp 面向字节流的特点还有不清楚的, 小伙伴们可以重新巩固下哦 ❤️ ❤️ ❤️ ❤️
面向字节流博客详解
而在本篇中就需要给小伙伴们介绍Tcp 在面向字节流进行网络通信时, 所可能产生的黏包问题
什么是黏包问题?
入上图:
就是当发送方发送几段数据后, 这些数据就会在接收缓冲区中连成一片, 相互黏合。
而当 主机B 从接收缓冲区中读取数据 , 就有可能会出现:
aa , abbb , ccc
aaab, bbc, cc
aa,abb,bccc 等… 各种读取情况, 就会出现实际数据信息读取错误, 这样的情况称之为: 黏包问题
。
如何解决黏包问题呢?
下面提供两种方案 🤔 🤔 🤔 🤔 🤔
2. 黏包问题的解决方案
<1>. 使用分隔符
使用分隔符 例如
\n
换行来 分隔每一个数据包 的信息。
比如当
主机A
写出一段数据, 就使用nextLine()
方法, 只要 换行了就说明写出完毕 。
而
主机B
读入一段数据 , 就使用println
来读取, 代表 一行一行的来读取 。
<2>. 使用固定长度来分隔
使用固定长度这个方案, 我们就可能参考UDP 的报头结构,
从载荷(应用层数据包)的首部开始分配一个 2/ 4字节
长度的空间, 用一段固定的空间来作为 每个数据包与数据包的边界 , 如此用一个 固定的长度来分隔数据 ,就很难出现 黏包问题 。
鱼式疯言
关于这种黏包问题, 小编这里只是举例 两种常用的方案 , 其实解决黏包问题的方案是 很多种的
。
四. 异常情况处理
对于异常情况的可能性很多, 下面小编就一一来为小伙伴们讲解 💞 💞 💞 💞
1. 进程崩溃
对于Java来说, 当进程崩溃时, 就会抛出异常, JVM
就会来处理 , 这时就会使 整个程序结束 。
但实际上, 操作系统就进行 善后工作 , 自动回收 PCB 的文件描述符表 , 并且会对 每一个PCB 中的 文件描述符表 的每一个
Socket 对象
进行释放。
针对
Socket文件
进行释放, 也就是进行四次挥手
的 断开连接操作。
2. 主机正常关机
对于主机正常关机,会出现两种情况:
1. 四次挥手 先完成 ,正常断开连接后, 主机正常关机
<2>. 四次挥手还没完成, 主机就已经断开连接
如上图 ,还没来得及完成四次挥手, 主机 A就先关机 , 此时主机B 没有收到ACK
而且 不能感知到主机A 已经关机了, 所以主机B 就会 一直进行超时重传 , 当主机B 超时重传一定次数后,就 不会进行超时重传 , 主机B 就会
自动一方断开连接
, 也就是 删除对方的信息。
3. 主机意外掉电
对于主机意外掉电的情况, 就有分为
-
发送方先发完数据掉电
-
接收方接收完就掉电
<1>. 发送方掉电
当A 发送了两段报文后, A 就直接掉电, 掉电之后B返回两个ACK
但从B 的角度来看, 不知道 A
是 掉电了 还是 休息一会再发 。
所以这时B 就会发送一个 探测报文 , 来 检查A 是嘎了 还是 想歇会 。
如果B 接收到
了 A 返回的ACK 就说明, A 想休息会。
如果发送了多次探测报文都 没有接收到了ACK , 就说明 A已经嘎了 。
这时B 就会 单方面释放连接 。
鱼式疯言
补充说明:
探测报文是一种 不携带载荷, 为了 触发ACK
的一种 特殊报文
就是用来探测对方
生死
的一种数据包, 该数据包我们称之为心跳包
心跳包是一种为了 触发ACK 而周期性发送的一种探测报文 , 在Tcp配置中, 探测报文的周期是 秒/ 分钟来衡量的。
应用程序 则这一层会 自动生成 一些心跳包 , 来达到更快的
保活机制
。
<2>. 接收方断电
如果
A 发送多段数据包
, 没有接收到 ACK , 就会超时重传, 但 重传达到一定的上限, A 就会重置连接, 如果 重置连接失败 , A 就会单方面的释放连接。
4. 网线断开
如果网线断开了, 也就意味着网络通信瘫痪了, 那么 A 无法发送数据给B , 同时
B也无法接收到 A 发送过来的数据
。
从 A 的角度来看, A 发送数据后, 没有接收到ACK , 就会超时重传 , 超时重传达到
一定的上限
那么就会 重置连接 , 那么 A 这边就会单方面的释放连接 。
从 B 的角度来看, B未接收到数据, 就会
周期性的发送心跳包
, 如果发送 一定次数的心跳包都没有接收到 ACK , 同时也会但 方面释放连接 。
鱼式疯言
总结补充 :
从 发送方
的探测方式: 重置连接
接收方
的探测方式: 心跳包
总结
-
延时应答: Tcp用于减少 可靠传输 带来的损耗的一种机制, 消耗一定时间尽可能的
消耗接收缓冲区中已有的数据
,
提高效率。 -
捎带应答: 将两次或两次以上的发送 合并成一次一起发送 ,提高效率, 并可能会利用
延时应答机制
来配合使用。 -
面向字节流:面向字节流的常见问题就是 粘包问题 , 常用的解决方案: 使用 分隔符 和 固定数据长度 。
-
异常情况处理:介绍多次异常的情况, 同时
重置连接
或者 心跳包 确定是否存活, 如果对端不存活就会 单方面的释放连接 。
如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正
希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖