【Java网络原理】 五

news2024/12/24 20:50:31

本文主要介绍了TCP传输控制协议的报头字段意义以及TCP协议的十大核心特性。

一.TCP传输控制协议

1.TCP报文格式

>端口

范围是0-65535 ,只有确定了端口号,才知道把数据报交给哪个应用程序。

>4位首部长度

TCP报头是变长的, 4bit的范围是0-15

此处的单位是4字节,因此真正的长度要乘4得到

因此tcp报头最大长度是15*4=60字节

而前20个字节是固定的,因此tcp报头的最短长度是20字节

使用首部长度,来确认报头到哪里结束,载荷数据从哪里开始;

>选项

报头变长的体现,可以有,也可以没有,选项的长度也决定了报头最后的长度

>保留(6位)

目前未使用,先占个位置,后面可能需要使用,给未来留下扩展的空间

>32位序列号

>32位确认序列号

>16位校验和

>16位窗口大小

>16位紧急指针

二.TCP十大核心特性

1.确认应答

确认应答是保证可靠性最核心的机制

TCP是有连接,可靠传输,但是由于可靠传输是内核实现的,程序员写代码的时候,并不能很好的感知。

比如:我对女神发出提问,女神对我的问题返回了一个应答

当发送多条数据的时候,可能会出现后发先至,这会导致女神的应答乱套

解决方法是:对发送的报文进行编号,女神对我的应答也进行编号

比如:

TCP中,面向字节流传输

1.针对字节进行编号,而不是针对条

对于一串要传输的字节,只要知道这串字节的开始编号(报头的32位序号指明),以及数据的长度,每个字节的编号自然也就知道了

2.应答报文也是和收到的数据的序号相关联

比如:

报头中的32位序号:报文的第一个字节的序号

32位确认序号:收到的最后的一个序号+1

确认报文 ACK:

如果ACK0 :表示这是一个普通报头,此时只有32位序号有效

如果AXK1:表示i这是一个应答报文,此时 序号 确认序号 都有效

确认应答,是TCP保证可靠性的最核心机制!

注意:在TCP报文中,是无法知道它的载荷数据是多长的,只能结合IP协议才知道,TCP载荷长度=IP载荷长度 - TCP报头长度

丢包:网络上,很可能发送一个数据,然后丢了。

往往是因为网络繁忙,后面等的数据太久了,就可能被丢弃了,网络负载越高,越繁忙,就越容易丢包

如果真的丢了,发送方就会启动超时重传

2.超时重传

超过一定时间之后,就将报文进行重传

我们把丢包分两种:

1.发的消息本身丢了

>触发超时重传

2.应答报文丢包了

>也会触发超时重传,发送方一旦重传,接收方同一消息收到了两次,就会出现问题,因此接收方需要把重复的数据丢弃,调用inputStream.read的时候,读到的不会出现重复

去重

直接使用tcp的序号作为判定依据,tcp会在内核中,给每个socket都安排一个内存空间,相当于一个队列,也称为 接收缓冲区

收到的数据,都会被放到接收缓冲区里,并且按照序号排列好顺序

收到数据,接收方的网卡,把数据放到对应的socket的接收缓冲区中,应用程序调用read,就相当于从这个接收缓冲区消费数据;

当被read走,就可以从队列中删除了

由于接收缓冲区是按照序号有序排列的,如果排列队首元素序号,已经超过新收到的这个数据的序号,表明新收到的数据对应的数据之前已经被读过

对方上述两种情况,发送方是无法区分的

注意:

1.由于接收缓冲区会对数据排列好顺序,就不必考虑数据传输的先后顺序了,因此也解决了后发先至的问题。

2.

正常情况下,丢包概率比较小,重传可以提高传输成功的可能性。

另外啊,超时时间不是固定的值,会随着轮次的增加,进一步增加

如果重传次数达到一定程度,就会放弃重传,此时就会尝试 重置TCP连接

TCP复位报文 

RSI如果为1就是复位报文

如果网络中出现严重故障,复位操作也无法成功,最终就会删除保存的对端的信息

超时重传也是TCP可靠性机制的有效补充

3.连接管理

1.建立连接  -->三次握手

握手:发一个发招呼的数据,并不会携带业务信息

A和B完成建立连接的过程,就需要三次这样的打招呼的数据交互

注意:中间的两次可以合并成一次。

为什么合并?

合并之后,节省了封装和分用的过程,降低成本提高了效率,而且还能起到消息协商的效果。

消息协商

通信的时候涉及到一些参数,需要双方保持一致,通过协商,来确定参数。

比如双方的序号从几开始(一般不从0/1),这样做主要是保证两次连接,消息的序号能够有较大的差异,从而去判定出某个消息是否属于这个连接的

比如:某个消息知道直到连接断开才到达对端,此时的连接已经不是彼时的连接了,这个时候,就可以通过序号,明显判别出这个是上一个连接的消息,就可以直接丢弃。

总结:

三次握手的初心有两方面

1.投石问路,验证通信路径是否畅通,双方的发送/接收能力是否正常

2.协商必要的参数,使客户端和服务器使用相同的参数进行消息传输

ACK是应答报文

SYN申请建立连接的请求 同步报文段

三次握手的过程可以化简成如下:

2.断开连接  -->四次挥手

连接,通信双方在各自的内存中保存了对端的信息;如果不需要连接了,就得即使释放上述的空间

FIN 为1,就是结束报文段

经过上述四个步骤之后,连接就彻底不能使用了,双方就可以把各自保存的对端信息的空间释放了


四次挥手:

为什么是四次?能不能是合并?

FIN的触发,是应用程序代码控制的,调用socket.close()或者进程结束,就会触发FIN;ACK则是内核控制的收到FIN立即就会返回ACK

因此,如果close执行的快,也有可能立即触发FIN,导致ACK和FIN的合并,形成三次挥手。


问题:

1.如果服务器始终不close会怎样,客户端的连接就始终不关闭吗?

此时,服务器的TCP状态,就处于CLOSE_WAIT状态

站在服务器的角度,虽然这里的连接没有关闭,但是这个连接其实已经不能正常使用了

针对当前socket进行读操作,如果数据还没读完,能正常读到缓冲区的数据;如果已经读完了,此时就会读到EOF

针对当前socket进行写操作,直接就会触发异常;

无论无何,这个连接,已经没用了,关闭是唯一的选择。更极端情况,忘记写close了,等不到关闭,就会单方面放弃连接。

2.如果通信中,出现丢包了,怎么办?

尽可能重传,如果重传仍然失败,连续多次,此时仍然会单方面释放连接

丢包分两种情况:

1.第一组丢了

客户端直接重传FIN即可

2.第二组丢了

>FIN丢了  重传

>ACK丢失 

如果最后一个ACK丢失,B就会重传一个FIN;如果此时A已经释放连接了,重传的FIN就无人进行ACK了;

因此,需要让A在发出去最后一个ACK之后让连接等一会;如果等了一会之后,对方没有重传FIN,就认为ACK已经被收到了

此时A才能正确释放连接。

A等待的这个时候叫做:MSL等待时间是网络上任意两点之间传输数据的最大空间*2

4.滑动窗口

提高传输效率,更准确的说是让TCP的可靠传输的前提下,效率不要太拉跨

如果滑动窗口发一次数据等待一个应答,就会导致消耗大量的时间等待ack,使用滑动窗口,就是为了缩短上述等待时间:

有滑动窗口:

批量发送:一次性发一组数据,发这一组数据的过程中,不需要等待ack,此时就相当于用一份等待时间等四个ack

窗口:一次性发多少数据,不用等ack这样的大小

窗口越大,批量发送的数据就越多,效率就越高;当然不能无限大,接收方能否处理过来,中间的网络设备能否承受住,都是未知数。

滑动窗口是一个形象的比喻,实质上就是批量发送数据。


问题:丢包

>数据丢了

>重传

比如:当1001-2000丢失,即使2001-3000数据到达,B返回的ACK确认序号仍然是1001

也就是索要1001数据,当A连续多次收到来自B的索要1001数据,A就会重传1001-2000.

>ACK丢了

不用做任何处理!

确认序号:该序号之前的数据都收到了!

比如,就算A没有收到1001确认序号,但是收到了2001序号,就足以表明1001已经收到了。

除非所有ACK都丢了,否则丢一部分,都是没有影响的!

注意:

滑动窗口不是使用TCP一定会涉及的,如果通信双方大规模传输数据,会有滑动窗口;如果数据规模小,那么就不会使用滑动窗口;

5.流量控制

作为滑动窗口的补充,给滑动窗口踩刹车

滑动窗口,窗口越大,传输效率越高

但是传输的窗口也不能无限大,如果太大,接收方/中间链路就可能处理不过来,这样一旦丢包,就得重传,窗口大反而影响了效率。

接收缓冲区

发送方发过来的数据会先放到接收方的接收缓冲区;如果这个缓冲区满了,继续发数据,就会丢包。

流量控制就是根据接收方的处理能力,来限制发送方的发送速度(窗口)

如何衡量接收方的处理速度

此处使用接收缓冲区剩余空间大小来作为衡量指标。

报头中的16位窗口大小:只对ack报文才有意义

这个数字返回给发送方,就可以作为下一轮发送的参考数据。

对于大小:

选项中有一个选项是窗口大小扩展因子

实际的窗口大小是16位窗口<<扩展因子(此时就很大了)

当接收缓冲区满的时候,发送方就会等待,周期性的发送窗口探测包(不会携带具体数据),只是为了触发ACK,查询当前接收缓冲区的情况,当不是0了,就可以继续发送了。


6.拥塞控制

总的传输效率,是一个木桶效应,取决于最短板

如果中间某个环节,转发能力比较差,此时发送方的发送速度就不应该超过这里的阈值

具体怎么去衡量中间设备的转发能力呢

采用实验的方式动态调整

1.使用一个较小的窗口传输,如果传输通畅,就调大窗口

2.使用一个较大的窗口,如果出现丢包/堵塞,就调小窗口

拥塞控制:

1.慢启动

刚开始通信的时候,先使用一个非常小的窗口

2.指数增长(*2)

3.线性增加(+n)

4.拥塞窗口回归小窗口

当窗口增长过程中,如果传输出现丢包,就把窗口调整为最初的小窗口,继续回到指数增长,线性增长,并根据丢包的窗口大小,调整阈值(丢包窗口大小/2)

 这样的调整就可以很好的适应多变的网络环境。

实际发送的窗口=min(拥塞窗口,流量控制窗口)

拥塞控制和流量控制,共同限制了滑动窗口机制,可以使滑动窗口,能够在可靠性的前提下,提高传输效率。


7.延迟应答

提高传输效率的机制

在返回ack的时候,拖延一点时间,就可以给应用程序腾出更多的消费数据,接收缓冲区的剩余空间就更大了。

此处,到底通过延迟应答能提高多少速度,还是取决于接收方的实际出列能力

8.捎带应答

在延时应答的基础上,引入进一步提高效率的方式

延时应答是让ack传输的时机更慢

捎带应答是基于延时应答,让数据进行合并

比如:

由于ack会延时应答,响应就可以直接捎带上ack一起发送

数据报合并成一个,效率会有明显的提升

能合并的原因:

1.时机上是可以同时的

2.ack 数据本身不携带载荷,和正常的数据也不冲突,完全可以让这一个数据报,既可以携带在载荷数据又带有ack的信息


9.面向字节流

在面向字节流的情况下,会产生粘包问题(粘的是应用层数据报)

通过tcp read/write的数据,都是tcp报文的载荷,也就是应用层数据

 发送方一次性是可以发送多个应用层数据报的,但是接收的时候,怎么区分一个完整的数据报

解决方法是,设计合理的应用层协议

1.应用层协议中,引入分隔符,区分包之间的边界

2.应用层协议中,引入包长度,也能区分包之间的边界


10.TCP异常情况处理

网络本身就会存在一些变数,导致tcp连接不能继续正常工作

(1)进程崩溃

进程没来-->PCB没了 --> 文件描述符表也就没了  -->相当于调用socket.close()

崩溃的这一方就会发出FIN,进一步触发四次挥手,此时连接就正常释放了

此时tcp的处理和进程正常退出没啥区别

(2)主机关机(正常关机)

正常关机,就会先强制终止所有的进程,就和上面的情况是一样的

主机关机会有一定的时间,在这个时间之内,四次挥手可能没挥完,但是也没关系

如果有包没送达,自然会单方面释放。

(3)主机掉电

瞬间掉电,没有任何可以操作的空间,此时无法发任何FIN

两种情况

a.如果A给B正在给B发消息,B掉电,A等不到ack就会单方面释放连接

b.如果A给B发消息,A掉电,B在等A的消息,B会阻塞等待

心跳包

B会周期性给对方发送一个不携带任何业务数据的tcp数据报,目的就是为了触发ack,确认一下A是否正常工作/确认网络是否畅通

和前面说的流量控制的窗口探测报文,是一样的。

(4)网线断开

和主机掉电一样~

最后再回顾一下TCP十大核心特性(当然TCP不止这十个特性!!)

关于TCP和UDP的对比

TCP优势在于可靠性,适用于绝大部分场景

UDP优势在于效率,适用于机房内部主机之间的通信

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1144485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Servlet核心API

目录 HttpServlet init destory service 实例&#xff1a;处理get、post、put、delete请求 1.通过postman得到请求 2.通过ajax得到请求 HttpServletRequest 常见方法 前端给后端传参 1.GET,query string 2.POST,form 3.POST&#xff0c;json HttpSeverletRespons…

数据类型与运算符-java

数据类型与运算符 1、变量和类型 1.1、整形变量 基本语法格式&#xff1a; int 变量名 初始值;代码示例&#xff1a; int num 10 //定义一个整型变量 System.out.println(num);注意&#xff1a; 1&#xff09;java中&#xff0c;一个int变量占4个字节&#xff0c;和操作…

【ChatGPT系列】ChatGPT:创新工具还是失业威胁?

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

进程、线程、处理机调度

程序&#xff1a;存放在磁盘中的可执行二进制文件&#xff08;即*.exe文件&#xff0c;包含一系列指令集合&#xff09;。是静态的。 进程&#xff1a;程序的一次执行过程。是动态的。同一个程序多次执行将对应多个进程。 线程&#xff1a;轻量级进程。一个进程至少有一个线程…

qml之ui控件

文章目录 ui控件移动版风格嵌套页面并排界面 ui控件 Qt Quick控件用于创建由标准化组件&#xff08;如按钮、标签、滑块等&#xff09;构建的用户界面。 QtQuick.Controls&#xff1a;基本控件。QtQuick.Templates&#xff1a;为控件提供行为化的、非可化视的基本类型。QtQui…

STM32 CAN使用

STM32 CAN使用 简介各种通讯接口对比报文总线上的报文信息表示为几种固定的赖类型数据帧列表模式掩码模式配置CAN配置参数位时序 简介 控制器局域网CAN&#xff08;Controller Area Network)是由德国博世公司为汽车应用而开发的多主机局部网络&#xff0c;用于汽车的监测和控制…

React 生成传递给无障碍属性的唯一 ID

useId() 在组件的顶层调用 useId 生成唯一 ID&#xff1a; import { useId } from react; function PasswordField() { const passwordHintId useId(); // ...参数 useId 不带任何参数。 返回值 useId 返回一个唯一的字符串 ID&#xff0c;与此特定组件中的 useI…

【CSS】包含块

CSS规范中的包含块 包含块的内容&#xff1a; 元素的尺寸和位置&#xff0c;会受它的包含块所影响。 对于一些属性&#xff0c;例如 width, height, padding, margin&#xff0c;绝对定位元素的偏移值&#xff08;比如 position 被设置为 absolute 或 fixed&#xff09;&…

『第十章』仪态万千的雨燕:UIKit 和 SwiftUI

在本篇博文中,您将学到如下内容: 1. 老骥伏枥:AppKit 和 UIKit2. 雨燕的新装:SwiftUI3. SwiftUI 原生视图4. SwiftUI 容器4.1 ViewThatFits4.2 自定义布局(Custom Layout)6. SwiftUI 修改器(Modifiers)6.1 修改器修饰作用域6.1 自定义修改器5. SwiftUI 状态:真相之源(S…

在spring boot+vue项目中@CrossOrigin 配置了允许跨域但是依然报错跨域,解决跨域请求的一次残酷经历

首先&#xff0c;说一下我们的项目情况&#xff0c;我们项目中后端有一个过滤器&#xff0c;如果必须要登录的接口路径会被拦下来检查&#xff0c;前端要传一个token&#xff0c;然后后端根据这个token来判断redis中这个用户是否已经登录。 if (request.getMethod().equals(&qu…

20、Python -- 变量作用域、局部函数

目录 变量作用域变量&#xff1f;字典&#xff1f;获取变量字典变量遮蔽解决方法&#xff1a;方法1&#xff1a;使用globals访问全局变量方法2&#xff1a;在函数中声明全局变量 局部函数封闭函数返回局部函数代码演示另一种写法 局部函数的遮蔽问题如图&#xff1a;解决方法&a…

深入理解Java中的转义字符

最近在学习《两周自制脚本语言》这本书&#xff0c;在词法分析的一些复杂的正则中用到了大量的转义字符’\&#xff0c;比如正则字符串中包含了这个部分\\\\\"你知道它是匹配什么的么&#xff1f; 反斜杠在字符串和正则表达式中都有特殊作用。今天让我们来深入理解一下Ja…

如何使用drawio画流程图以及导入导出

画一个基本的流程图 你可以在线使用drawio, 或者drawon创建很多不同类型的图表。 如何使用编辑器&#xff0c;让我们以一个最基本的流程图开始。 流程图&#xff0c;就是让你可视化的描述一个过程或者系统。 图形和很少部分的文字表达就可以让读者很快的理解他们需要什么。 创…

文心大模型走进高校!百度携手吉林大学计算机学院成功举办AI师资培训

随着人工智能技术的快速发展&#xff0c;大模型已经成为了人工智能的主流发展方向&#xff0c;同时也对新时代AI人才的培养带来了新的思考与挑战。为了推动大模型及人工智能相关专业人员的培养&#xff0c;10月20日-22日&#xff0c;百度飞桨携手中国电子学会&#xff0c;吉林大…

@TableLogic 这个注解的作用

TableLogic 是 MyBatis-Plus&#xff08;一个 MyBatis 的增强工具&#xff09;提供的一个注解&#xff0c;用于实现逻辑删除功能。 逻辑删除并不是真正从数据库中删除记录&#xff0c;而是通过在数据库表中设置一个标记字段&#xff08;通常是一个状态字段&#xff0c;如 is_d…

【Linux】部署及发布单机项目及前后端分离的项目

目录 一、讲述 1. 为什么 2. 要求 二、单机项目 1. 本机测试 2. 部署 三、前后端 1. 准备 2. 部署 一、讲述 1. 为什么 实施部署和发布项目的目的是将软件开发的成果转化为可用的产品或服务&#xff0c;以满足用户的需求。以下是实施部署和发布项目的一些重要原因&am…

Proteus仿真--闪烁的LED灯

本文介绍一种基于51单片机实现的LED灯闪烁仿真&#xff08;完整仿真源文件及代码见文末链接&#xff09; 本文主要介绍51单片机的LED闪烁仿真设计&#xff0c;仿真文件截图如下&#xff1a; 仿真视频如下&#xff1a; Proteus仿真--闪烁的LED灯 附完整Proteus仿真资料代码资…

NlogPrismWPF

文章目录 Nlog&Prism&WPF日志模块实现原理添加配置注入服务应用测试其他模块怎么调用&#xff1f; Nlog&Prism&WPF 日志模块 介绍了为WPF框架Prism注册Nlog日志服务的方法 实现原理 无论是在WPF或者ASP.NET Core当中, 都可以使用ServiceCollection来做到着…

【软考】10.1 算法特性/时间复杂度/递归/分治/动态规划

《算法》 《时间复杂度》 n 的最高次项 渐进符号 算法复杂度 线性级 O&#xff08;n&#xff09;&#xff1a;顺序查找对数级 O&#xff08;logn&#xff09;&#xff1a;对半查找、快速查找、归并算法 《递归》 时间复杂度 《分治法》 《动态规划法》 适用于求全局最优解构建…

MySQL总结 (思维导图,常用)

一、常见的增删改查 二、约束&#xff08;五种&#xff09; 三、聚合查询 1、聚合函数 2、group by 和 having 3、联合查询 案例表&#xff1a; drop table if exists classes; create table classes (id int primary key auto_increment,name varchar(20) ); insert into …