《协议栈的骨架:从Web请求到比特流——详解四层架构的可靠传输与流量控制》
前言
本篇博客将详细介绍网络原理(细~~~)
💖 个人主页:熬夜写代码的小蔡
🖥 文章专栏
若有问题 评论区见
🎉欢迎大家点赞👍收藏⭐文章
一.应用层
这里的应用层只是个开头,更详细的在下一篇文章
应用层是和程序员接触最密集的,在这里, 很多时候,都是程序员“自定义”应用层协议“(当然有一些现成的应用层协议)其实也就是这两点:
1.根据需求,明确要传输的信息
2.约定好信息按照什么格式来传输
在实际开发中,有这么几种常见的格式
1.xml
- 结构化格式:基于标签的文本格式(如
<person><name>John</name></person>
),支持嵌套和复杂数据。 - 可读性:可直接阅读,适合配置文件和文档。
- 灵活性:支持自定义标签和命名空间,扩展性强。
优点:严格的结构化,适合复杂数据场景
缺点:标签占用大量字符,数据体积大。
2.json
json是当下最流行的一种数据组织格式
- 轻量级键值对格式:语法简洁使用键值对结构,键值对之间使用”,”来分割,键和值之间使用“:”来分割(如
{"name": "John", "age": 30}
),支持数组、嵌套对象。 - 主流支持:几乎被所有编程语言原生或通过库支持(如Python的
json
模块、JavaJackson)。
优点:相比XML减少冗余字符,文本解析较XML高效。
缺点: 在网络传输中,消耗额外的带宽(需要把key也进行传输)
3.protobuffer
- 二进制序列化协议:由Google开发,数据以高效二进制传输。
优点:占用宽带最低,传输效率最高,非常适合对于性能要求比较高的场景
缺点: 可读性不好(二进制结构,肉眼无法直接阅读),一定程度影响开发效率
二.传输层(重点)
2.1UDP
2.1.1端口号
再来回顾一下端口号,写一个服务器,必须手动指定一个端口号,通过端口号来区分当前这个主机上的不同的应用程序,写一个客户端,客户端在通信中也会有一个端口号,是系统自动分配的。
端口号,固定就是2个字节,表示的数据范围0~65535,一般来说0是不用的,1~1023称为“知名端口号”,给一些知名的服务器预留的位置,像ssh:20,http:80,https:443,1024~65535 称为普通端口号,平时自己写代码还是用普通端口,不要和别人的端口号重复。
2.1.2UDP协议报文格式
在UDP的学习中,最主要的工作就是去理解协议报文格式
在UDP报头里有源端口号,目的端口号,UDP报文长度,UDP的校验和,UDP载荷数据部分是完整的应用层数据报,报头和载荷之间就可以认为是一个“字符串拼接”
UDP报文长度只有2个字节,16位表示的数据,表示的范围0~65535也就是64kb,能否对UDP进行升级,比如把2个字节变成4个字节来把UDP报文表示的范围变大?
不可以!不是技术上不可以,这是一个政治问题,要升级,就得通信上方都要升级,如果一方升级了,一方没有升级,数据就对不上了,肯定无法通信了,全世界的设备都得一起升级(升级操作系统内核,UDP是内核中实现的)
那我们熟悉的源IP,目的IP在哪??
不在传输层,而在网络层中(IP协议里)
校验和是什么???
在网络传输过程中,由于一些外部干扰,可能会出现数据传输出错的情况,因此就需要有办法来识别出出错的数据
校验和就是这样的一种检查手段~~
那怎么检查呢,是根据数据的大小吗?个数吗?
说现在一眨眼我就大二了,可是还要上早八,今天早上我起晚了,上午的课是计算机组成原理,计算机网络原理,我需要拿这两本书,然后我就拿了两本和他俩差不多厚度的书去上课了,到教室一看拿错书了,所以根据数据的大小,个数显然不是很靠谱,那如果我只记得拿计网计组我就知道是算机组成原理,计算机网络原理,这两本书
校验和,其实本质上也是一个字符串,体积比原始的数据更小,又是通过原始的数据生成的原始数据相同,得到的校验和就一定相同.反之, 校验和相同, 原始数据大概率相同 (理论上会存在不同的情况, 实际的概率非常低,可以忽略不计)
如何基于校验和来完成数据的校验???
1.发送方,把要发送的数据整理好(称为 data1),通过一定的算法, 计算出校验和 checksum1
2.发送方把 data1 和 checksum1 一起通过网络发送出去,
3.接收方收到数据,收到的数据称为 data2(数据可能和 data1 就不一样了),收到数据 cHecksum1
4.接收方再根据 data2 重新计算校验和 (按照相同的算法),得到 checksum2
5.对比 checksum1 和 checksum2 是否相同.如果不同,则认为 data2 和 data1 一定不相同.如果 checksum1 和 checksum2 相同,则认为 data1 和 data2 大概率是相同的(理论上存在不同的可能性,概率比较低,工程上忽略不计
校验和是怎么算的???
计算校验和,有很多种算法,此处 UDP 中使用的是 CRC 算法(循环冗余算法)把当前要计算校验和的数据,每个字节,都进行累加,把结果保存到这个 两个字节的 变量中.累加过程中如果溢出,也没关系,如果中间某个数据,出现传输错误,第二次计算的校验和就会和第一次不同~~
CRC这个算法其实不是特别的靠谱,导致两个不同的数据,得到相同的 crc 校验和的概率比较大(前一个字节恰好 少1,后一个字节恰好 多 1)
所以还是md5算法更加可靠~~~
这里有一系列的公式,来完成 md5 的计算,(咱们不需要考虑公式是啥样的,是一个数学问题), 但是咱们需要知道 md5 的特点
1.定长.无论你原始数据多长, 计算得到的 md5,都是固定长度
2.分散.给定两个原始数据, 哪怕绝大部分内容都一样,只要其中-个字节不同,得到的 md5 值都会差异很大
这里咱们把上面那一堆数据的最后一个字母改一下,再来对比
3.不可逆,给你一个原始数据,计算 md5,非常容易.现有计算机的算力极限,理论上是不可行的
2.2TCP
2.2.1 TCP的特点
TCP 这个协议最大的特点,就是 可靠传输 ~~(TCP 的初心!)
下面的图片看不懂没关系,先往下看,再回过头来看。
2.2.2TCP的相关特性
1.有链接
2.可靠传输
3.面向字节流
4.全双工
1,3,4都在代码中有体现,那什么是可靠传输(能不能抗住挖掘机一铲子)???
可靠传输,不是说,发送方把数据能够 100% 的传输给接收方~~ (要求太高了)
1)发送方发出去数据之后,能够知道接收方是否收到数据.
2)一旦发现对方没收到,就可以通过一系列的手段来"补救”
2.2.3TCP协议实现可靠传输和高效流量控制的核心机制
1.确认应答
发送方,把数据发给接收方之后,接收方收到数据就会给发送方返回一个 应答报文 (acknowledge, ack),发送方,如果收到这个应答报文了,就知道自己的数据是否发送成功了.
在实际的网络传输过程中数据可能会出现“后发先至”的情况
所以TCP在此要完成两个工作:
1.确保应答报文和发出去的数据, 能对上号,不要出现歧义.
2.确保在出现后发先至的现象时,能够让应用程序这边仍然按照正确的顺序来理解数据
一个 TCP 数据包里一共有 1000 个字节的荷数据,其中第一个字节的序号是 1,就在 TCP 报头的序号字段中写"1"由于一共是 1000 个字节,此时最后一个字节的序号自然就是1000 了.但是 1000 这样的数据并没有在 TCP 报头中记录.TCP 报头中记录的序号,是这一次传输的载荷数据中第一个字节的序号
剩下其他字节的序号,都需要依次的推出,在 应答报文中,就会在 确认序号 字段中填写 1001,因为收到的教据是 1-1000,所以 1001 之前的数据,都被 B 收到了或者也可以理解成, B 接下来向 A 素要 1001 开始的数据。
TCP 的初心,是为了实现可靠传输 =>达成可靠传输的最核心的机制, 就是 确认应答。
如何区分一个数据包是普通的还是ack应答数据呢???
在第二个ACK这里这一位为1, 表示当前数据包是一个应答报文.此时该数据包中的“确认序号字段”就能够生效.这一位为 0,表示当前数据包是一个普通报文.此时数据包中的"确认序号字段”是不生效.
最后总结:确认应答,是 TCP 最核心的机制, 支持了 TCP 的可靠传输!!
2.超时重传
确认应答,描述的是一个比较理想的情况,、如果网络传输过程中出现丢包了,怎么办??发送方,势必就无法收到 ACK 了。使用超时重传机制,针对确认应答,进行补充.
为什么会丢包???
网络中,“收费站” 可以理解成是一些 路由器/交换机如果数据包太多了,就会在这些路由器/交换机上出现“堵车”但是路由器针对“堵车"的处理,往往是比较粗暴的,不会把这些积压的数据包都保存好,而是会把其中的大部分数据包直接给丢弃掉,比时这个数据包就在网络上消失
丢包又分两种情况???
由于丢包是一个“随机" 的事件,因此在上述 tcp 传输过程中,丢包就存在两种情况
1.传输的数据丢了
2.返回的ACK丢了
无论出现上述哪种情况,发送方都会进行"重新传输"第一次是丢了,重传一下试试呗,很大概率就能传过去呢~.
重传操作,大幅度的提升了数据能够被传过去的概率~~重传就是一个很好的丢包下的补救措施了
那么发送方何时进行重传呢???
发送方,发出去数据之后,会等待一段时间,如果这个时间之内,ack 来了,此时就自然视为数据到达.如果达到这个时间之后,数据还没到, 就会出发重传机制~~
超过了等待的时间,再重传。
1.初始的等待时间,是可配置的,不同的系统上都不一定一样,也可以通过修改一些内核参数来引起这里的时间变化.
2.等待的时间,也会动态变化,每多经历一次超时,等待时间都念变长
A ->B 发了一条数据,第一次,A 等待 ACK 的时间,假设是 50ms此时如果达到 50ms, 还没有 ack,A 就重传,当 A 重传的数据,还是没有收到 ack,第二次等待的时间就会比第一次更长拉长也不是无限拉长,重传若干此时,时间拉长到一定程度,认为数据再怎么重传也没用了,就放弃 tcp 连接(准确的说,是会触发 tcp 的重置连接操作)
如果站在接收方的角度,收到两条重复的数据,是否会带来BUG???
比如发的是一条数据,收的时候收到两条数据了 (inputStream.read,读出来的是两条一样的数据),其实 TCP 已经非常贴心的帮我们把这个问题解决了.
TCP 会有一个“接收缓冲区"就是一个内存空间,会保存当前已经收到的数据,以及数据的序号,接收方如果发现当前发送方发来的数据,是已经在接收缓冲区中存在的(收到过的重复数据了),接收方就会直接把这个后来的数据给丢弃掉,确保应用程序进行read 的时候读到的是只有一条数据接受缓冲区,不仅仅是能进行去重,还能进行重新排序,确保发送的顺序,和应用程序读取的顺序是一致的
3.连接管理
在这里有两方面,建立连接+断开连接,建立连接也就是下面说的三次握手,断开连接也就是下面说的四次挥手
什么是握手呢???
握手也就是打招呼,打招呼的内容,没有实际意义,也比较简短,只是为了唤起对方的注意~~,tcp 这里的握手,也是类似,也就是给对方传输一个简短的,没有业务数掘的数据包通过这个数据包,来唤起对方的注意,从而触发后续的操作.
什么是三次握手???
TCP 的三次握手,TCP 在建立连接的过程中,需要通信双方一共"打三次招呼" 才能够完成连接建立的
如果SYN为1表示这个报文是一个同步报文段(就是一个特殊的TCP数据包没有载荷的(不携带业务数据的)) A 想和 B建立连接. A 就会主动发起握手操作,实际开发中,主动发起的一方,就是所谓的"客户端”被动接受的一方,就是"服务器”,此时,握手完成.此时,A 和 B 记录了对方的信息(也就是构成了“逻辑"上的连接),建立连接的过程,其实是,通信双方都要给对方发起 syn, 也都要给对方反馈 ack.一共是 4 次握手了,但是中间两次,恰好可以合并成一次.
三次握手是要解决什么问题???通过四次握手,是否可行?
TCP 初心,是为了实现"可靠传输”,进行确认应答和超时应答有个大前提,当前的网络环境是基本可用的,通畅的,如果当前网络已经存在重大故障了,此时,可靠传输,无从谈起,3次握手就是检查网络是否畅通。四次握手可以,但是没必要,两个数据合并成一个数据效率更高.
三次握手的作用???
三次握手核心作用一: 投石问路,确认当前网络是否是畅通的
三次握手核心作用二: 要让发送方和接收方都能确认自己的发送能力和接收能力均正常
三次握手核心作用三: 让通信双方,在握手过程中,针对一些重要的参数,进行协商(这里协商的信息有好几个,现在不做过多讨论,但至少知道tcp 通信过程中的序号从几开始,就是双方协商出来的(一般不是从1开始的))
断开连接——四次挥手
建立连接,一般都是客户端主动发起,断开连接, 客户端和服务器都可以主动发起.
最后的FIN就叫做结束报文段
和三次握手不同,此处的四次挥手,能否把中间的两次交耳合二为一?
不一定,不能合并的原因,ACK 和 第二个 FIN 的触发时机是不同的, ACK 是内核响应的.B 收到 FIN,就会立即返回 ACK,第二个 FIN 是应用程序的代码触发,B 这边调用了 close 方法才会触发 FIN ,像前面的三次握手, ACK 和 第二个 syn 都是内核触发的. 同一个时机. 可以合并,这里的四次挥手,ACK 是内核触发的,第二个 FIN 是应用程序执行 close 触发的,时机不相同,不能合并.
是否意味着,如果我这边代码 close 没写/没执行到,是不是第二个 FIN 就一直发不出去??
有可能的,果是正常的四次挥手,“好聚好散”, 正常的流程断开的连接,如果是不正常的挥手(没有挥完四次),异常的流程断开连接,(也是存在的)
在四次挥手中,TIME _WAIT有什么意义
TIME WAIT 状态主要存在的意义,就是为了防止最后一个 ACK 丢失,留下的后手如果最后一个 ACK 丟了,站在 B的角度,B就会触发超时重传
重新把刚才的 FIN 给传一遍.如果刚才 A 没有 TIME WAIT 状态, 就意味着 A 这个时候就已经真的释放连接了,此时重传的 FIN 也就没人能处理,没人能返回 ACK 了.B 永远也收不到 ACK 了.A 这边使用 TIME WAIT 状态进行等待, 等待的这个时间, 就是为了处理后续 B 重传的 FIN
此时有重传的 FIN 来了,就可以继续返回 ACK 了,B 这边的重传 FIN 才有意义.
4.滑动窗口
因为TCP要保证“可靠传输”,所以在所难免会牺牲一些效率,而滑动窗口就是来尽可能的提升效率的,让可靠传输对性能的影响,更少一些,TCP 只要引入了可靠性,传输效率是不可能超过 没有可靠性的 UDP 的,TCP 这里的"效率机制"都是为了让 影响更小,缩短和 UDP 的差距,缩短和UDP的差距。
每次收到一个应答报文,再发下一个数据,这个过程中,等待时间比较长的,怎样缩短应答确认的时间?
批量传输数据不等 ack 回来, 直接再发下一个数据,批量传输,也不是“"无限的"传输,批量传输也是存在一定的上限的,达到上限之后,再统一等待 ack
不等待的情况下,批量最多发多少数据,这个数据量,称为"窗口大小"
当前 A ->B 是批量的发了四份数据,此时 B 也要给 A 回应四组 ACK,此时 A 已经达到窗口大小, 再收到 ACK 之前,不能继续往下发了,需要等待有 ACK 回来了之后, 才能继续往下发。
这里是怎么继续发的? 是等待四个 ack 都回来了,在继续发四条?
回来一个 ack,就立即继续发一个。
TCP 初心是"可靠传输",上述滑动窗口中,确认应答是可以正常工作的,但是,如果出现丢包了咋办??
这里的重传,相比于前面的超时重传,又有变化~~~
情况1:ACK丢了
出现这种情况,不需要任何的重传。
确认序号,表示的含义是,当前序号之前的数据,已经确认收到了,下一个你应该从确认序号这里,继续发送。如果 1001 这个 ack 丟了.但是 2001 ack 到了.
12001之前的数据都已经确认传输成功了.涵盖了 1001 的情况!!!
情况2:数据包丢了
由于前面的 1001-2000 这个数据没了,此处返回的 ack 仍然是索要 1001,无论当前传输的数据具体是几,都在索要1001 这个数据,此时,主机 A 看到了 B这边连续的几个ack,都是在索要 1001.A 就知道了1001 这个数据就是丢了,就重传了1001,上述的重传过程中,并没有额外的冗余操作,哪个数据丢了,就重传哪个,没丟的数据则不需要重传整个过程都是比较快速的,(快速重传——滑动窗口下,超时重传的变种)
如果 ack 全都丟了呢??
平时丢包率达到 10%,就已经非常非常高了,直接丢包率 100% 了,此时相当于网线都断了,无从谈起"可靠传输"
如果通信双方,传输数据的量比较小,也不频繁,就仍然是普通的确认应答和普通的超时重传.
如果通信双方,传输数据量更大,也比较频繁, 就会进入到滑动窗口模式, 按照快速重传的方式处理
通过滑动窗口的方式传输数据,效率是会提升的,窗口越大,传输效率就越大.(一份时间, 等待 的 ack 更多了,总的等待时间更少了)
滑动窗口, 设置的越大,越好嘛??
如果传输的速度太快,就可能会使接收方,处理不过来了.此时,接收方也会出现丢包,发送方还得重传,TCP 前提是可靠性,可靠性的基础上,再提高传输效率
5.流量控制
站在接收方的角度,反向制约发送方的传输速率,发送方发送的速率,不应该超过接收方的处理能力.
数据到达 B的系统内核中,tcp socket 对象上带有接收缓冲区.A ->B 发的数据, 就会先到达 B的接收缓冲区.B 这边还有应用程序,就会调用 read 这样的方法,把数据从接收缓冲区中读出来,进一步的进行处理.(一旦数据被 read 了,就可以从接收缓冲区删除了)
这里也就是我们以前提到的生产者消费者模型,生产者:A,消费者:B的应用程序,交易场所:B的接收缓冲区(相当于阻塞队列)
消费速度,就是所谓的"处理能力"(取决于 B 的应用程序代码是咋写的)
如何量化衡量???
直接通过接收方,缓冲区的剩余空间大小,作为衡量处理能力的指标,剩余空间越大,意味着消费速度越快,处理能力就越强,剩余空间越小,消费速度越慢,处理能力就越弱.接收方每次收到数据之后,都会把接收缓冲区剩余空间大小,通过 ack 返回给发送方,发送方就会按照这个数值来调整下一轮的发送速度.
6.拥塞控制
流量控制,是考虑的接收方的处理能力,不仅仅是接收方,还有你整个通信的路径
这中间的转发过程中,任何一个节点,处理能力达到上限,都可能会对发送方产生影响,都可能会影响到可靠传输,由于中间节点,结构更复杂,更难以直接的进行量化,因此就可以使用"实验"的方式,来找到个合适的值,让 A 先按照比较低的速度先发送数据(小的窗口),如果数据传输过程非常顺利,没有丢包,
再尝试使用更大的窗口,更高的速度进行发送,(一点一点变化),随着窗口大小不停的增大,达到一定程度,可能中间节点就会出现问题了,此时这个节点就可能会出现丢包,发送方发现丢包了,就把窗口大小调整小,此时如果发现还是继续丢包,继续缩小,如果不丢包了,就继续尝试变大
再这个过程中,发送方不停的调整窗口大小,逐渐达成"动态平衡",这种做法,就相当于把中间节点,都视为"整体”,通过实验的方式,来找到中间节点的瓶颈在哪里~~~
流量控制
拥塞控制
都是在限制发送方的发送窗口的大小.
最终时机,发送的窗口大小,是取 流量控制 和 拥塞控制 中的窗口的较小值
7.延时应答
A 把数据传给 B, B就会立即返回 ack 给A[正常]
也有的时候, A传输给B, 此时B等一会再返回 ack 给A[延时应答]
延时应答本质上也是为了提升传输效率.发送方的窗口大小, 就是传输效率的关键.流量控制这里,就是根据接收缓冲区的剩余空间,来决定发送速率的,
如果能够有办法,让这个流量控制得到的窗口更大点,发送速率就更快点,(大点的前提,能够让接收方还是能处理过来的),延时返回 ack,给接收方更多的时间, 来读取接收缓冲区的数据,此时接收方读了这个数据之后, 缓冲区剩余空间, 变大了~~返回的窗口大小也就更大了,初始情况下,接收缓冲区剩余空间是 10kb,如果立即返回 ack,返回了 10kb 这么大的窗口,如果延时个 200ms 再返回,这 200ms 的过程中,接收方的应用程序的,又读了 5 kb,此时,返回的 ack, 就可以返回 15kb 的窗口了
8.捎带应答
在延时应答的基础上,进一步的提高效率,网络通信中,往往是这种"一问一答"这样通信模型
ack 也是内核立即返回的,response 则是应用程序代码来返回的,这两者时机是不同的,由于 tcp 引入了延时应答,上面的 ack,不一定是立即返回,可能要等一会在等一会的过程中,B 就正好把 response 给计算好了.计算好了之后就会把 response 返回,于此同时顺便就把刚才要返回的 ack 也带上了
这两个数据,就合并成了一个数据了本来是要传输两个 tcp 数据包 (封装分用两遍),现在通过上述操作,就可以把两个包合并成一个了,此时就可以得到更高效的效果。
9.面向字节流
创建⼀个TCP的socket, 同时在内核中创建⼀个 发送缓冲区 和⼀个 接收缓冲区。
• 调⽤write时, 数据会先写⼊发送缓冲区中;
• 如果发送的字节数太⻓, 会被拆分成多个TCP的数据包发出;
• 如果发送的字节数太短, 就会先在缓冲区⾥等待, 等到缓冲区⻓度差不多了, 或者其他合适的时机发送出去;
• 接收数据的时候, 数据也是从⽹卡驱动程序到达内核的接收缓冲区;
• 然后应⽤程序可以调⽤read从接收缓冲区拿数据;
• 另⼀⽅⾯, TCP的⼀个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这⼀个连接, 既可以读数据,也可以写数据. 这个概念叫做 全双⼯
由于缓冲区的存在, TCP程序的读和写不需要⼀⼀匹配, 例如:
• 写100个字节数据时, 可以调⽤⼀次write写100个字节, 也可以调⽤100次write, 每次写⼀个字节;
• 读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以⼀次read 100个字节, 也可以⼀次read⼀个字节, 重复100次;
10.粘包问题
粘包问题 (不是 tcp 独有的,而是面向字节流的机制都有类似的情况)
此处“包"应用层数据包,如果同时有多个应用层数据包被传输过去,此时就容易出现粘包问题
目前,接收缓冲区中,这三个应用层数据包的数据,就是以字节的形式紧紧挨在一起的,接收方的应用程序,读取数据的时候,可以一次读一个字节,也可以读两个字节, 也可以读 N 个字节....但是最终的目标是为了得到完整的应用层数据包,B 应用程序,就不知道,缓冲区里的数据。从哪里到哪里是一个完整的应用数据包了。
相比之下,像 UDP 这样的面向数据报的通信方式,就没有上述问题
UDP 的接收缓冲区中,相当于是一个一个的 DatagramPacket 对象,应用程序读的时候,就能明确知道哪里到哪里是一个完整的数据
那如何解决粘包问题?
核心思路: 通过定义好应用层协议,明确应用层数据包之间的边界.
1.引入分隔符
2.引入长度.
11.异常情况的处理
如果在使用 tcp 的过程中,出现意外,会如何处理?
1)进程崩溃:
进程没了,异常终止了,文件描述符表,也就释放了,相当于调用 socket.close0),此时就会触发 FIN, 对方收到之后,自然就会返回 FIN 和 ACK,这边再进行 ACK(正常的四次挥手断开连接的流程),TCP 的连接,可以独立于进程存在,(进程没了,TCP 连接不一定没)
2)主机关机(正常流程):
在进行关机的时候,就是会先触发强制终止进程操作,(相当于 1)此时就会触发 FIN, 对方收到之后, 自然就会返回 FIN 和 ACK.
不仅仅是进程没了,整个系统也可能关闭了,如果在系统关闭之前,对端返回的 ACK 和 FIN 到了,此时系统还是可以返回 ACK,进行正常的四次挥手的,如果系统已经关闭了,ACK 和 FIN 迟到了,无法进行后续ACK 的响应,站在对端的角度,对端以为是自己的 FIN 丢包了,重传 FIN,重传几次都没有响应,自然就
会放弃连接.(把持有的对端的信息就删了)
3)主机掉电(非正常):
这里说的是台式机哦,不是笔记本电脑
此时,是一瞬间的事情,来不及杀进程,也来不及发送 FIN,主机直接就停机了,站在对端的角度,对端不一定知道这个事情咋搞~~
1.如果对端是在发送数据(接收方掉电),发送的数据就会一直等待 ack,触发超时重传,触发 TCP 连接重置功能.发起"复位报文段”,如果 复位报文段 发过去之后,也没有效果,此时就会释放连接了。
2.如果对端是在接收数据 (发送方掉电),对端还在等待数据到达...,等了半天没消息,此时其实无法区分,是对端没法消息还是对方挂了
TCP 中提供了 心跳包 机制.
接收方也会周期性的给发送方发起一个特殊的,不携带业务数据的数据包, 并且期望对方返回一个应答,如果对方没有应答,并且重复了多次之后,仍然没有,就视为对方挂了.此时就可以单方面释放连接了.
4)网线断开:
网线断开,和刚才的主机掉电非常类似的,当前假设,是 A 正在给 B 发送数据, 一旦网线断开
A 就相当于就会触发超时重传 ->连接重置 ->单方面释放连接
B 就会触发心跳包 ->发现对端没响应 ->单方面释放连接.
2.3TCP 和 UDP 之间的对比~~
TCP 优势 可靠传输 /TCP 适用于绝大部分场景.
UDP 优势 更高效率' UDP 更适合于, 对于"可拿性不敏感”,"性能敏感”场景,比如说:局域网内部(同一个机房)的主机之间通信同一个机房内部,网络结构简单,带宽充足,交换机/路由器网络设备负载程度也不是很高出现丢包的概率就不大.往往也希望机器之间数据传输能更快.
如果要传输比较大的数据包,TCP 更优先(UDP 有 64KB 的限制),如果要进行"广播传输",优先考虑 UDP. UDP 天然支持广播,TCP 不支持 (应用程序额外写代码实现),有一种特殊的场景,需要把数据发给局域网的所有的机器这个情况就是广播(手机投屏)
经典面试题: 如何基于 UDP 实现可靠传输??
这个问题本质上是考察 TCP !!
1)确认应答
2)引入序号 确认序号
3)超时重传
4)滑动窗口
...........
三 .网络层
网络层要做的事情,主要是两方面,
1)地址管理:制定一系列的规则,通过地址,描述出网络上一个设备的位置,
2)路由选择:网络环境比较复杂的,从一个节点到另一个节点之间,存在很多条不同的路径,就需要通过这种方式,筛选/规划出更合适的路径进行数据传输
3.1 IP协议
3.1.1协议头格式
• 4位版本号(version): 指定IP协议的版本, 对于IPv4来说, 就是4.
• 4位头部⻓度(header length): IP头部的⻓度是多少个32bit, 也就是 length * 4 的字节数. 4bit表⽰最⼤的数字是15, 因此IP头部最⼤⻓度是60字节.
• 8位服务类型(Type Of Service): 3位优先权字段(已经弃⽤), 4位TOS字段, 和1位保留字段(必须置为0). 4位TOS分别表⽰: 最⼩延时, 最⼤吞吐量, 最⾼靠性, 最⼩成本. 这四者相互冲突, 只能选择⼀个.对于ssh/telnet这样的应⽤程序, 最⼩延时⽐较重要; 对于ftp这样的程序, 最⼤吞吐量⽐较重要.
• 16位总⻓度(total length): IP数据报整体占多少个字节.
• 16位标识(id): 唯⼀的标识主机发送的报⽂. 如果IP报⽂在数据链路层被分⽚了, 那么每⼀个⽚⾥⾯的这个id都是相同的.
• 3位标志字段: 第⼀位保留(保留的意思是现在不⽤, 但是还没想好说不定以后要⽤到). 第⼆位置为1表⽰禁⽌分⽚, 这时候如果报⽂⻓度超过MTU, IP模就会丢弃报⽂. 第三位表⽰"更多分⽚", 如果分⽚了的话, 最后⼀个分⽚置为1, 其他是0. 类似于⼀个结束标记.
• 13位分⽚偏移(framegament offset): 是分⽚相对于原始IP报⽂开始处的偏移. 其实就是在表⽰当前分⽚在原报⽂中处在哪个位置. 实际偏移的字节数是这个值 * 8 得到的. 因此, 除了最后⼀个报⽂之外, 其他报⽂的⻓度必须是8的整数倍(否则报⽂就不连续了).
• 8位⽣存时间(Time To Live, TTL): 数据报到达⽬的地的最⼤报⽂跳数. ⼀般是64. 每次经过⼀个路由, TTL -= 1, ⼀直减到0还没到达, 那么就丢弃了. 这个字段主要是⽤来防⽌出现路由循环
• 8位协议: 表⽰上层协议的类型
• 16位头部校验和: 使⽤CRC进⾏校验, 来鉴别头部是否损坏,不管IP数据的载荷
• 32位源地址和32位⽬标地址: 表⽰发送端和接收端.
3.1.2地址管理
IPv4地址由 32位二进制数 构成,理论上,32位二进制可组合的地址数量为约42.9亿个,在当时看起来还觉得很多,但互联网发展到现在,能上网的设备越来越多,还有最近几年很火的物联网,汽车,智能家居.......IP地址早就已经不够用了
如何解决IP地址不够用的问题???
我们有两种解决方案
方案一:动态分配IP,但是治标不治本,提高了IP地址的利用率,但并没有增加IP地址的数目(没什么卵用)
方案二:NAT机制(网络地址转换)
假设这么一个场景,你是一名大学生,你的周围有着和你一样成千上万的大学生,你们在网络上购物所填的地址都是这个大学所在的地址
所以把IP地址分成两大类:
1)内网IP(局域网):
在同一个局域网中,内网IP之间不能重复,在不同的局域网之间,内网IP之间可以重复
如果一个 |P 地址,是以 10.*或者 172.16.- 172.31.*或者 192.168.*(复合上述条件之一,IP 就是内网 IP)
2)外网IP(广域网IP)
外网IP始终都不允许重复,始终唯一
在现在的社会环境下,通常都是一个小区/学校/公司构成一个大的局域网,这样的局域网,就使用一个外网IP。
NAT是怎么工作的???
此时,运营商路由器也是一个NAT设备,对这里的源IP进行替换,也就相当于一个中转站。
如果当前局域网内,有多个主机, 都访问同一个网站服务器,此时服务器返回的响应经过当前的路由器之后,要交还给哪个主机呢(路由器还能记住谁是谁吗)???
可以看到,虽然IP一样,但是这两个请求来自不同的端口,返回响应的数据自然也会带着不同的目的端口
服务器返回的两条数据一个端口号是6666,一个是8888,路由器就知道6666的这个,就需要把IP换回第一主机的IP(192.168.0.100),8888这个就把IP换回第二个主机的IP(192.168.0.200)
当服务器返回数据之后,路由器如何决定这个数据要交给哪个设备?
是要结合端口号来进行区分!!!"端口号,可以用来区分同一个主机的不同进程,也可以区分不同主机的不同进程!
那么问题又来了,那恰好有两台电脑的端口号也一样,咋办???
这时候,路由器就主动地把相同的端口替换成不同的端口
NAT 机制最大的优势就是"纯软件的方案",不需要进行硬件升级,也正是因为这个机制,局域网内部的设备,能够主动访问外网的设备
外网的设备无法主动访问局域网内部的设备~
说到最后,其实IPV6才是最终解~~~~
3.1.3网段划分
把一个 IP 地址,会分成两个部分,网络号(标识了一个局域网) + 主机号(标识了局域网中的一个设备)
在第一个绿色的框内,也就是在一个局域网中,网络号为192.168.1,后面的.1 .10 .11 .12为主机号
第二个局域网中网络号 192.168.0主机号.1 .10 .11 .12,同一个局域网中的设备,网络号必须相同,主机号必须不同,两个相邻的局域网,网络号不能相同,通过一个路由器,连接一个局域网。
如果一个!P 地址,主机号全 0,当前这个 IP 就表示"网络号",192.168.100.0,代表一个局域网,一个具体的主机,是不能分配这个 IP 的
如果一个 IP 地址,主机号全 1, 表示当前这个 IP 就是一个"广播地址" ,192.168.100.255,也是具体的主机,是不能分配这个 IP 的
如果一个 IP 是 127 开头的, 此时这个 IP 就是"环回 ip",127.0.0.1 (最常用的)表示"设备自身” 自己发给自己~~
3.1.4路由选择
路由选择,就是描述了 IP 协议(IP 数据报) 转发过程,从 A->B,中间可能有很多条可行的路径,具体怎么走~,而进行IP 数据报转发的时候,每个路由器,都是无法知道网络的“全貌”的,只知道一些局部信息.(一个路由器能知道哪些设备和它自己是相连的),这就意味着 IP 数据在转发过程中, 是一个"探索式""启发式"过程.
路由器转发数据报的过程还比较复杂,咱们通过一个简单的例子来介绍
我在我们学校中要从我们宿舍去操场,但是我不认识路(假设没有导航地图),但是我会问路啊!
1.遇到了A
A说他不知道怎么走,但是听说操场在东区,建议我往东走
2.往东走的时候遇到了B
B也不知道怎么走,只知道在三食堂的附近
3.到了三食堂附近遇到了C
C说往北走两条街就是操场了
前面几个人,虽然不知道操场在哪,但是给我指出了一个逐渐接近的方向,最后距离比较近的时候,C就已经知道操场在哪里了,就可以完成最后的一段路线了~~
一个网络层的数据报,每次到达一个路由器,也会进行上述"问路"过程,每个路由器内部都有一个数据结构的”路由表“,更具数据包中的目的IP,查路由表,如果查到了 (问的人,恰好知道咋走,,就直接按照路由表给定的方向(从哪个网络接口进行转发),继续转发就行了,如果没査到 (问的人,不知道咋走),路由表里有一个"默认的表项”(下一跳地址),按照默认的表项转发即可~~
四.数据链路层
4.1认识以太网与mac地址
这里也有很多种协议,其中一个比较常见常用的,就是"以太网协议",通过网线/光纤,来通信,使用的协议,以太网协议,以太网,横跨数据链路层 +物理层
以太数据帧的格式为帧头+载荷(IP数据包)+帧尾
这里6个字节的目的地址不是IP地址,是网络中另一套地址体系,mac地址(物理地址),mac 地址由于是6个字节,能表示的范围,比IP 地址大了很多~~
IP 地址虽然早都不够用了,但是 mac 还是够用的.目前来说,每个设备都是有唯一的 mac 地址~~,mac 地址通常是 十六进制 表示的两个十六进制数字就是一个字节,字节和字节之间通常使用-或者:来分割
4.2对比理解IP地址和MAC地址
IP 地址和 Mac 地址各自的用途是什么?
IP 协议立足于全局,完成整个通信过程的路径规划工作
以太网 则是关注于局部, 相邻两个设备之间的通信过程~.
我要回老家(运城->双鸭山)
网络层关注的是路径是什么样的??
运城->太原->哈尔滨->双鸭山
运城->太原->石家庄->哈尔滨->双鸭山
运城->哈尔滨->双鸭山
.......
无论走哪条路,IP数据包里的源IP始终是运城,目的IP始终是双鸭山
网络层关注的是这么多路径我走哪条路
数据链路层关注的是路径是什么样的??
运城->太原:坐高铁
数据报:
源IP:运城 目的IP:双鸭山
源mac地址:运城 目的mac地址:太原
太原->哈尔滨:坐火车
数据报:
源IP:运城 目的IP:双鸭山
源mac地址:太原 目的mac地址:哈尔滨
源 IP 和 目的 IP 始终是整个通信过程中的最初的起点和终点(这里是不考虑 NAT 的情况),源 mac 和 目的 mac 会根据你当前转发的过程每次到达一个节点,往下一个节点转发的时候,源 mac 和 目的 mac 都会随之改变
4.3什么是MTU
MTU: 数据链路层的数据报能携带的最大载荷长度,不同数据链路层的协议的 MTU 是不一样的.MTU 可以考虑成一辆汽车的载重量~~
路是土路,汽车太重了,就容易压坏~~路是沥青的路~~ 载重量就更大路是高速公路级别的,载重量就更大~~
像交换机这样的设备,收到以太网数据帧的时候,就需要进行转发,(这个转发过程就需要能够根据 mac 地址, 判定出数据要走哪个网口,这里的网口是"物理意义"上插网线的口
具体如何转发?
交换机内部也有一个数据结构"转发表”和前面说的路由表, 有点像, 其实还是有一系列差别~~
转发表是一个简单的像 hash 这样的映射(当然这个表不一定是软件实现的,也可能是硬件实现的)
4.4DNS应用层协议
DNS是一套域名解析系统,使用IP地址来描述设备在网络上的位置像我们熟悉的www.baidu.com......,需要有一套 自动的系统把域名翻译成IP地址
如果你想访问某个域名,就先给这个 DNS 服务器发起请求,査询一下当前 域名 对应的 ip,然后再访问目标网站
全世界,无时不刻都有很多设备需要进行 DNS 的请求,这一组DNS服务器,能抗住这么高的请求量吗???
这种所谓的高并发,其实没有那么复杂,核心思路就是两条:
1)开源
搭建DNS系统的大佬们,就开始号召各个网络运营商,你们都可以自己搭建一组"DNS 镜像服务器",镜像服务器的数据,都从他们这边来同步此时用户就会优先访问离自己最近的镜像服务器.
2)节流
让请求量变少,让每个上网的设备,搞本地缓存我的电脑 1min 之内要访问 10 次 www.sogou.com只是让第一次请求 DNS 即可. 把请求得到的结果保存到本地,后面 9 次请求都使用第一次的结果即可~~(域名的变换,没有那么频繁)
好了,为了避免文章太长就先写到这里了,我会在后面的文章中详细介绍http和servlet
相关文章:
《协议栈的骨架:从Web请求到比特流——详解四层架构的可靠传输与流量控制》
前言 本篇博客将详细介绍网络原理(细~~~) 💖 个人主页:熬夜写代码的小蔡 🖥 文章专栏 若有问题 评论区见 🎉欢迎大家点赞👍收藏⭐文章 一.应用层 这里的应用层只是个开头&a…...
软考 系统架构设计师系列知识点 —— 设计模式之创建者模式
本文内容参考: 软考 系统架构设计师系列知识点之设计模式(2)_系统架构设计师中考设计模式吗-CSDN博客 创建者模式_百度百科 建造者模式_百度百科 https://zhuanlan.zhihu.com/p/551870461 特此致谢! Builder Pattern…...
oracle判断同表同条件查出两条数据,根据长短判断差异
目标:同一个物料,账套不同,排查同料号有差异的规格名称 在Oracle数据库中,如果你想查询同一张表中两条数据某个字段的长度不同的情况,你可以使用JOIN语句或者窗口函数(如ROW_NUMBER()、RANK()、DENSE_RANK…...
咋用fliki的AI生成各类视频?AI生成视频教程
最近想制作视频,多方考查了决定用fliki,于是订阅了一年试试,这个AI生成的视频效果来看真是不错,感兴趣的自己官网注册个账号体验一下就知道了。 fliki官网 Fliki生成视频教程 创建账户并登录 首先,访问fliki官网并注…...
【STM32-代码】
STM32-代码 ■ printf() 输出到uart1■■■ ■ printf() 输出到uart1 static UART_HandleTypeDef * g_HDebugUART &huart1;int fputc(int c, FILE *f) {(void)f;HAL_UART_Transmit(g_HDebugUART, (const uint8_t *)&c, 1, DEBUG_UART_TIMEOUT);return c; }int fgetc…...
用cursor三个小时复刻高德地图的足迹地图
用cursor三个小时复刻了高德地图的足迹地图,当然,是“低配”版的。 1、首先要初始化,提出一个需求,让它自由发挥 运行之后发现它报错了,原因出在这行代码,“https://cdn.jsdelivr.net/npm/echarts5,4.3/…...
Git分支管理与工作流实践
Git分支管理与工作流实践 一、Git分支规范与核心原则 主分支(master/main) 核心作用:存储生产环境代码,永远保持稳定且可直接发布。禁止直接在此分支开发。操作规范:仅通过合并release或hotfix分支更新,合…...
python面试总结
目录 Python基础 1、python及其特点 2、动态类型和静态类型? 3、变量命名规则是什么? 4、基本数据类型有哪些? 5、Python 中字典? 6、集合set是什么?有什么特点? 7、python的字符串格式化 函数 1…...
基于骨骼识别的危险动作报警系统设计与实现
基于骨骼识别的危险动作报警系统设计与实现 基于骨骼识别的危险动作报警分析系统 【包含内容】 【一】项目提供完整源代码及详细注释 【二】系统设计思路与实现说明 【三】基于骨骼识别算法的实时危险行为预警方案 【技术栈】 ①:系统环境:Windows 10…...
HarmonyOS 5.0应用开发——五子棋游戏(鸿蒙版)开发
【高心星出品】 文章目录 五子棋游戏(鸿蒙版)开发运行效果开发步骤项目结构核心代码棋盘组件:游戏逻辑处理:主页面: 五子棋游戏(鸿蒙版)开发 五子棋是一款传统的两人策略型棋类游戏࿰…...
避坑,app 播放器media:MediaElement paly报错
System.Runtime.InteropServices.COMException HResult=0x8001010E Message= Source=WinRT.Runtime StackTrace: 在 WinRT.ExceptionHelpers.<ThrowExceptionForHR>g__Throw|38_0(Int32 hr) 在 ABI.Microsoft.UI.Xaml.Controls.IMediaPlayerElementMethods.get_MediaPlay…...
STM32单片机入门学习——第38节: [11-3] 软件SPI读写W25Q64
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.16 STM32开发板学习——第一节: [1-1]课程简介 前言开发板说明引用解答和…...
使用阿里云创建公司官网(使用wordpress)
安装 LNMP 不通的lnmp版本 https://lnmp.org/download.html wget http://soft.vpser.net/lnmp/lnmp2.1.tar.gz -cO lnmp2.1.tar.gztar zxf lnmp2.1.tar.gz && cd lnmp2.1 && ./install.sh lnmp数据库选5.7 选好数据库,会让你设置数据库 root 用户…...
Python程序结构深度解析:顺序结构与对象布尔值的底层逻辑与应用
一、程序结构的三大基石 在计算机科学领域,任何复杂的算法都可以分解为顺序结构、选择结构和循环结构这三种基本结构的组合。这种结构化编程思想由计算机科学家Bhm和Jacopini在1966年首次提出,至今仍是现代编程语言设计的核心原则。 1.1 顺序结构的本质…...
【系统搭建】Ubuntu系统两节点间SSH免密配置
SSH免密配置是MPI分布式、DPDK通信等集群节点间通信的基础配置 1. 安装SSH服务端(所有节点执行) Ubuntu 默认只安装 SSH 客户端(openssh-client),未安装服务端(openssh-server),需要手动安装并…...
美信监控易:揭秘高效数据采集和数据分析双引擎
在当今复杂多变的运维环境中,一款强大的运维管理软件对于保障企业的IT系统稳定运行至关重要。北京美信时代的美信监控易运维管理软件,凭借其卓越的数据分析双引擎,成为了众多运维团队的首选。 首先,美信监控易的数据采集引擎展现出…...
基于STM32+FPGA的地震数据采集器软件设计,支持RK3568+FPGA平台
0 引言 地震观测是地球物理观测的重点,是地震学和 地球物理学发展的基础 [1] 。地震数据采集器主要功 能是将地震计采集的地震波模拟信号转换为数字信 号并进行记录或传输 [2] ,为地震学提供大量的基础 数据。本文将介绍基FPGAARM的地震数据采集器软…...
NO.95十六届蓝桥杯备战|图论基础-单源最短路|负环|BF判断负环|SPFA判断负环|邮递员送信|采购特价产品|拉近距离|最短路计数(C++)
P3385 【模板】负环 - 洛谷 如果图中存在负环,那么有可能不存在最短路。 BF算法判断负环 执⾏n轮松弛操作,如果第n轮还存在松弛操作,那么就有负环。 #include <bits/stdc.h> using namespace std;const int N 2e3 10, M 3e3 1…...
Linux 网络管理深度指南:从基础到高阶的网卡、端口与路由实战
一、网卡管理:构建网络连接的基石 1.1 现代网络工具链解析 在当代Linux系统中,iproute2套件已全面取代传统的net-tools,其优势体现在: 推荐组合命令: ip -c addr show | grep "inet " # 彩色显示有效IP…...
《重构全球贸易体系用户指南》解读
文章目录 背景核心矛盾与理论框架美元的“特里芬难题”核心矛盾目标理论框架 政策工具箱的协同运作机制关税体系的精准打击汇率政策的混合干预安全工具的复合运用 实施路径与全球秩序重构阶段性目标 风险传导与反制效应内部失衡加剧外部反制升级系统性风险 范式突破与理论再思考…...
stateflow中的函数
最近开始使用STATEFLOW,感觉功能比较强大,在嵌入式的应用中应该缺少不了,先将用到的仔细总结一下。还有一点,积极拥抱ai,学会使用AI的强大功能来学习。 在 Stateflow 中,不同类型的函数和状态适用于不同的建模需求。以下是 图形函数(Graphical Function)、Simulink 函…...
41.[前端开发-JavaScript高级]Day06-原型关系图-ES6类的使用-ES6转ES5
JavaScript ES6实现继承 1 原型继承关系图 原型继承关系 创建对象的内存表现 2 class方式定义类 认识class定义类 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible&qu…...
Flutter学习四:Flutter开发基础(一)Widget
Widget 简介 0 引言 本文是对 Flutter Widget 相关知识的学习和总结。 1 Widget 概念 1.1 Widget 基础 Widget 字面意思:控件、组件、部件、微件、插件、小工具widget 的功能是"描述一个UI元素的配置信息",所谓的配置信息就是 Widget 接收…...
Dify智能体平台源码二次开发笔记(6) - 优化知识库pdf文档的识别
目录 前言 新增PdfNewExtractor类 替换ExtractProcessor类 最终结果 前言 dify的1.1.3版本知识库pdf解析实现使用pypdfium2提取文本,主要存在以下问题: 1. 文本提取能力有限,对表格和图片支持不足 2. 缺乏专门的中文处理优化 3. 没有文档结…...
【LaTeX】公式图表进阶操作
公式 解决不认识的符号 查资料:1)知道符号样子;2)知道符号含义 放大版括号 用来括住存在分式的式子,或者用来括住内部由有很多括号的式子。用法是在左右括号[]分别加上\left和\right \[ J_r\dfrac{i \hbar}{2m} \l…...
第二阶段:数据结构与函数
模块4:常用数据结构 (Organizing Lots of Data) 在前面的模块中,我们学习了如何使用变量来存储单个数据,比如一个数字、一个名字或一个布尔值。但很多时候,我们需要处理一组相关的数据,比如班级里所有学生的名字、一本…...
matlab中simulink的快捷使用方法
连接系统模块还有如下更有效的方式:单击起始模块。 按下 Ctrl键,并单击目标块。 图示为已经连接好的系统模块 旋转模块:选中模块后按图示点击即可...
Redux部分
在src文件夹下 的store文件夹下创建modules/user.js和index.js module/ user.js // 存储用户相关const { createSlice } require("reduxjs/toolkit");const userStore createSlice({name:"user",// 数据状态initialState:{token:},// 同步修改方法red…...
基于STM32F103C8T6的温湿度检测装置
一、系统方案设计 1、系统功能分析 本项目设计的是一款基于STM32F103C8T6的温室大棚检测系统低配版。由 STM32F103C8T6最小系统板,OLED显示屏,DHT11温湿度检测传感器,光敏电阻传感器组成, 可以实现如下功能: 使用D…...
设计模式 - 单例模式
一个类不管创建多少次对象,永远只能得到该类型一个对象的实力 常用到的,比如日志模块,数据库模块 饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了 懒汉式单例模式:唯一的实例对象,…...
Linux驱动开发1 - Platform设备
背景 所有驱动开发都是基于全志T507(Android 10)进行开发,用于记录驱动开发过程。 简介 什么是platform驱动自己上网搜索了解。 在driver/linux/platform_device.h中定义了platform_driver结构体。 struct platform_driver {int (*probe…...
力扣-hot100(盛最多水的容器)
11. 盛最多水的容器 中等 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明…...
使用 PyTorch 构建 UNet 图像去噪模型:从数据加载到模型训练的完整流程
图像去噪是计算机视觉中的一个基础问题,在医学图像、遥感、夜间视觉等领域有广泛应用。本文将手把手带你用 PyTorch 构建一个 UNet 架构的图像去噪模型,包括数据预处理、网络搭建、PSNR 评估与模型保存的完整流程。 本项目已支持将数据增强版本保存为独立…...
从信号处理角度理解图像处理的滤波函数
目录 1、预备知识 1.1 什么是LTI系统? 1.1.1 首先来看什么是线性系统,前提我们要了解什么是齐次性和叠加性。...
集合框架--List集合详解
List集合 List 接口直接继承 Collection 接口,它定义为可以存储重复元素的集合,并且元素按照插入顺序有序排列,且可以通过索引访问指定位置的元素。常见的实现有:ArrayList、LinkedList。 Arraylist:有序、可重复、有索引 Linke…...
需求分析---软件架构师武器库中的天眼系统
在软件架构中,需求分析决定了系统的核心设计方向。 然而,现实中的需求往往存在以下问题: 需求被二次加工:产品经理或业务方可能直接提供“解决方案”(如“我们需要一个聊天功能”),而非原始需…...
Spring Cloud Gateway 的执行链路详解
Spring Cloud Gateway 的执行链路详解 🎯 核心目标 明确 Spring Cloud Gateway 的请求处理全过程(从接收到请求 → 到转发 → 到返回响应),方便你在合适的生命周期节点插入你的逻辑。 🧱 核心执行链路图(执…...
Python----机器学习(基于PyTorch框架的逻辑回归)
逻辑回归是一种广泛使用的统计学习方法,主要用于处理二分类问题。它基于线性回归模型,通过Sigmoid函数将输出映射到[0, 1]范围内,表示实例属于正类别的概率。尽管逻辑回归适用于二分类任务,但在多分类问题中常使用Softmax函数&…...
工业数据治理范式革新:时序数据库 TDengine虚拟表技术解析
小T导读:在工业数字化过程中,数据如何从设备采集顺利“爬坡”到上层应用,一直是个难题。传统“单列模型”虽贴合设备协议,却让上层分析举步维艰。TDengine 用一种更聪明的方法打通了这条数据通路:不强求建模、不手动转…...
Linux的应用领域,Linux的介绍,VirtualBox和Ubuntu的安装,VMware的安装和打开虚拟机CentOS
目录 Linux的应用领域 Linux的介绍 Linux的介绍 Linux发行版 Unix和Linux的渊源 虚拟机和Linux的安装 VirtualBox和Ubuntu的安装 安装VirtualBox 安装Ubuntu 下载Ubuntu操作系统的镜像文件 创建虚拟机 虚拟机设置 启动虚拟机,安装Ubuntu系统 Ubuntu基…...
使用 Java 8 Stream实现List重复数据判断
import java.util.*; import java.util.stream.Collectors;public class DeduplicateStreamExample {static class ArchiveItem {// 字段定义与Getter/Setter省略(需根据实际补充)private String mATNR;private String lIFNR;private String suppSpecMod…...
GDAL:地理数据的万能瑞士军刀
目录 1. 什么是GDAL?2. 为什么需要GDAL?3. GDAL的主要功能3.1. 数据转换3.2. 数据裁剪和处理3.3. 读取和写入多种格式 4. 实际应用场景4.1 环境监测4.2 城市规划4.3 导航系统 5. 技术原理简单解释6. 如何使用GDAL?6.1 简单命令示例 7. 学习建…...
每日文献(十三)——Part two
今天从第三章节:“实现细节”开始介绍。 目录 三、实现细节 四、实验 五、总结贡献 六、致谢 三、实现细节 我们在多尺度图像上训练和测试区域建议和目标检测网络。这是在KITTI目标检测基准[13]上基于CNN的目标检测的趋势。例如,在[16]中ÿ…...
ArrayList 和 LinkedList 区别
ArrayList 和 LinkedList 是 Java 集合框架中两种常用的列表实现,它们在底层数据结构、性能特点和适用场景上有显著的区别。以下是它们的详细对比以及 ArrayList 的扩容机制。 1. ArrayList 和 LinkedList 的底层区别 (1) 底层数据结构 ArrayList: 基于…...
【iOS】UITableView性能优化
UITableView性能优化 前言优化从何入手优化的本质 CPU层级优化1. Cell的复用2. 尽量少定义Cell,善于使用hidden控制显示视图3. 提前计算并缓存高度UITableView的代理方法执行顺序Cell高度缓存高度数组 4. 异步绘制5. 滑动时按需加载6. 使用异步加载图片,…...
通过检索增强生成(RAG)和重排序提升大语言模型(LLM)的准确性
探索大语言模型(LLM)结合有效信息检索机制的优势。实现重排序方法,并将其整合到您自己的LLM流程中。 想象一下,一个大语言模型(LLM)不仅能提供相关答案,还能根据您的具体需求进行精细筛选、优先…...
IDEA202403常用快捷键【持续更新】
文章目录 一、全局搜索二、美化格式三、替换四、Git提交五、代码移动六、调试运行 在使用IDEA进行程序开发,快捷键会让这个过程更加酸爽,下面记录各种快捷键的功能。 一、全局搜索 快捷键功能说明Shift Shift全局搜索Ctrl N搜索Java类 二、美化格式 …...
硬件元件三极管:从基础到进阶的电子探秘
一、基础理论 1. PN结(二极管) PN 结是采用不同的掺杂工艺,将 P 型半导体与 N 型半导体紧密接触而形成的一个界面区域。也就是我们常说的二极管。(P型带正电、N型带负电,电流由P流向N) 形成过程࿱…...
4. k8s核心概念 pod deployment service
以下是 Kubernetes 的核心概念详解,涵盖 Pod、Service、Deployment 和 Node,以及它们之间的关系和实际应用场景: 1. Pod 定义与作用 • 最小部署单元:Pod 是 Kubernetes 中可创建和管理的最小计算单元,包含一个或多个…...
12.第二阶段x64游戏实战-远程调试
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 上一个内容:11.第二阶段x64游戏实战-框架代码细节优化 本次写的内容是关于调试、排错相关的…...