【JavaEE初阶】网络原理(2)

欢迎关注个人主页:逸狼


创造不易,可以点点赞吗~

如有错误,欢迎指出~



目录

TCP协议

4位首部长度

保留(6位)

[URG, 紧急指针](#URG, 紧急指针)

PSH

TCP的核心机制

确认应答

"后发先至"问题

TCP的32位序号

TCP可携带的数据量

应答报文

解决"后发先至"

超时重传

"丢包"问题

"丢包"原因

判断是否丢包

超时重传

丢弃重复数据

超时重传的时间设定

连接管理(网络模块,最高频的面试题)

建立连接=>三次握手

三次握手的意义

商定起始序号

断开连接=>四次挥手

[TCP 的4个关键状态](#TCP 的4个关键状态)

listen

established

close_wait

time_wait


TCP协议

4位首部长度

4位首部长度 是TCP报头长度,4个比特位表示的数据范围是0~15,长度单位是"4字节",而不是"字节"

对于TCP来说,报头的长度是可变长的(UDP中报头长度固定就是8字节)

保留(6位)

保留位用于 现在不用,以备不时之需, 若TCP要新增属性 或者某个属性的长度不够用了,就可以把保留位拿出来使用=>充分吸取了UDP的教训,考虑了未来的可扩展性

URG, 紧急指针

URG是和紧急指针配合使用的

URG值为1时 紧急指针能够生效(紧急指针里保存的是一个偏移量)

TCP正常情况下都是按照顺序来传输数据的,紧急指针就是让后面的数据插队,根据紧急指针的偏移量,把指定位置的数据优先发送出去(特殊场景的特殊方案,日常开发中很少直接涉及到)

PSH

PSH表示催促标志位,带有这个标志位的数据就相当于提醒接收方要尽快处理这个数据(也是特殊场景的特殊方案)

TCP的核心机制

TCP最核心 的机制就是**"可靠传输"**(不能做到100%送达,只是尽可能的使数据能够到达对方)

  • 能感受到对方是否收到=>确认应答
  • 如果发现对方没收到,就要进行重试=>超时重传

确认应答和超时重传,相互补充 共同构建了TCP的"可靠传输机制"

确认应答

接收方收到数据之后,就要给发送方返回一个**"应答报文"(ack/**acknowledge)

"后发先至"问题

数据传输中的"后发先至",正常传输数据的时候 传输的两个数据包,不一定走的是同一条路线,它们遇到的状况也有所差别,最终到达目的地的时序也就可能存在差异.

后发先至是客观事实 ,无法改变,可以给传输的数据添加"编号 ",通过编号,可以区分出数据的先后顺序

TCP的32位序号

TCP是面向字节流的,实际编号是按照"字节"来的,"第1个字节 到第1000个字节",每个字节都是一个独立 的编号,字节与字节之间编号是连续递增的.

按照字节编号这样的机制,就成为了"TCP的序号"

在应答报文中,针对之前收到的数据进行对应的编号,称为"TCP的确认序号"

32位序号 表示的就是TCP数据报载荷 (序号只针对TCP数据报携带的载荷进行编号的,tcp报头不参与其中)中的第一个字节的序号,由于序号是连续递增的,知道了第一个字节的序号,后续的每个字节的序号也就知道了

TCP可携带的数据量

32位/四字节 表示的范围是0~42亿9千万(4GB),

TCP是面向字节流的**,TCP携带的数据天然就是"可拼装的"**,比如一个特别大的数据,传输过程中,本身就会通过多个TCP数据报来进行携带,这些TCP数据报彼此之间携带的载荷都是可以在接收方自动被拼接起来的

  • 使用UDP传输大数据就需要考虑调用一次send 操作,参数是否超过64KB,超过64KB就不行
  • 使用TCP就没有关系,可以调用一次或者多次write (无论是怎么进行write,在网络传输和对端接受的角度来看都是没有差别的),假设多次write, 传输的总数据量超过4GB也没有关系

应答报文

应答报文默认情况是不携带数据的

对于应答报文来说,确认序号就会按照收到的数据的 最后一个字节序号+1的方式填写

六个标志位中的第二位 ack会设为1

  • 如果是普通报文,序号是有效的,确认序号是无效的
  • 如果是ack应答报文 ,序号 (这里的序号有另一套编号体系,和传输的数据不是同一套)和确认序号都是有效的

解决"后发先至"

TCP会针对接收方收到的数据 ,进行重新排序 ,确保 应用程序 read到的数据一定是和 发送方发的顺序是一致

接收方这边操作系统的内核里,会有一段内存空间作为"接收缓冲区",收到的数据就会先在接收缓冲区中排队等待 ,只有等到 开头的数据到了 ,应用程序才能真正读取到里面的数据. 确保发送方write的顺序和接收方的顺序始终是一致的

超时重传

"丢包"问题

网络传输中,并非一帆风顺,可能会出现"丢包"情况

"丢包"原因
  • 数据传输过程中,发生了bit翻转 ,收到这个数据的接收方/中间的路由器等,计算校验和时发现对不上时,会把这个数据包直接丢弃掉,不会继续往后 转发/不交给应用层使用
  • 数据传输到某个节点(路由器/交换机)时,这个节点的负载太高 了(超过了路由器可以转发包数量的上限->高峰期 时忙得发不过来了,后续传输过来的数据就可能被这个路由器直接丢弃掉)

丢包问题不可避免 ,TCP能做的是 ,感知 到数据是否丢包,如果丢包,就重发一次

判断是否丢包

通过应答报文来区分

  • 收到 应答报文,说明数据没丢包
  • 没收到 应答报文,说明数据丢包

发送方收到数据之后,会给出一个"时间限制"(超时时间),如果在这个时间内没有收到ack,就视为数据丢包了

超时重传

  1. 主机A发送的数据无法达到主机B
  2. B发送的应答报文,A没有收到

这两种情况,发送方无法区分 是哪种情况,但是发送方都会在到达超时时间后进行 重传数据

丢弃重复数据

若主机B收到两份一样的数据 ,TCP会将收到得数据根据序号在缓冲区中找到对应的位置(排序),如果发现当前序号1-1000这个数据已经在缓冲区存在了,就直接把新收到的这个数据丢弃掉(去重 ),以确保 应用程序,调用read读出来的数据是唯一

超时重传的时间设定

超时时间的设定不是固定值,而是动态变化的.

发送方第一次重传,超时时间是t1,如果重传之后,仍然没有ack,会进行第二次重传,超时时间是t2,其中t2>t1,每多重传一次,超时时间的间隔就会变大 /重传的频次就会降低

经过一次重传 之后就能让数据到达对方的概率提升很多 ,再重传一次,又会提升很多, 反之,如果多次重传都没有顺利到达,说明网络的丢包率已经达到了一个非常高的程度了 (网络发生了严重的故障,大概率无法正常使用了),重传再快也没有意义了

重传不会无休止的进行,当重传到达一定次数后,TCP不会尝试重传,就认为此连接已经断开

先尝试进行**"重置/复位 连接",** 发送一个特殊的数据包"复位报文".如果网络恢复了,复位报文就会重置连接,使通信可以继续进行,如果网络还有严重问题,复位报文也没有得到回应,此时TCP会单方面放弃连接(连接:通信双方各自保存对方的信息)

连接管理(网络模块,最高频的面试题)

连接管理包含三次握手和四处挥手 ,这里的"次数"指的是 "**网络通信"的次数,**握手和挥手 是形象的比喻(handshake,计算机中常见的术语)

建立连接=>三次握手

网络中的握手,发送不携带业务数据 (只有载荷,没有报头)的数据包,但是能起到"打招呼"的效果,挥手同理

syn(synchronized)此处syn 意思是"同步 ",表示 客户端希望服务器和它统一步调 来完成后续的传输

建立连接是一个"双向操作",

本来是4次交互,但是中间两次合并 (合并很重要,分两次发送,效率打折扣,每个数据包都需要一系列封装分用)**了,就成了三次握手,**中间两次(ack+syn)都在操作系统负责进行的,时机都是收到syn之后,开始合并的

三次握手的意义
  • 投石问路,初步的验证通信链路是否畅通(可靠传输的前提条件)
  • 确认通信双方各自的发送和接收能力 是否都正常
  • 让通信双方在进行通信之前对通信过程中需要用到一些关键参数进行协商
商定起始序号

TCP通信时,起始数据的序号就是通过三次握手协商确定的(TCP序号,并不是从1开始的),每次建立连接,TCP的起始序号都不同(而且故意差别很大)

在A和B传输数据的过程中,可能有某个数据包 "迷路 ",绕了一大圈,最终才到达对端,当它达到时 ,已经"改朝换代 "(虽然还是AB两个主机连接,但是可能是不同的应用程序)了,针对这样迟到的数据,就需要把它丢弃掉

所以对于B来说,需要区分当前收到的数据是"本朝"还是"前朝"的. 给每个连接都协商一个不同的起始序号 ,如果发现收到的数据的起始序号与最近收到的数据序号都相差很大 的话,就视为这个数据是"前朝"的数据

断开连接=>四次挥手

断开连接 表示:双方各自都把对端的信息删掉了

  • 断开连接的正常流程:四次挥手,双方都删除对方的信息
  • 异常流程 :超时重传也一直失败,会触发"单方面删除"

对于四次挥手,中间两次,不一定能合并(大概率不能) ,ack是内核控制的,但是fin的触发则是通过应用程序调用close/进程退出来触发的(代码中针对socket.close() =>系统内部发送fin)

TCP 的4个关键状态

listen

服务器进入的状态

服务器把端口绑定好,相当于进入了listen状态 ,此时服务器已经初始化完毕,准备好迎接客户端了

->例如手机开机,信号良好,随时可以有人来打电话了

established

客户端和服务器都会进入状态

TCP连接建立完成(保存好对方的信息了),接下来就可以进行业务数据的通信了

->电话接通,可以开始说话了

close_wait

被动断开连接的一方(先收到FIN的一方),会进入这个状态.等待代码执行close方法

如果发现 服务器端存在大量close_wait状态的TCP连接 说明服务器代码可能有bug->排查close是否写了,以及是否及时执行到了

time_wait

主动断开连接的一方 ,会进入这个状态

time_wait有时间限制,达到一定时间 (2MSL,MSL=>数据报在网络传输中消耗的最大时间)之后,连接就会释放

为什么不直接释放,而是要等待一段时间?

担心最后一个ACK丢包(任何一个数据包都可能丢包),如果最后一个ack丢包了,此时B就会重传一次FIN,需要A再发一次ACK.

能够再发一次ACK的前提是 A这边的连接还不能释放(如果连接释放了,就不知道对方的信息,无法返回任何数据了),所以就有了time_wait等待时间

相关推荐
yngsqq几秒前
c#使用高版本8.0步骤
java·前端·c#
尘浮生10 分钟前
Java项目实战II基于微信小程序的校运会管理系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
小白不太白95014 分钟前
设计模式之 模板方法模式
java·设计模式·模板方法模式
Tech Synapse16 分钟前
Java根据前端返回的字段名进行查询数据的方法
java·开发语言·后端
xoxo-Rachel23 分钟前
(超级详细!!!)解决“com.mysql.jdbc.Driver is deprecated”警告:详解与优化
java·数据库·mysql
乌啼霜满天24924 分钟前
JDBC编程---Java
java·开发语言·sql
色空大师37 分钟前
23种设计模式
java·开发语言·设计模式
闲人一枚(学习中)38 分钟前
设计模式-创建型-建造者模式
java·设计模式·建造者模式
2202_754421541 小时前
生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件
java·linux·开发语言