Linux网络编程——TCP协议格式、可靠性分析

news2025/4/13 21:42:21

目录

一、前言

二、TCP协议格式

三、TCP的可靠性 

TCP协议的确认应答机制

总结

四、TCP协议的缓冲区及流量控制

五、 TCP流量控制

六、TCP报文类型 标记位


一、前言

在上一篇文章中,我们重点介绍了UDP协议格式的一些内容。在本文中介绍的便是TCP协议格式的相关内容了。

TCP(传输控制协议,Transmission Control Protocol)的全名已经明确指出了它的核心功能——对数据传输进行详细的控制。作为互联网基础通信协议之一,TCP提供了面向连接的服务,确保了数据的可靠传输。

二、TCP协议格式

还是像UDP一样,先从TCP的协议格式来看

看起来比UDP的协议格式复杂很多,在上一篇我们介绍UDP协议时提到过,TCP/IP协议栈 的每一层在进行数据传输时, 都需要考虑三个内容: 封装、解包和分用。

该协议报中也有16位源端口号16位目的端口号,显而易见是解决分用使用的。

剩下的自然而然就是封装和解包时候用的了,下面我们就着重讨论TCP协议的封装和解包

TCP协议的封装和解包

可以看到TCP协议报头在没有选项时是一共20个字节,这些字节的数据是必须的,被称为标准长度。除去这20个字节之外还有一个占有 n字节 的选项,这部分是不固定的,并且也属于TCP协议报头內容。但是尽管选项不是必须的,也不能忽略那n字节 的选项长度。

即,TCP包头的长度最少为20字节,但是并不固定,可能更大。那么问题就来了,报头不固定不像UDP协议报头那样,该怎么封装和解包呢?

观察到TCP报文格式,可以看到一个 4位首部长度,这里存储的数据表示的就是TCP协议报头的长度,但是又有一个问题,TCP报头的长度最少为20字节,但是报头中表示首部长度的数据只有4位,最多也就是能表示16个数据(0000~1111)不太够用呀?

但是实际上是够用的,因为这4位 16个数据的单位并不是1字节,而是4字节,那么也就是说,这四位数据最多可以表示 60字节,即  TCP首部长度最大为60字节。 

例如,如果“首部长度”字段的值是5,这意味着TCP报头的长度是 5×4=20 字节,这是不包含任何选项和填充的标准TCP报头长度。最大值15意味着TCP报头的最大长度可以达到 15×4=6015×4=60 字节。这允许在标准报头的基础上添加选项(如最大段大小MSS、窗口缩放因子等),从而使整个报头扩展到最多60字节。

TCP报头中,首部长度字段是一个4位的值,表示的是32位字(即4字节块)的数量。因此,它只能表示那些是4字节倍数的长度。这意味着TCP报头的实际长度总是4字节的整数倍。

由于这个限制,TCP报头长度不能直接表示为59字节,因为59不是4的倍数。最接近59字节且小于它的4的倍数是56字节,而下一个4的倍数则是60字节。

既然TCP报头中存储有表示报头长度的数据, 那么就可以很好的解决封装和解包的问题 

在UDP中我们有16位UDP长度,而在TCP中只有上述的四位首部长度并没有有效载荷的长度,这是为什么呢?这是因为TCP时是面向字节流的,不需要关心有效载荷如何做区分,只需要将数据一股脑全放在缓冲区中就可以了,对有效载荷做区分是应用层的事情了。而UDP是面向数据报的,他需要对每次发送的数据包作区分。

这里先留一个问题:

TCP报头并没有表示报文总长度的数据, 那么接收端如何接收到报文中所包含的所有数据呢

这个问题要等到介绍网络IP层才会有一个答案

三、TCP的可靠性 

在之前的文章中,我们已经你了解到了TCP和UDP的可靠性和不可靠性。再来回顾一下:

不可靠的传输 - UDP的表现

  1. 无保证的数据完整性:UDP不对传输的数据进行确认,也不提供重传机制。这意味着如果数据包在传输过程中丢失或损坏,不会自动重发。
  2. 无顺序保障:UDP不保证数据包按发送顺序到达接收端。如果应用程序需要有序的数据流,则必须自行处理数据排序问题。
  3. 没有流量控制和拥塞控制:UDP不实施任何流量控制或拥塞控制策略。它尽可能快地发送数据,这对实时应用(如视频会议或在线游戏)是有利的,但可能导致网络拥堵或丢包。
  4. 无连接模式:UDP是无连接的,因此不需要像TCP那样建立连接即可直接发送数据报文。这种方式减少了延迟,适合于需要快速传输的场景。

可靠的传输 - TCP的表现

  1. 数据完整性:TCP通过序列号和确认应答机制确保所有发送的数据都按原样到达目的地。如果接收方检测到数据包丢失或损坏,会请求重传。
  2. 顺序性:即使数据包在传输过程中乱序到达,TCP也能通过序列号将它们重新排序,以确保应用层接收到的数据顺序与发送时一致。
  3. 流量控制:TCP使用滑动窗口技术来防止发送方过快地发送数据而淹没接收方。这有助于维持高效的双向通信。
  4. 拥塞控制:TCP实现了一系列算法来探测网络的拥塞状态,并据此调整发送速率,从而避免网络过载。
  5. 连接管理:TCP是面向连接的协议,在数据传输之前需要建立连接(三次握手),并在完成后关闭连接(四次挥手),这提供了更稳定的通信环境。

TCP协议的确认应答机制

我们知道 TCP协议会对接收方没有正常收到数据的情况做出弥补,但是本机怎么知道接收方是否完整无误接收到了数据呢?通过接收方的回应

只要接收方接受到数据之后,给发送发一个回应,发送发受到了应答,那么就会确认自己刚刚发出的消息一定被接收到了。那么接收方发出回应之后,自己如何确定发送方收到自己的回应了呢?还是同样的方法。如下图所示

所以这就陷入了死循环中, 也就是说 TCP协议也不是完全的可靠, 并且没有协议可以做到完全百分百的可靠,因为在这样的长距离通信中, 永远有一条最新的消息是不能被确认的、没有应答的

但是TCP协议可以做到局部的可靠. 只要保证最新消息之前的消息都有了应答, 那么最新消息之前的数据就可以确定都已经接收到. 这就是TCP协议的可靠性

这样的机制, 被称为 TCP协议的确认应答机制(ACK)

TCP协议的超时重传机制

TCP的超时重传机制表示, TCP通信中, 如果一端长时间没有收到来自对端的应答, 那么就会重新发送没有收到应答的报文

但是, 长时间没有收到对端应答有两种情况:

  1. 报文根本就没有发送到对端, 在传输过程中丢包了,此时对端没有接收到数据
  2. 对端接收到报文了, 并且也发送了应答报文, 但是对端的应答却在传输的过程中丢包了,此时对端接收到了数据

如果对端没有收到数据,此时, 只需要在超时之后 将报文重新发送给对端 就可以了

如果对端收到了数据,如果对端已经收到了数据, 但是对端的应答报文丢了,那么, 当报文重新发送给对端之后, 对端会再次发送应答报文

但是, 此时 对端就会接收到重复的数据. 但重复的报文、数据是没用的 需要丢弃, 所以 TCP协议需要有能力识别接收的报文是否重复

这就要用到TCP报文的 序号字段. 只要两个报文的序号字段相同, 就说明收到了相同的报文

TCP协议的超时重传机制, 说明了TCP报文在发送出去 或 接收到之后, 并不会立刻丢弃, 而是会存储一段时间

这也是 TCP超时重传机制的基础

那么, TCP如何界定 是否超时?

最理想的情况, 就是可以找到一个最短的时间, 保证此次发送之后"确认应答一定能在这个时间内返回".但是, 网络环境是会变化的, 所以这个最短的时间也是不可能固定下来的

所以Linux中TCP协议就需要自行的界定、计算 超时边界

不过, 重传不会一直进行, 当重传累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接

如果超时时间设的太长, 会影响整体的重传效率

如果超时时间设的太短, 有可能会频繁发送重复的包

因此,TCP为了保证无论在何时都能以较高的性能通信,因此会动态的计算这个最大超时时间。


序列号

这里又出现了其他问题:

在使用TCP进行通信时, 发送方可能一下发送很多报文, 接收方可能会一下子收到很多报文, 并且 接收方可能会针对接收到的每一个报文都单独做出应答。但是, 报文在网络中传输是充满不确定性的, 即使按照一定的顺序发送, 也不一定会按照顺序到达。所以, 发送方收到的 接收方的应答报文 很大可能是乱序 (接收方实际也是这样)

那么, 发送方如何确定对方的应答报文, 应答的是哪一个报文呢?

TCP协议报头中的: 32位序号32位确认序号 就是来解决这个问题的。TCP协议在 发送数据 填充报头时, 会填充序号. 那么, 接收方接收到报文之后, 会根据报文的报头中填充的序号, 做出对应的应答. 即, 接收方 会在应答报文的报头中, 填充对应的确认序号,这是贯穿整个TCP可靠性的一个重要设计

确认序号, 一般为接收到的报文序号+1, 表示 确认序号之前的所有序号的报文都已经接收到, 也同时表示接收方期望下次开始接收报文的序号

如下图所示

 

同时, 接收端还可以通过接收到报文的序号对报文进行排序

从这两个序号的作用可以看出来, 发送端报头中的序号 与 接收端报头中的确认序号 是配套使用的

那么, 也就意味着, 同一个报文的报头中, 序号与确认序号是相互独立、互不影响的. 这也是 TCP协议全双工 的一种体现, 因为同一个报文中的序号和确认序号是相互独立的, 所以同一个报文中可以同时填充序号和确认序号, 那么就表示这个报文在具有应答功能的同时, 还携带有数据进行发送

TCP协议规定收到应答报文之后 发送方可以认为 确认序号之前的所有序号的报文都已经接收到

那么, 基于协议, 在实际实现时就可能会出现这样的情况:

 

这是种实现被称为 积累应答延迟应答, 可以有效提高通信效率

按照这样, 如果发送端发送了1~10序号的报文, 但是接收端只收到了1~68~10, 没有收到7

那么, 接收端应答报文中的确认序号 最高也只能填充7, 因为只有7之前序号的报文都收到了, 即使8~10也收到了, 也不会对其做出应答

TCP协议通信时, 报文的起始序号实际是随机的

并且, 后续的序号与 初始序号和报文数据本身 有关

序号协定的规则是什么呢?

首先, 起始序号是在建立连接时协定好的, 是随机的

并且, TCP协议会针对 报文数据的每一个字节进行编号

一个报文的序号, 就表示此 报文数据的第一个字节的编号

如果存在此次TCP通信的第一个报文:

那么上图表示的这个报文中,7214表示此次TCP通信的初始序号, 同样也表示此报文数据的第一个字节的编号,

那么第二个报文应为:

再之后的报文, 同样会按照相同的规则进行编号

总结

序号协定规则

  • 字节流编号TCP将数据视为一个无结构但有序的字节流,并为每个字节分配一个序列号。这意味着发送的数据不是基于报文或段来编号,而是基于每个单独的字节。例如,如果发送的第一个报文包含1000字节的数据,且起始序号为100,那么该报文的最后一个字节的序号就是1099。
  • 确认机制接收方通过ACK(Acknowledgment)字段告知发送方已成功接收到的数据字节数量。ACK值表示接收方期望接收的下一个字节的序列号。例如,如果接收方发送了一个ACK值为2000,这意味着它已经收到了序列号从初始序号到1999的所有字节,并期待着序列号为2000的字节。
  • 数据传输与序号更新每次发送数据时,发送方会根据发送的数据大小更新下一个要发送字节的序列号。比如,若初始序号为100,首次发送了500字节的数据,则下一个待发送字节的序列号将是600(100 + 500)。同样地,当接收方接收到这些数据后,它将使用相应的ACK值来确认这些数据。
  • 重传和重复数据处理如果发送方未在一定时间内收到对某段数据的ACK(即发生超时,该时间是根据网络状况浮动的),则认为该数据丢失并进行重传,所以发送端对于刚刚发送出去的数据并不会像我们想得一样将数据立马移除,而是通过算法先在缓冲区中维持一段时间;此外,TCP还具有处理重复数据的能力,以避免因网络问题导致的数据重复接收(通过序号)

四、TCP协议的缓冲区及流量控制

在介绍UDP协议的文章中提到过, 无论是UDP协议还是TCP协议. 在发送报文时, 都不会直接将数据发送到网络, 而是将数据放入内核针对协议实现的 发送缓冲区 中(UDP没有真正的发送缓冲区). 接收数据也是相同的, 操作系统会将报文放入 接收缓冲区

UDP协议 在内核中没有实现真正的发送缓冲区, 只有接收缓冲区

TCP协议 则在内核中真正实现了 发送缓冲区接收缓冲区

那么, 两个主机在使用TCP协议进行通信, 使用write()/send()read()/recv()接口实现数据发送和接收所执行的操作, 简单理解可以看作:

ssize_t write(int fd, const void *buf, size_t count);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t read(int fd, void *buf, size_t count);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

上述四个调用都需要指定一个buffer 

即, 使用TCP协议进行通信:

调用write()/send()发送数据 实际 是将数据 从进程指定的缓冲区中拷贝到了内核中TCP的发送缓冲区

调用read()/recv()读取数据 实际 是将数据 从内核中TCP的接收缓冲区拷贝到了进程指定的缓冲区中

也就是说,write()/send()实际并没有将数据发送走, 而只是将数据从用户拷贝到了内核数据中

实际上, 常用的I/O类函数, 本质上都是拷贝函数

即使使用write()向文件内写数据, 也只是将拷贝数据交给了操作系统, 并不是直接就写入了文件内

因为, TCP协议在内核中实现拥有发送缓冲区和接收缓冲区并且互不干扰, 所以TCP协议通信是全双工的

并且, 因为TCP协议发送数据, 是将数据拷贝到发送缓冲区, 然后由内核中的TCP协议自行决策(比如: 什么时候发、发多少、要不要进行一些调整…), 所以这个协议叫做 传输控制协议(Transmission Control Protocol)

五、 TCP流量控制

TCP协议在内核中是拥有发送缓冲区和接收缓冲区的, 那么 既然是缓冲区, 那就一定有一定的大小

并且, TCP协议通信是可靠的, 那么对发送出去的数据就不能不管不顾, 不能像UDP那样(如果接收缓冲区满了, 再发送过来的数据报就丢掉不管了)

那么, 如果TCP协议发送数据过快, 导致接受方的接收缓冲区满了, 怎么办? 继续快速的发送数据, 然后接收方来不及接收 直接丢包不管吗?

TCP协议并不会这样. TCP协议为了保障通信效率, 拥有自己的流量控制功能,TCP协议可以获取接收方当前接收数据的能力, 来调节发送方发送数据的速率

但是, client该如何知道server的接受能力呢? server的接收能力又如何表示呢?

缓冲区是有大小的, 那么, server的 接收能力 就可以通过 接收缓冲区的剩余空间大小来表示

那么, client该如何获取server的接收缓冲区剩余空间大小呢?

TCP协议报头中, 有一个字段是 16位窗口大小, 这个 窗口大小表示的就是接收缓冲区剩余空间的大小

如此一来, client接收到server的应答时, 就可以获取到server的窗口大小, 就可以调节自己发送速率, 进而实现流量控制

即, 发送方 可以通过 读取接收方的应答报头中填充的窗口大小, 来了解接收方接受数据的能力, 然后来调控自己发送数据的能力

再思考一个问题

既然在使用TCP协议正常通信时, 发送方可以通过接收方的应答报文中的窗口大小, 来获取接收方的接收能力

那么, 发送方在第一次发送数据的时候, 如何知晓接收方的窗口大小呢?(三次握手)

六、TCP报文类型 标记位

我们都知道, 在使用TCP协议进行通信的时候, 需要先"三次握手"建立连接, 然后才能实现正常的数据通信, 并且在通信结束的时候, 还需要"四次挥手"断开连接

为了方便TCP通信时需要做出一些特殊的处理, 实际上TCP报文是存在类型的, 针对不同类型的TCP报文TCP协议会做出不同的处理和响应:

  • 建立连接过程中发送的报文, TCP协议需要分辨出这个报文是建立连接用的, 然后会做出对应的处理与响应
  • 正常通信过程中发送的报文, TCP协议需要分辨出这个报文是正常通信用的, 然后会做出对应的处理与响应
  • 断开连接过程中发送的报文, TCP协议需要分辨出这个报文是断开连接用的, 然后会做出对应的处理与响应

TCP报文的类型, 则是通过TCP报头中的 6个标记位 来标识、分区的:


                        

  1. URG (Urgent)紧急指针有效标志。当设置时,表示报文中包含有紧急数据,需要优先处理。紧急数据位于数据流的最前面,紧急指针指向最后一个紧急数据字节之后的位置。

    我们知道, 报文在网络中路由时, 有些报文即使发送的早, 也不一定就会很早的到达接收方

    那么也就是说, 在进行TCP通信时, 即使是按照序号的大小顺序发送的报文, 但是报文到达接收方的顺序也不一定是发送时的顺序. 即, 报文按顺序发送, 却乱序到达. 这是不可靠的一种体现, 而TCP协议是可靠的, 那么接收方就需要保证 接收到的数据是按照顺序的

    所以, 接收方可以根据已经发送过来的报文的序号, 对报文进行排序并解包, 如果有数据没有到, 那就应答已经到了数据序号. 让后将排好顺序的报文数据再放到接收缓冲区中. 比如, 如果按照1 2 3 4 5 6 7 8发送数据, 数据却按照3 2 4 1 5 7 8 6的顺序到达了, 如果接收方当时只接受到了3 2 4 1 5 7 8, 还没接收到6, 那么就会对已经接收到的报文排序1 2 3 4 5 7 8, 发现6之前的报文都收到了, 那么接收方就会对1~5序号报文进行解包, 并应答确认序号6

    这样, TCP可以实现报文数据按照发送顺序到达

    但是, 这样会有另外的问题: 有些时候, 应用层需要处理的某些数据优先级比较高. 那么, 此时优先级高的数据如果还按照发送顺序进行接收, 报文到达的早还好, 如果报文到达的很晚, 好像高优先级就没有意义了

    那么, 要解决这个问题, 就需要用到URG标记位了

    当存在紧急数据需要发送时, TCP协议的发送方就会设置URG标志位, 接收方接收到报文读取到URG被设置为1时, 就会选择将紧急数据存入 外带缓冲区. 应用层可以直接从外带缓冲区读取紧急数据, 所以紧急数据也叫做外带数据

    不过, 一个报文中的紧急数据的大小只能是1字节, 这与TCP报头的另一个字段有关: 16位紧急指针

    TCP报头中的紧急指针字段, 实际上就是指紧急数据在本报文数据中的字节偏移量, 并且 只能保存一个偏移量, 也就是说, 一个TCP报文中只能标识1个紧急数据. 这也是为什么紧急数据只能是1字节

  2. ACK (Acknowledgment)确认序号有效标志。当该位被设置时,表示报文段中的确认号字段是有效的。

    按照名字来说, 此标记位表示 该报文是对历史报文的确认, 应答报文应该设置此标记位为1. 但是, 实际上ACK标记位的使用 不仅仅只能作确认用

    因为一般来说, 应答报文也是可以携带数据的, 而应答报文是需要设置ACK标记位的, 也就是说ACK标记位也允许在传输数据时设置

    TCP连接建立后,几乎所有包都应将ACK位置1。

  3. PSH (Push)推送功能标志。提示接收方尽快将数据交给应用程序,而不是等待缓冲区满再进行处理。尽管PSH可以加快数据传递到应用层的速度,但它并不保证即时性。

    要理解这个标记位是干什么用的, 需要先介绍一些Linux操作系统I/O操作的特点

    上面介绍过TCP协议是拥有接收缓冲区的, 而在TCP通信 调用read()是从TCP的接收缓冲区内拿数据到进程设置的缓冲区中

    read()是一个阻塞式的接口, 当TCP接收缓冲区没有数据时, 调用read()的进程也好、线程也好 都会阻塞住, 直到TCP的接收缓冲区有数据了,read()才会继续执行读取数据. 这个过程中, read()只有主动调用 才会检测TCP接收缓冲区是否有数据, 然后才会阻塞或读取数据 的. 但是, 这样的阻塞式I/O并没有非常高效

    所以, Linux实际提供的还有非阻塞式I/O接口(暂时不具体介绍). 也就是说, 应用层可以非阻塞式的从TCP接收缓冲区读取数据. 大概就是, 当TCP接收缓冲区没有数据的时候, 即使调用了非阻塞式接口, 进程或线程也不会阻塞住, 会结束执行. 而, 当TCP接收缓冲区中的数据大小达到一定阈值了(即让应用层读取数据的条件满足了), 内核会去通知进程或线程 可以读取数据了, 然后才会重新调用非阻塞式接口, 然后将数据读取到应用层. 也就是说, 这样的非阻塞式接口, 是不需要主动调用才能接收数据的(当然也可以主动调用), 它可以等待内核的通知, 然后再调用 实现读取数据

    而设置PSH标志位, 就是 让内核通知应用层马上、尽快读取TCP接收缓冲区内的数据 的. 即使TCP接收缓冲区中的数据大小 还没有达到需要让内核通知应用层的阈值(即, 即使让应用层读取数据的条件并没有满足)

  4. RST (Reset)重置连接标志。用来强制关闭连接。通常在检测到错误或无法识别的连接请求时使用,以立即终止连接。

  5. SYN (Synchronize)同步序列号标志。主要用于TCP三次握手过程,发起一个新的连接请求或响应连接请求。SYN标志位仅在建立连接阶段使用,使用时需要将此标志位设置为1。

  6. FIN (Finish)结束标志。表示发送方已经完成数据发送,想要断开连接。在四次挥手过程中,一方会发送带有FIN标志的TCP段来请求关闭连接,使用时需要将此标志位设置为1。

上面的6个标记位本质上代表着不同类型的TCP报文,服务端或者客户端需要根据不同类型的报文执行不同的处理动作。


感谢阅读! 

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

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

相关文章

【深度学习】Downstream Model:预训练模型的下游应用与微调技术

Downstream Model:预训练模型的下游应用与微调技术 文章目录 Downstream Model:预训练模型的下游应用与微调技术1 什么是Downstream Model(下游模型)2 预训练模型与下游任务的关系3 微调技术与迁移学习微调的必要性高效迁移学习参…

C# ref out关键字 理解学习记录

ref 在传参是可以以指针的方式传递,而不是传参数的值 举例,函数返回void ,局部变量要传参后得到结果: ref传参前要实例化赋值,而函数体内不一定要赋值 out 传参前不一定要赋值,而函数体内一定要赋值 ,与r…

Python中的AdaBoost分类器:集成方法与模型构建

引言 在机器学习领域,集成方法(Ensemble Methods)是一种通过结合多个基学习器来提高模型性能的技术。AdaBoost(Adaptive Boosting)是集成方法中的一种经典算法,它通过迭代训练多个弱分类器,并将…

11:00开始面试,11:08就出来了,问的问题有点变态。。。

从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到8月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%…

大模型本地部署系列(1) Ollama的安装与配置

一. Ollama简介 Ollama 是一个 本地化的大模型运行工具,可以让你在自己的电脑(比如Mac、Windows、Linux)上直接下载和运行各种开源的大型语言模型(比如 LLaMA 3、Mistral、Gemma 等),而无需依赖互联网或云…

宝塔面板数据库管理页面打不开,提示405 Not Allowed

宝塔面板数据库的管理按钮打开,提示405 Not Allowed 一般是php版本不匹配。 PHPMyAdmin 4.x PHP 5.2:安装 phpMyAdmin 4.1 PHP 5.3/5.4:安装 phpMyAdmin 4.4 PHP 5.5:安装 phpMyAdmin 4.4 PHP 5.6:安装 phpMyAdmin 4…

文件上传漏洞原理学习

什么是文件上传漏洞 文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。“文件上传” 本身没有问题,有问题的是文件上传后,服务器怎么处理、解释文件。如果服务器的处理逻辑做的不够安全&#…

数字的乘阶运算

求数字的乘阶: 例如:6的乘阶运算:6*5*4*3*2*1 例如:3的乘阶运算:3*2*1 class Program{static void Main(string[] args){Console.WriteLine("请输入数字:");int num_01 Convert.ToInt32 (Con…

OpenCV——图像融合

OpenCV——图像融合 一、引言1.1 图像融合分类 二、C代码实现三、效果展示3.1 标准球3.2 铝制底座 一、引言 在许多计算机视觉应用中(例如机器人运动和医学成像),需要将来自多幅图像的相关信息集成到一幅图像中。这种图像融合将提供更高的可靠性、准确性和数据质量…

基于 Spring Boot 瑞吉外卖系统开发(四)

基于 Spring Boot 瑞吉外卖系统开发(四) 新增分类 新增分类UI界面,两个按钮分别对应两个UI界面 两个页面所需的接口都一样,请求参数type值不一样,type1为菜品分类,type2为套餐分类。 请求方法都为POST。…

C语言for循环嵌套if相关题目

一、题目引入 以下代码程序运行结果是多少? 二、思路解析 进入一个for循环 a<100 进入第一个if b1不大于20为假 进入第二个if b4 a这时a自增为2 当b4时,满足第二个if条件 1.b4,a2 当b7时,满足第二个if条件 2.bb37,a3 当b10时,满足第二个if条件 …

springAOP终极总结

开头先大致说一下bean的生命周期 创建 Bean 实例 → 填充属性 → 初始化前&#xff1a; → 所有 postProcessBeforeInitialization(bean, name) 执行 init 方法&#xff08;比如 PostConstruct&#xff09; → 所有 postProcessAfterInitialization(bean, name) OK&#xff…

紫光展锐5G SoC T8300:影像升级,「定格」美好世界

影像能力已成为当今衡量智能手机性能的重要标尺之一。随着消费者对手机摄影需求日益提升&#xff0c;手机厂商纷纷在影像硬件和算法上展开激烈竞争&#xff0c;力求为用户带来更加出色的拍摄体验。 紫光展锐专为全球主流用户打造的畅享影音和游戏体验的5G SoC——T8300&#x…

视频设备轨迹回放平台用EasyCVR打造变电站智慧消防远程集中视频监控方案

一、方案背景 近年来&#xff0c;电力系统中变电站火灾事故频发&#xff0c;消防势态不容乐观。强化变电站的消防安全管理&#xff0c;成为电网企业核心的任务之一&#xff0c;预防火灾、消除隐患不容延缓。目前&#xff0c;我国消防安全领域仍面临着诸多的挑战&#xff0c;基…

每日定投40刀BTC(13)20250404 - 20250408

定投 坚持 《劲松吟》 千山寒雪覆虬枝&#xff0c; 犹自擎空展翠姿。 岂畏风霜摧瘦骨&#xff1f; 心如磐石立崖时。 十年蓄得凌云志&#xff0c; 终向苍穹吐碧丝。 莫道深冬无劲色&#xff0c; 长将孤影刻天墀。

牛客 小红杀怪

通过枚举所有使用y技能的次数来枚举出所有方案&#xff0c;选出最合适的 #include<iostream> #include<cmath> #include<algorithm> using namespace std;int a, b, x, y; int ans500;int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>&…

部署大模型不再难:DeepSeek + 腾讯云 HAI 实战教程

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

JVM中常见的垃圾回收器(Garbage Collectors)

JVM中常见的垃圾回收器&#xff08;Garbage Collectors&#xff09;的分类和描述&#xff1a; 一、新生代收集器&#xff08;Young Generation Collectors&#xff09; 新生代收集器主要负责收集新创建的对象&#xff0c;这些对象通常存活时间较短。 Serial GC • 单线程收集…

极空间NAS进阶玩法:Debian 系统安装教程

文章目录 第 1 步:下载 Debian 镜像第 2 步:创建虚拟机创建虚拟机安装操作系统第 3 步:登录 Debian第 4 步:使用 Docker 搭建跳板机远程访问参考🚀 本文目标:在极空间 NAS 中安装 Debian 12。 第 1 步:下载 Debian 镜像 下载地址:https://www.debian.org/distrib/ 第…

煤矿数据机房防静电地板:智能化时代的“隐形守护者”

在煤矿行业&#xff0c;调度室不仅是安全生产的“大脑”&#xff0c;更是数据交互的“神经中枢”。随着智能化升级&#xff0c;如今的煤矿调度室早已不再是传统的电话挂图配置&#xff0c;而是集成了高清监控、精准定位系统、智能传感器等高精密电子设备的数字化空间。然而&…