【JavaSE】【网络原理】UDP和TCP原理

【JavaSE】【网络原理】UDP和TCP原理

目录

一、UDP协议

UDP在前面套接字编程介绍了特点是:
无连接、不可靠传输、面向数据报、全双工。

UDP协议格式:

  • 16位UDP⻓度,表⽰整个数据报 (UDP⾸部+UDP数据) 的最⼤⻓度,0 - 65535,也就64KB;
  • 16位UDP校验和:如果校验和出错,就会直接丢弃;

校验和的作用:

  • 防止传输过程出现比特翻转(比特翻转就是指:数据受到外界干扰,0变1,1变0)
发送之前,先计算一个校验和,把真个数据报的数据都代入
把数据 和 校验和 一起发送给对端
接收方收到之后重新计算一下校验和,和收到的校验和进行对比(UDP发现校验和不一致,就会直接丢弃)
UDP的校验和使用了CRC方式来进行校验(循环冗余校验)
把每个字节(除了校验和位置的部分之外),都当做整数进行累加.溢出也没关系,继续加
最终得到结果CRC校验和
传输到对端时,数据如果出现错误了,对端再次计算的校验和,就会和第一个校验和不一样了
校验和相同,原始数据可能相同(原始数据不同发生的概率非常小)。
校验和不同,原始数据一定不同。

这样的机制虽然也有错,因为一个数据和对应的数据不是唯一的,但是这种是小概率事件。

二、TCP协议

2.1 TCP结构

TCP在前面套接字编程介绍了特点是:
有连接、可靠传输、面向字节流、全双工。

TCP格式:

  • 4位首部长度:表⽰该TCP头部有多少个32位bit (有多少个4字节);所以TCP头部最⼤⻓度是15 * 4 = 60 字节
  • 选项:选项就是确定TCP长度是可变的,固定长度是20字节,选项最多增加40字节
  • 保留位:UDP长度不够时,不能扩展,而保留位就是TCP预留解决这种问题的。
  • 6个标志位:
    • URG:紧急指针(相当于“插队”,跳过前面数据,从指定序号开始)是否有效
    • ACK:确认号是否有效
    • PSH:催促标志位,提⽰接收端应⽤程序⽴刻从TCP缓冲区把数据读⾛
    • PST:对⽅要求重新建⽴连接;我们把携带RST标识的称为复位报⽂段
    • SYN:请求建⽴连接;我们把携带SYN标识的称为同步报⽂段
    • FIN:通知对⽅,本端要关闭了,我们称携带FIN标识的为结束报⽂段
  • 16位校验和:校验数据是否出现错误
  • 16位紧急指针:标识哪部分数据是紧急数据

2.2 TCP十大核心机制

2.2.1 确认应答

保证可靠性:那就肯定需要,发送放知道接收方是否接收到请求,接收方返回一个“应答报文(acknowledge ,ack)”

如果有这种情况:后发先至

网上做题是答案是对应题目的,但是如果你先写的第一题答案,后写的第二题答案,由于传输问题,导致第二题答案先到。那么如果没有题号对应的话,那么就可能填在第一题去了。所以TCP也引入的类似题号作用的东西:序列号

TCP将每个字节的数据都进⾏了编号。即为序列号。
每⼀个ACK都带有对应的确认序列号,意思是告诉发送者,该确认序号前的数据都已经收到;下⼀次你从哪⾥开始发。

2.2.2 超时重传

超时重传是为了应对丢包问题。

丢包:数据无法到达指定位置。

丢包两个原因:假如主机A发送数据给主机B主机A发送的数据,由于各种原因,没能到达主机B,造成丢包主句B返回的应答数据,由于各种原因,没能到达主机A,造成丢包

TCP就引入超时时间(TCP中判定超时的时间阈值,不是固定值,动态变化),来应对丢包情况,
当超出超时时间,还没有接收到应答报文,那么就是出现丢包(无论哪种原因造成),那么都会重新发送这条数据。

超时时间的动态变化机制:

TCP为了保证⽆论在任何环境下都能⽐较⾼性能的通信,因此会动态计算这个最⼤超时时间。Linux中(BSD Unix和Windows也是如此),超时以500ms为⼀个单位进⾏控制, 每次判定超时重发的
超时时间都是500ms的整数倍.如果重发⼀次之后, 仍然得不到应答, 等待 2*500ms 后再进⾏重传.如果仍然得不到应答, 等待 4*500ms 进⾏重传. 依次类推, 以指数形式递增.累计到⼀定的重传次数, TCP认为⽹络或者对端主机出现异常, 强制关闭连接.

确认应答和超时重传是确认TCP可靠传输的最核心机制

2.2.3 连接管理

TCP中连接是逻辑上的连接,都保留对端的信息,不是物理上的连接。

两个主机间的连接管理,TCP通过三次握手机制建立连接,四次挥手断开连接。

2.2.3.1 三次握手建立连接

过程简述:主机A与主机B通信

主机A先发一个状态码为syn的报文给主机B(相当于我给你打电话,你接通后,我先说一个喂)主机B接收到主机A发的报文后,也要发一个状态码为ack的应答报文,还要发送一个syn报文,这两个报文可以一起发送。(这就相当于打电话,你听到了我说喂,你回一个干嘛)主机A收到主机B的报文后,要发送一个状态码为ack的应答报文。(就相当于打电话,我知道你那边听筒和麦克风正常,我就开始说事了,你听到我说事,也就知道我设备没问题,但是在TCP中要应答报文,让主机B知道,然后才是发送数据)

syn和ack报文简述:

syn报文,就是通知对端我要和你建立连接了,这里面包含了发送端的信息,让对端保存好ack报文,就是通知对端你发的报文,我收到了,将信息记录好了。

三次握手简图:

三次握手机制好处:

  1. 三次握手,相当于“投石问路”,初步探索一下网络通信链路是不是畅通的
  2. 验证通信双方的发送和接收能力是不是正常的。
  3. 三次握手过程中,是可以协商一些关键数据的,比如通信的初始序号
2.2.3.2 四次挥手断开连接

过程简述:主机A与主机B通信

主机A先发一个状态码为FIN的报文给主机B(相当于我给你打电话,我要挂电话了,我说我要挂电话了,你还有事吗)主机B接收到主机A发的报文后,也要发一个状态码为ack的应答报文,(这就相当于打电话,你听到了我说要挂电话了)还要发送一个FIN报文。(这就相当于打电话,你听到了我说要挂电话了,你回一个ok)主机A收到主机B的报文后,要发送一个状态码为ack的应答报文。(就相当于打电话,我挂电话)

在四次挥手时:接收端发送的FIN和ACK报文如能合并。

接收端发送的FIN和ACK报文,只有在延时应答机制下才能合并。而其他时候不能合并。因为ACK的报文是操作系统内核发的,而FIN报文是程序猿代码调用到Socket的close方法才发送的。

四次握手简图:

三次握手与四次挥手的丢包问题:

三次握手无论哪个报文发生丢包,触发超时重传就可以解决。
四次挥手中在除了最后发送端(主机A)的ACK报文外,其它报文发生丢包问题,触发超时重传就可以解决。
当发送端(主机A)接收到了FIN,直接发送ACK,同时释放这次资源,那么如果ACK丢包,主机B重传FIN后,主机A都不认识了。这是就引入一个TIME-WAIT状态(在接收到了FIN后等一定时间),再释放资源。

CLOSE-WAIT:

⼀般⽽⾔,对于服务器上出现⼤量的 CLOSE_WAIT 状态, 原因就是服务器没有正确的关闭 socket, 导致四次挥⼿没有正确完成. 这是⼀个 BUG. 只需要加上对应的 close 即可解决问题.

三次握手和四次挥手的详图(出自《图解TCP/IP》)

2.2.4 滑动窗口

滑动窗口:

像在发送数据报的时候,我们发一条等待对方接收一条返回一条应答报文,那么和发一堆再进入等待状态相比,明显后者的效率更高。
滑动窗口就是指第二种发数据方式。

滑动窗口机制解析:

窗口大小:就是指无需等待的数据报数量,也就是第一次可以发送的最大值。操作系统内核为了维护这个滑动窗⼝, 需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答; 只有确认应答过的数据, 才能从缓冲区删掉;滑动窗口的大小要适量,过大会影响TCP的可靠性,过小对效率提升没啥作用。

进出数据:滑动窗口中的数据,接收到了哪个确认序列号,就将滑动窗口的头移动到对应的确认序列号的数据地方

滑动窗口中的丢包问题:

数据报丢了
快速重传:在滑动窗口下的变种机制。
2.1. 当某⼀段报⽂段丢失之后, 发送端会⼀直收到 1001 这样的ACK, 就像是在提醒发送端 “我想要的是1001” ⼀样;
2.2. 如果发送端主机连续多次都收到了同样⼀个 “1001” 这样的应答, 就会将对应的数据 1001 - 2000 重新发送;
2.3. 这个时候接收端收到了 1001 之后, 再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就
已经收到了, 被放到了接收端操作系统内核的接收缓冲区中;

数据报已经抵达, ACK丢了。
这种情况,不用任何处理,因为后面到达的ACK的确认序号就包含了,前面的数据都接收到了的意思。

2.2.5 流量控制

流量控制:

接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满(就像小学数学小明给泳池一边放水一边蓄水一样), 这个时候如果发送端继续发送, 就会造成丢包, 继⽽引起丢包重传等等⼀系列连锁反应.
因此TCP⽀持根据接收端的处理能⼒, 来决定发送端的发送速度. 这个机制就叫做流量控制(Flow Control);

如何实现流量控制:

  • 接收端将自己的接收缓冲区剩余的容量,通过TCP首部的“十六位窗口大小”字段,通过ACK发给发送端,发送端根据这个值来设置滑动窗口大小,来实现流量控制。

特点:

  • 16位数字最⼤表⽰65535,但是TCP窗⼝最⼤却不是65535字节么。实际上,TCP⾸部40字节选项中还包含了⼀个窗⼝扩⼤因⼦M,实际窗⼝⼤⼩是 窗⼝字段的值左移 M 位;
  • 如果接收端缓冲区满了,就会将窗⼝置为0;这时发送⽅不再发送数据,但是需要定期发送⼀个窗⼝探测数据段,使接收端把窗⼝⼤⼩告诉发送端。

流程解释图:

2.2.6 拥塞控制

拥塞控制:依据通信链路的转发能力,进行限制。

找拥塞控制的滑动窗口的大小:

我们前面的流量控制的滑动窗口的大小,直接是TCP首部字段带的。但是我们通信链路没这个功能,我们就将通信链路当一个整体,先按照小的窗口发着,一直加大窗口,当窗口过大,发生丢包就减小窗口到较小值,再次执行前面操作,又增大窗口(面多加水,水多加面),让窗口大小一直处于丢包临界值动态平衡。

图解:

  • 慢启动:初始的小窗口大小
  • ssthresh初始值:预设的窗口大小
  • 过程解析:慢启动 -> 指数增长 -> 线性增长 -> 丢包,窗口变回较小值

滑动窗口的最终大小取决于拥塞控制和流量控制的较小值。

2.2.7 延时应答

延时应答:

默认情况,接收方收到数据报第一时间返回ACK,但是可以通过延时应答,延时返回ACK的方式提高效率。
返回窗口的大小跟流量控制,接收缓冲区剩余容量的大小有关,当接收到数据报的时候,等一会,程序就会消耗缓冲区的数据报,这样我们返回的ACK的窗口大小(剩余容量)就可以比不等直接返回的大,提高效率。

但是如果程序消耗的速度比不上发送方的发送速度,引入延时机制相反还会是窗口大小变小,降低效率。

延时应答限制:

  • 数量限制: 每隔N个包就应答⼀次;
  • 时间限制: 超过最⼤延迟时间就应答⼀次;

图解:

2.2.8 捎带应答

捎带应答:

引入了延时应答,接收方得到数据后,不会立刻返回当前数据报的ACK,那么下次返回数据的时候,捎带把上次的ACK带回去。

图解:

2.2.9 面向字节流

面向字节流:

创建⼀个TCP的socket, 同时在内核中创建⼀个 发送缓冲区 和⼀个 接收缓冲区;
• 调⽤write时, 数据会先写⼊发送缓冲区中;
• 如果发送的字节数太⻓, 会被拆分成多个TCP的数据包发出;
• 如果发送的字节数太短, 就会先在缓冲区⾥等待, 等到缓冲区⻓度差不多了, 或者其他合适的时机发
送出去;
• 接收数据的时候, 数据也是从⽹卡驱动程序到达内核的接收缓冲区;
• 然后应⽤程序可以调⽤read从接收缓冲区拿数据;
• 另⼀⽅⾯, TCP的⼀个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这⼀个连接, 既可以读数据, 也可以写数据. 这个概念叫做 全双⼯
由于缓冲区的存在, TCP程序的读和写不需要⼀⼀匹配, 例如:
• 写100个字节数据时, 可以调⽤⼀次write写100个字节, 也可以调⽤100次write, 每次写⼀个字节;
• 读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以⼀次read 100个字节, 也可以⼀
次read⼀个字节, 重复100次;

粘包问题:

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

解决方法:

  • 在TCP角度无解,在应用层解决。
  • 法1:约定包与包之间的分隔符(包的结束标志);
  • 法2:约定包的长度(例如固定开始几个字节表示接下来的数据包的长度)

2.2.10 异常情况处理

  • 进程终⽌:进程终⽌会释放⽂件描述符,仍然可以四次挥手发送FIN。和正常关闭没有什么区别。
  • 机器重启/正常关机:本质上还是先杀死所有进程,和进程终⽌的情况相同。
  • 接收端掉电:触发超时重传,触发“重置连接”,发送方方主动发送一个复位报文RST,还没回应就断开连接。
  • 发送方掉电:发送方一直不发,接收方等到一定时间,像发送方传输一个特殊报文“心跳包”,不携带数据,为了触发ACK,还是没有就断开连接。
  • ⽹线断开:就是相当于接收方和发送方同时掉电了。两边都进行操作。

三、TCP、UDP对比

TCP,UDP对⽐:

  • TCP是可靠连接,但是TCP不⼀定就优于UDP。TCP和UDP之间的优点和缺点,不能简单、绝对的进⾏⽐较
  • TCP⽤于可靠传输的情况,应⽤于⽂件传输,重要状态更新等场景;
  • UDP⽤于对⾼速传输和实时性要求较⾼的通信领域,例如,早期的QQ,视频传输等。另外UDP可以⽤于⼴播;

Read more

Java IO 流进阶:Buffer 与 Channel 核心概念解析及与传统 IO 的本质区别

Java IO 流进阶:Buffer 与 Channel 核心概念解析及与传统 IO 的本质区别

在 Java IO 编程中,传统的字节流与字符流大家都不陌生,但当面对高并发、大文件处理等场景时,NIO(New IO)中的 Buffer 与 Channel 逐渐成为性能优化的关键。本文将深入剖析 Buffer 与 Channel 的核心概念,通过对比传统 IO 流,带你理解它们为何能显著提升 IO 效率,并配合直观的图示帮你建立清晰的认知。 一、传统 IO 流的局限性:为什么需要 Buffer/Channel?         在了解 Buffer 与 Channel 之前,我们先回顾传统 IO 流的工作方式。传统 IO 流分为字节流(InputStream/OutputStream) 和字符流(Reader/Writer)

By Ne0inhk
飞算JavaAI:人工智能与Java的创新融合与应用前景

飞算JavaAI:人工智能与Java的创新融合与应用前景

目录 引言 一、飞算JavaAI的背景与发展 二、飞算JavaAI的技术架构 1. 核心模块: 2. AI算法库: 3. 模型训练与调优: 4. 接口与集成: 三、飞算JavaAI的创新特点 1. 高效的数据处理能力: 2. 与Java生态的深度结合: 3. 自动化模型调优: 4. 可扩展性与灵活性: 四、真实体验—智能引导功能 五、飞算JavaAI的应用场景 1. 金融领域: 2. 智能制造: 3. 医疗健康: 4. 智能推荐系统: 六、飞算JavaAI面临的挑战 1. 计算资源要求: 2. 技术门槛: 3. 跨平台支持: 七、总结 正文开始—— 引言 随着人工智能(

By Ne0inhk
基于飞算JavaAI的在线图书借阅平台设计与实现(深度实践版)

基于飞算JavaAI的在线图书借阅平台设计与实现(深度实践版)

摘要: 本文以从概念到落地,完整构建一个“在线图书借阅平台”的全过程。文章不仅覆盖了环境配置、需求分析、接口设计、数据库建模等基础流程,更着重于展示AI自动生成的项目核心代码,并在此基础上进行了详尽的功能扩展和代码优化。通过对用户管理、图书管理、借阅与归还等关键业务模块的详细代码实现与注释,本文旨在全面、深入地展现飞算JavaAI在真实项目开发中的强大能力,探讨其如何重塑传统Java开发范式,显著提升开发效率与代码质量。 一、引言 在软件工程领域,随着业务逻辑的日益复杂化和市场对产品迭代速度的严苛要求,传统的纯手动编码模式正面临前所未有的挑战。开发周期长、人力成本高、代码质量参差不齐、技术债累积等问题,成为制约项目成功的重要因素。正是在这样的背景下,人工智能辅助编程(AI-Assisted Programming)应运而生,它通过将大型语言模型与软件工程知识深度融合,旨在自动化处理开发流程中的重复性、模式化任务,使开发者能够聚焦于更具创造性的核心业务逻辑。 飞算科技推出的飞算JavaAI,正是这一变革浪潮中的杰出代表。它作为一款深度集成于IntelliJ IDEA的智能插件,能够

By Ne0inhk
JAVA最新版本详细安装教程(附安装包)

JAVA最新版本详细安装教程(附安装包)

目录 文章自述 一、JAVA下载 二、JAVA安装 1.首先在D盘创建【java/jdk-23】文件夹 2.把下载的压缩包移动到【jdk-23】文件夹内,右键点击【解压到当前文件夹】 3.如图解压会有【jdk-23.0.1】文件 4.右键桌面此电脑,点击【属性】 5.下滑滚动条,点击【高级系统设置】 6.点击【环境变量】 7.找到系统变量(S),然后点击【新建】 8.输入变量名和变量值 9.确认无误,点击【确定】 10.继续点击系统变量下的【新建】 11.输入变量名和变量值

By Ne0inhk