当前位置: 首页 > news >正文

核心机制:面向字节流

面向字节流

        读取/写入的时候,读写操作有很多方式,非常灵活

        读 100 字节

        1.一次读 10个字节,10次完成

        2.一次读 20 个字节,5次完成

        3.一次读 50 个字节,2次完成

粘包问题

接收方分用的时候,去掉报头,把载荷内容放到一个,接受缓冲区中

接受方的应用程序,read 的时候,就有很多种 read 的可能性

read 的可能性:

1)a   a   a   b   b   b   c   c   c

2)aa   ab  bb  cc  c

3)aaa   bbb   ccc

4)aaab   bbbc   c

5) aa   abb   bcc  c

怎么 read 是取决于应用程序的代码是咋写的

具体怎么来读,才能确保读到的是一个"完整的应用层数据包"

粘包,粘的是应用层的数据包

TCP 字节的特效,收到多个 TCP 数据报的时候把所有的载荷都给混到一起,放到接受缓冲区里

包的边界比较模糊,就好像是"粘上了一样"

粘包问题就是咱们非常需要关心的问题

1.通过特殊的分隔符,来作为包边界的区分

        比如, 约定每个应用层数据包,都已 ; 结尾

        包的数据里面,不能包含分隔符,需要找到合适的符号,确保这个符号在正文中不会重复出现,即使 ascil 码表中,也有不少的字符,可以用来作为分隔符的,有一下特殊的"不可见字符"历史遗留问题

在比如,之前写的回显服务器,当时是使用 \n 作为分隔符的

String request = sacnner.next(); => 读到空白符就结束了,空白符是统称,包括但是不限于:空格,换行,回车,制表符,分页符,垂直制表符

writer.println(request) => 发送请求的时候,使用 \n 作为结束标记的,由于是通过控制台来进行控制输入的请求内容的,控制台输入的内容本来就不会包含 \n

2.在应用层数据包开头的地方,通过固定长度,约定整个应用层数据包的长度

应用程序, read 的时候,先固定 read 2个字节,看看 2 个字节里面的内容是啥 => 发现是3接下来再 read 3 个字节,读到的 aaa 就是完整的应用层数据包

粘包问题只是针对字节流的传输.对于文件的操作,(使用文件存储多个结构性数据,也是可能涉及到粘包问题的)

比如,通过文件,保存若干个 学生信息

class Student {

        name

        id

        age

}

比如约定成,每个学生信息占一行(使用 \n 作为结束标记,作为分隔符)

对于 UDP 来说不存在粘包问题 UDP 的接受缓冲区和 TCP 的不太一样

应用层不需要做区分,应用层每次调用 recv 得到的就是一个完整的 DatagramPackage 也就对应一个完整的 应用层数据包

核心机制 异常情况

1.进程崩溃 [正常流程]

进程崩溃,意味着对应的文件描述符就被关闭了(调用 close,干掉进程) 只要是进程退出,都会释放 PCB,释放文件描述符表 触发 FIN

TCP 的连接并没有因为进程的结束立即结束,保留一会

2.主机关机 [正常流程]

正常流程下的主机关机,就会先杀死所有的进程,此时也会触发 FIN, 进而进入四次挥手,有可能挥不完

如果关机的速度比较慢,有很大可能四次挥手就挥完了

如果关机的速度比较快,刚发 FIN,机器就关了

对端可以正常返回 ack ,也会继续正常发送 FIN,这里的 FIN 就没有收到 ack,尝试几次重传 FIN 还是没有 ack,对端就直接放弃连接(删除之前保存的对端信息)

四次挥手,如果挥完了,双方可以确认,双发都能顺利吧保存的信息删掉

如果挥不完,至少直接可以把保存的信息删除掉,对端的就不管了

此时对端关机了,内存的数据全没了

3.主机掉电(直接拔电源)

直接啥都没了.来不及 FIN

1)如果掉电的一方是接受方,对方是发送方

对方继续发送数据,没有 ack =>超时重传 =>仍然没有 ack => 继续超时重传,达到一定的程度,掉电方仍然没有 ack ,发送方发送一个 复位报文,就是表示要重置连接放弃当前的连接

2)如果掉电的一方是发送方,对方是接受方

接受方感受到的是,发送方突然停下来了,接受方会继续阻塞等待,等待发送方发来新的数据(心跳包)

心跳包

接受方会周期性的和发送方交换"心跳包"

        A 给 B 发一个无业务数据的报文

        B 给 A 返回一个 ack

如果对方有应答,就可以认为对方是正常工作的

如果心跳包也没有应答,就可以认为,对方挂了

发现心跳包没有,就可以单方面的释放连接了(这个机制非常重要,尤其是分布式系统中,分布式系统中,知道,某个节点存活,非常重要)

TCP 协议自身虽然提供了心跳,心跳周期比较长,而在实际开发中,需要更高频的心跳应用层,代码实现的

4.网线断开

        本质上是和主机掉电是一样的.

        网线断卡的两端,一个是发送方,一个是接受方

                对于发送方来说,没有 ack => 超时重传 => 仍然没有 ack => 超时重传 => 达到一定程度放弃连接

对于接受方来说,周期性触发心跳包 => 发现对端下线 => 放弃连接

1.确认应答

2.超时重传

3.连接管理(三次握手,四次挥手)

4.滑动窗口(快速重传)

5.流量控制

6.拥塞控制

7.延时应答

8.捎带应答

9.面向字节流(粘包关系)

10.异常情况(心跳包)

这只是 TCP 协议的十大核心机制,TCP 还有其他机制

URG :表示"紧急指针"有效,正常情况下,TCP 的数据都是"顺序传输" 1- 1000, 1001- 2000,...., 紧急指针意味着后面有一些数据要先传输(插队),紧急指针的值表示,从当前位置往后多少个字节位置的部分,要进行插队的(使用比较少)

ACK: 应答报文

PSH:崔楚对方,尽快把缓冲区的数据交给应用程序

RST:复位报文

SYN:同步报文

FIN:结束报文

http://www.xdnf.cn/news/970993.html

相关文章:

  • C++:std::is_convertible
  • <7>-MySQL内置函数
  • Python训练营-Day27-函数专题2:装饰器
  • Java如何权衡是使用无序的数组还是有序的数组
  • copilot基于 DeepSeek-R1 思路构建 VLA 自动驾驶强化学习系统
  • 华为云Flexus+DeepSeek征文|体验华为云ModelArts快速搭建Dify-LLM应用开发平台并创建联网大模型
  • QMC5883L的驱动
  • iview组件库:自定义方法去控制Tree树形数据的根节点与叶节点的关联性
  • Android Studio jetpack compose折叠日历日期选择器【折叠日历】
  • IOC和AOP
  • vue实现气泡词云图
  • FastJson的反序列化问题入门
  • Qt使用ODBC连接MySQL数据库
  • R7-1 显示Pascal三角形
  • 【代码模板】从huggingface加载tokenizer和模型,进行推理
  • idea64.exe.vmoptions配置
  • IDEA中配置HTML和Thymeleaf热部署的步骤
  • 蓝桥杯 2024 15届国赛 A组 儿童节快乐
  • 指针与引用参数传递的区别及内存操作流程详解
  • 分散电站,集中掌控,安科瑞光伏云平台助力企业绿色转型
  • 高通录像功能
  • Vim 光标移动命令总览
  • Java中高并发线程池的相关面试题详解
  • 《ZLMediaKit 全流程实战:从部署到 API 调用与前后端集成》
  • 用 LoRA 对 Qwen2.5-VL 模型进行SFT - FORCE_TORCHRUN=1
  • 条件运算符
  • error: src refspec master does not match any - Git
  • coze的基本使用
  • 从零开始搭建现代化 Monorepo 开发模板:TypeScript + Rollup + Jest + 持续集成完整指南
  • Git操作问题及解决方案-记录5