初识Linux · 传输层协议TCP · 下
目录
前言:
滑动窗口和流量控制机制
流量控制
滑动窗口
1.滑动窗口如何移动
2.滑动窗口的大小如何变化的
3.如果发生了丢包如何解决(快重传)
拥塞控制
延迟应答
面向字节流
RST PSH URG
什么是 PSH?
什么是 URG?
那这俩标志会不会冲突?
对比表格:
RST 一般啥时候出现?
1. 你给了我一个莫名其妙的连接
2. 应用层拒绝服务
3. 半开连接或 zombie 连接清理
看到 RST 要不要慌?
前言:
前文我们从TCP的报头字段开始介绍,从最开始的首部长度,到16位的源端口号和目的端口号,然后逐渐从TCP的缓存管理机制开始理解TCP报头中的标志位ACK,并且顺便引出了32位的序号和确认序号,从中我们知道了TCP管理报文的时候是依赖的环形缓冲队列,并且报文是以sk_buff的结构体的形式管理起来的。
前文最后的大头是三次握手和四次挥手,从三次握手我们理解了标志位SYN,顺带理解了什么是超时重传和知道如果连接异常,那么标志位RST会设置为1,重新建立连接。从四次挥手,我们理解了FIN标志位,理解并且验证了三种状态TIME_WAIT,CLOSE_WAIT,LAST_ACK。
那么本文,介绍TCP的其他策略,如滑动窗口,快重传,流量控制,拥塞控制,TCP的异常情况,延迟应答,粘包问题和什么是面向字节流~
干货较多~我们直接进入主题吧!
滑动窗口和流量控制机制
流量控制
对于流量控制来说,在网络世界中,报文的发送是无时无刻的,那么报文的数量控制就成为了一个很重要的点,如果报文发送的数量控制不好,就会导致网络拥塞。
我们来只有两台主机的情况来说,对于主机A和主机B,主机A的接收缓冲区空间是有限的,如果主机B无限制的往主机A中发送报文,那么势必会导致主机B迟迟收不到多余报文的ACK报文,因为主机A处理不过来了,最后导致的结果就是主机B不停的触发超时重传机制,这对网络资源来说无疑是一种浪费,所以两台主机来说有一个很重要的工作就是确认双方的接收缓冲区的大小,那么在什么时候确认就成为了一个比较重要的问题。
实际中,在双方三次握手建立连接的时候,就会通过对方的ACK报文来确定对方的接收缓冲区的大小。
确定了对方的接收缓冲区的大小,就是如何进行报文传输控制了,那么对于流量控制来说,滑动窗口就是它的核心机制之一。
滑动窗口
介绍滑动窗口之前,相信大家都有一个共同的认识就是在应用层调用read和write的接口的时候,实际上都是在内核中拷贝发送缓冲区和接收缓冲区中的数据,那么问题来了,我们前面不管是介绍确认应答机制还是捎带应答机制,都是基于对方接收缓冲区有足够的空间的情况,如果对方的接收缓冲区没有足够的空间,我们是否还能“无所畏惧”的发送报文?
所以从这里我们得出:发送报文之前,对方的接收能力如何?在后面我们介绍拥塞控制的时候,我们还会考虑到网络状况。
那么影响发送报文的大体可以分为:对方的接受能力和网络状况。
在前文我们也形象的描述了OS是如何组织报文的,一个环形队列,那么为了方便学习,我们可以给它简化为一个数组:
形象一点,我们把这里的滑动窗口理解为现实的一个窗口,直接套在了这个数组的上面。而这个滑动窗口套住的就是数据,我们发送缓冲区的数据分为三部分:滑动窗口左边的数据,是已发送已确认的,滑动窗口内部的数据是已发送暂时未确认的,滑动窗口右边的数据是未发送未确认的。
问题来了:滑动窗口的大小我们怎么确定呢?我们通过什么属性来确定呢?
对于滑动窗口的大小,我们在TCP的报头中看到过一个字段叫做16位的窗口大小,而每次发送报文的时候,TCP会在报文中实时更新这个属性的大小,那么,另一方接收到了报头,一看16位窗口大小,就知道自己应该发送多少数据了。
而我们在前文所说的,发送报文我们要考虑对方的接收能力,这个接收能力,难道不就是对方的接收缓冲区的大小吗?所以,滑动窗口的大小,依赖于对方的接收缓冲区的大小。
那么我们肯定不能光这么说,因为即便是对于抽象的连接来说,也是通过内核数据结构描述的,对于协议也是通过udphdr tcphdr进行描述的,对于滑动窗口的大小,我们暂时认为是对方同步给我们的接收缓冲区的大小。
目前对滑动窗口的理解,我们可以列出以下的问题:滑动窗口如何移动?滑动窗口的大小如何变化?滑动窗口可以为0吗?如果发生了丢包,如何解决?
1.滑动窗口如何移动
对于如何移动的问题,首先,我们规定滑动窗口是只能向左移动,不能向右移动,因为发送缓冲区中的数据都是明确规定了应答和发送的关系的,如果滑动窗口向右移动,势必就破坏了规定。
2.滑动窗口的大小如何变化的
滑动窗口的大小我们在逻辑上可以简单的使用win_start和win和win_end简单来代表窗口的起点,窗口大小,窗口结束位置,但是实际上,如果我们阅读源码,我们会发现TCP报头中的16位窗口大小和源码中的窗口大小属性对不上:
/** RFC793 variables by their proper names. This means you can* read the code and the spec side by side (and laugh ...)* See RFC793 and RFC1122. The RFC writes these in capitals.*/u32 rcv_nxt; /* What we want to receive next */u32 copied_seq; /* Head of yet unread data */u32 rcv_wup; /* rcv_nxt on last window update sent */u32 snd_nxt; /* Next sequence we send */u32 snd_una; /* First byte we want an ack for */u32 snd_sml; /* Last byte of the most recently transmitted small packet */u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */u32 lsndtime; /* timestamp of last sent data packet (for restart window) */
这是滑动窗口在Linux内核中的定义,版本为2.62.32,我们发现好像窗口的属性基本都是32位的,它们对不上的原因实际上是因为我们没有介绍TCP中的选项,选项里由一个叫做“窗口扩大因子”,这个扩大因子,就可以让窗口大小从65535一直到1GB左右,所以我们在源码中看到的实际上是32位。
当接收方收到了报文,并且给发送方返回报文,其中有确认序号,这个确认序号恰好代表了发送方在滑动窗口内的哪些数据被接收了,那么有了确认序号,也就是ack_seq,win_start = ack_seq, 更新窗口的起始位置,因为我们能通过确认序号确定之前的数据接收方都收到了,所以此时满足窗口左边的数据是已发送已确认的,然后win_end = win_start + win,通过对方的ACK报文,我们有它的窗口大小,那么我们已经确定了窗口的起始位置,所以可以通过对方的窗口大小确定,win_end的位置。
这是窗口的大小变化,那么有意思的来了,我们在第一个小问题中知道窗口是只能往右边移动的,那么移动的快慢,是取决于win_start, win_end的,那么如果,对方的返回的窗口大小为0,也处理了一定的报文,那么,它返回的确认序号是不是会更新?win_start就会更新,win_start更新了,但是win为0,那么win_start = win_end,此时窗口大小不就为0吗?
那么问题来了,滑动窗口的移动快慢,实际上看的不就是win_start++和win_end谁更新的更快,更多吗?
而在源码的角度来看,win_start和win_end实际上就是序号之间的加法而已,所以源码中的属性基本都是和序号有关的,当然有时间戳变量我们暂时先不管。
3.如果发生了丢包如何解决(快重传)
这个问题才是滑动窗口中问题的重中之重了,对于发送缓冲区的数据,我们可以分为滑动窗口左边的数据,滑动窗口内部的数据,滑动窗口右边的数据,那么实际要发送的数据是滑动窗口内部的报文,对于内部的报文,我们可以这样排序,最左侧的报文,中间的报文,最右侧的报文,我们从三个角度来考虑,如果发生了丢包,我们如何解决?
对于最左侧的报文丢失:
假设发送2001 3001 4001 5001,而实际情况是2001-3000的报文收到,3001到4000的报文收到,4001到5000的报文收到,1001到2000的报文丢失了,此时会返回三个报文的确认序号不会是3001 4001 5001,因为1001到2000的报文丢失,在前文我们已经介绍了确认序号要保证的是TCP的可靠性,这个可靠性实际上是保证的历史报文能被收到,所以实际上三个ACK报文的确认序号是1001,因为1-1001的报文是已经发送,并且已经确定了,对于1001-2000的报文没有收到,为了可靠性,所以确认序号应该为1001。
此时,因为三个ACK报文的确认序号都是1001,OS就知道1001-2000的报文没有收到,所以此时就触发高速重发机制,即快重传,那么快重传的触发条件也很明显,OS连续收到三个同样确认序号的报文,就会根据实际情况看是否触发快重传了。
那么有意思来了,我们前文学习过超时重传机制,超时重传机制和快重传的机制有什么区别呢?或者说它们的应用场景有什么不同。
我们不妨把超时重传机制理解为兜底的机制,同样都是重传,因为超时重传机制等待的时间较久,在系统中配置了对应的超时时间,过了这个时间没收到应答在重传,而快重传是连续收到多个一样的确认序号,此时直接重传,不用等待那么久的超时时间。那么它在一定程度上提高了重传的效率,主要是因为它提前判断,响应的更快了。
在TCP中结合了这两个机制,在提高重传效率的同时,也有保底机制,极大程度上保证了TCP的效率和可靠性。
对于丢包还有一个小小的问题,如果是ACK丢失了呢?也就是说返回的是2001 3001 5001,其中丢了某个应答,是完全没有关系的,因为TCP的可靠传输。
好了,视角放到中间报文丢失和右侧报文丢失,不管了哪一侧报文丢失,左侧的数据成功发送并应答,那么滑动窗口就会通过确认序号更新,测试win_start变为新的确认序号,此时问题就演化为了最左侧的报文丢失应该怎么办?就和我们上面的问题形成了完美闭环!
那么问题来了,丢失的报文,我们放在哪儿?已发送已确认的报文,我们怎么处理?
首先对于第一个问题,丢失的报文,我们放在哪儿?当一个报文段丢失时,TCP 不会立刻把它移出窗口,而是将它保留在发送窗口区间内,等待超时重传或者重传就可以了嘛。
对于第二个问题,已经被接收方确认(ACK)的数据,就说明这段数据已经“安全送达”了。此时 TCP 会将它从发送缓存中移除,释放内存。而用于发送的缓冲区通常是一个环形缓冲区,指针会不断向前推进,旧位置的数据会被新数据覆盖。
这就像写磁带一样,头部已经播放完的内容,可以被下一段录音覆盖,节省空间又高效。
TCP 的滑动窗口不仅用于控制发送速率,还承担了“数据暂存与重发控制”的职责。
拥塞控制
前文我们说暂时认为滑动窗口的大小是对方的接收缓冲区的大小,但是实际情况上,我们考虑了双方主机的通信能力,却忘记了网络的状态,比如网络拥塞怎么办,网络波动了怎么办?
对于滑动窗口的介绍,我们都是基于网络状况良好的情况下,现在局域网内存在多台主机,而网络资源是有效的,比如网络带宽,所以势必会存在一种情况为:多台主机共享网络资源,导致主机之间通信速度变慢。
所以我们需要合理的策略来解决拥塞的问题,就像堵车的马路上会引入交警这个角色一样,来解决拥堵的问题。
首先,在多台主机通信之前,都会获取窗口大小来了对方的接收缓冲区,但是实际上,滑动窗口的大小并不是完全取决于对方的接收缓冲区的,因为要考虑网络资源,所以引入了拥塞窗口的概念,同样,在tcp_sock中描述了滑动窗口的,也描述了拥塞窗口:
/** Slow start and congestion control (see also Nagle, and Karn & Partridge)*/u32 snd_ssthresh; /* Slow start size threshold */u32 snd_cwnd; /* Sending congestion window */u32 snd_cwnd_cnt; /* Linear increase counter */u32 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */u32 snd_cwnd_used;u32 snd_cwnd_stamp;
其中cwnd代表的就是拥塞的意思。
其中snd_ssthresh代表的是慢启动门限值,snd_cwnd代表的是当前拥塞窗口的大小,snd_swnd_cnt代表的是每次收到ACK就+1,到了一定的程度就会进行线性增长。snd_cwnd_clamp代表的是拥塞窗口的最大值。
同学们也注意到了,对于以上的字段,都是用来描述拥塞窗口的,并且引入了慢启动算法,我们以下面的图介绍拥塞避免:
首先我们清楚滑动窗口大小=min(对方接收能力,拥塞窗口),那么在通信初期,对方的接收能力可以说是杠杠的,因为初期的报文积攒并不多,所以可以说接收空间非常大。
但是可以很负责任的说,不考虑拥塞窗口的传输都是耍流氓,你别看别人的接受能力那么强你就使劲发报文,比如两个地点,中间有一条马路,A点可以放100辆车,那么你难道就知道整100辆车过去吗?显然不能,因为马路不足以支撑100辆车,而实际上也有别的车要通过,所以我们初期需要发报文探测实际能通过多少车。
网络也是如此,初期从1个报文开始发送,然后按照指数级别增长,为什么不线性增长呢?因为通信的时候,我们虽然要考虑拥塞的问题,但是同时也要兼顾效率,所以前期,是按照指数增长的。那么增长到了ssthresh的时候,就开始按照线性增长了,因为再double一下,就超出了拥塞窗口的范围了。线性增长的过程我们叫做加法增大。
而一直加大的过程,总会碰到网络拥塞的时候,此时直接跌到1,重新探测网络状态,并且设置了新的临界值,跌到1的这个过程我们称为乘法减小。
以上的图我们看到的是拥塞避免算法AIMD的核心框架,实际上最后拥塞窗口的值会处于一个带宽的某个极限值震荡,以保证通信的稳定传输。
有个问题就是,我们如何确认是网络拥塞了呢?对于少量的丢包,我们可以认为是网络波动,并且采取超时重传或者是快重传的方式解决,但是如果是大量丢包,我们就有理由认为是网络拥塞了。
延迟应答
延迟应答指的是对方发送报文之后,接收方等会儿再给应答。
对于初学TCP的同学对于延迟应答大概会感觉有点怪,我明明可以快速应答它,为啥还要延迟呢?因为有一种情况是,上层应用处理报文的速度极快,如果接收方收到了报文,马上应答,那么窗口大小是接收大小-该报文的大小。
但是当报文以极快的速度处理了之后,接收方再应答,此时窗口的大小就是接收缓冲区的大小了。并且我们在学习Redis的时候我,就像 Redis 推出的 mset
是为了减少多次 set 带来的网络开销,TCP 的延迟应答机制也是为了减少不必要的 ACK 报文数量。与其频繁确认,不如一次性“捎带”更多信息,提高效率。
这里也是一样的,我能一次接收多个报文,为什么要马上应答,然后接收少数的报文呢?
延迟应答也是有一定的配置的,主要是最大延迟时间和数量限制。一般设置的是延迟2个包和延迟时间设置为200ms,当然了不同的系统有不同的配置。
如图这样。
面向字节流
TCP的特点是面向字节流,学习到了这里,我们也能对于UDP的面向数据报和TCP的面向字节流有了一个较为清晰的分辨了。
首先,UDP的面向数据报特点主要是因为UDP发送数据的时候,是直接把整个数据打包发送的,接收方只能一次性全部接受,并且不会存在数据需要拼接的问题,一次性就接收了,那么丢包了无所谓,反正不是我UDP的事儿。
其次,TCP的面向字节流主要是因为TCP的数据是放在缓冲区之后,根据序号发送,而序号的本质是数据在缓冲区按照字节单位编排出来的,而经过TCP的层层封包之后,不同数据包按照序号可能被分配到一个报文里面,那么这个过程是没有人关心哪个数据是哪个包的,我们以一个统一的视角来看待报文,就是基本单位字节,没人关心里面的数据是谁的,我只知道这个数据的基本单位是字节。
那么在C语言阶段学习的文件操作,同样,也是面向字节流的,这里的面向字节流,和TCP的面向字节流是完全一样的,所以在文件操作的时候会用大量的时间去学习,主要就是因为面向字节流我们当时并不理解。
到了这里,我们已经了解了面向字节流,而以字节的统一视角去看待问题就会有其他问题,比如粘包问题,因为不同的数据包的数据按照字节,进到了同一个报文里面,我们如何将不同的数据拆出来呢?
记得我们之前写的HTTP服务器吗?
对于粘包问题我们简单的总结:对于定长数据包,我们按照固定长度来接收,对于变长数据包,我们可以引入一个特殊分隔符,标识数据包的结尾,我们也可以引入一个字段标识数据包的长度。
像这样:
uint32_t len;
recv(sock, &len, 4); // 读取消息长度
len = ntohl(len); // 网络字节序转本地
recv(sock, buf, len); // 按长度读取完整消息
RST PSH URG
在 TCP 报头里,大家最熟的无非就是 SYN、ACK、FIN 这些字段,用来建立连接、确认、断开连接。但除了这些“明星字段”,还有两个小透明字段:PSH(Push) 和 URG(Urgent)。大多数人学 TCP 都直接跳过它们,觉得用不到,其实这俩字段还是有点意思的。
什么是 PSH?
PSH 的意思是:“我发的这些数据你就别等了,快点扔给上层应用吧。”
我们知道,TCP 是一个带缓冲的协议,它可能接收了一点数据,但不会立刻交给上层应用,而是等攒多一点再交。但是有些时候,我们希望这个过程别拖了,比如下面这些场景:
-
你在远程终端(比如 SSH)打了一个字母,对方应该立刻看到结果。
-
聊天程序,你敲一句“在吗?”,当然希望对方立即看到。
-
实时指令,比如发送一个“退出”、“取消”命令,不能等。
这些时候就需要 PSH 上场。它的作用就是:告诉对方 TCP 栈,别攒包了,赶紧把这些数据交上去。
什么是 URG?
URG 这个就更冷门一点,叫 Urgent,意思是“这里有段数据是紧急的,你优先处理”。
这个字段配合一个 **紧急指针(urgent pointer)**使用,告诉接收方:从某个偏移量开始,有一段字节很重要,你先把它捞出来处理。
举个例子:
-
Telnet 协议早期就用 URG 实现“中断”功能,比如你敲 Ctrl+C,它就发一个带 URG 标志的包,中断对方的执行。
但说实话,URG 现在用得非常非常少,很多系统对它支持也不统一,甚至直接忽略。像我们现在熟悉的 Redis、HTTP、gRPC 等现代协议,根本用不到它。
那这俩标志会不会冲突?
其实不会。
-
PSH 是说:“别等了,我发的这段你马上处理。”
-
URG 是说:“我发的这一部分,特别重要,你先处理这段。”
它们的粒度不一样。PSH 是报文整体行为的建议;URG 是精确到字节范围的优先级提示。而且 URG 需要配合指针使用,PSH 是隐式的,很多时候系统自己会帮你处理。
对比表格:
对比项 | PSH(Push) | URG(Urgent) |
---|---|---|
功能 | 请求立即将数据交给应用层 | 指定某段数据优先处理(紧急数据) |
使用目的 | 提高实时性,减少等待 | 中断、控制信号等特定用途 |
影响范围 | 整个报文 | 报文中的一段数据(由 urgent pointer 定位) |
典型场景 | SSH、Telnet 交互、实时通信 | Telnet 中断(Ctrl+C) |
现代系统支持 | ✅ 自动处理,常见 | ❌ 多数协议/语言已不支持 |
应用层是否处理 | 不需要显式处理,系统会交给应用 | 应用需读取“紧急数据”,处理逻辑更复杂 |
是否常用 | ✅ 常用(甚至自动设置) | ❌ 非常少用,基本淘汰 |
说白了,RST 就是 TCP 协议里的“出事了,赶紧断开”按钮。
我们平时连接断开不是都有一个优雅的四次挥手吗?你 FIN,我 ACK,我 FIN,你 ACK……然后大家礼貌说再见。但 RST 可不管那么多,它直接说:“不玩了,掀桌子!”——连接不正常,直接重置。
RST 一般啥时候出现?
1. 你给了我一个莫名其妙的连接
比如你这边给我发了个 ACK,但是我根本没这个连接(也许我重启了),我一脸懵逼,干脆发个 RST 给你,告诉你“这连接别用了”。
2. 应用层拒绝服务
有些服务端一看你这连接不合法,比如权限问题、校验失败,它就用 RST 告诉你:“你走吧,我不收。”
3. 半开连接或 zombie 连接清理
有些时候,一方掉线了,另一方还傻傻等着。这个时候,系统探测之后可能会用一个 RST 来直接清理。
看到 RST 要不要慌?
不用慌,但要注意。
-
如果你自己在开发应用,一不小心被 RST 了,那得排查:
-
是不是你用错了端口?
-
是不是连接早就断了你还在用?
-
是不是服务器主动踢你了?
-
-
如果你只是用现成软件,偶尔看到 RST,其实也正常,比如连接被负载均衡打断啥的,不用太紧张。
项目 | RST 标志说明 |
---|---|
全称 | Reset |
触发时机 | 异常连接请求、资源不存在、主动拒绝等 |
行为 | 立即断开连接,不走四次挥手 |
应用层能看到吗 | 能看到 socket 报错,通常是 connection reset |
常见场景 | 服务端拒绝连接、半开连接清理、端口未监听 |
是否正常现象 | 有时是预期行为,有时是 bug,需结合上下文分析 |
以上就是TCP传输层协议的所有内容~
感谢阅读!
相关文章:
初识Linux · 传输层协议TCP · 下
目录 前言: 滑动窗口和流量控制机制 流量控制 滑动窗口 1.滑动窗口如何移动 2.滑动窗口的大小如何变化的 3.如果发生了丢包如何解决(快重传) 拥塞控制 延迟应答 面向字节流 RST PSH URG 什么是 PSH? 什么是 URG&…...
OpenCv实战笔记(4)基于opencv实现ORB特征匹配检测
一、原理作用 ORB 原理(Oriented FAST and Rotated BRIEF): 特征点检测:使用 FAST 算法检测角点(关键点)。 方向计算:为每个关键点分配主方向,增强旋转不变性。 特征描述:…...
LeetCode LCR 007. 三数之和 (Java)
题目描述 给定一个整数数组 nums,判断是否存在三个元素 a, b, c,使得 a b c 0?找出所有满足条件且不重复的三元组。 解题思路 核心方法:排序 双指针 排序:首先将数组排序,便于后续去重和双指针操作。…...
Spark的三种部署模式及其特点与区别
Spark支持多种集群部署模式,主要分为以下三类: 部署模式特点适用场景资源管理依赖Local模式单机运行,所有进程(Driver、Executor)在同一个JVM中开发调试、小规模数据测试无集群资源管理,仅本地线程模拟无需…...
2505d,d的借用检查器
void func(scope ref int*) {}unique(int*) a ...; assert(a !is null);unique(int*) b a; assert(a is null); assert(b !is null);func(b); // ok用live作为检查器,不必有断定了. int* a ...; int* b a; // 所有权转至b *a 3; // 不能再用a.编译器保证约束指针. live…...
前端EXCEL插件,智表ZCELL产品V3.0 版本发布,底层采用canvas全部重构,功能大幅扩展,性能极致提升,满足千万级单元格加载
本次更新是底层全部重构,按照现代浏览器要求,采用canvas方式进行了重构,预留了将来扩展空间,特别是在大数据量性能提升方面有了较大提升,可以满足千万级单元格加载,欢迎大家体验使用。 体验地址࿱…...
如何理解编程中的递归、迭代与回归?
作为编程初学者,递归、迭代和回归这三个概念常常让人感到困惑。本文将通过生活化的比喻、Python代码示例和直观的对比,帮助你彻底理解这三个重要概念及其应用场景。 一、从生活比喻理解核心概念 1. 递归(Recursion)—— 俄罗斯套…...
【金仓数据库征文】学校AI数字人:从Sql Server到KingbaseES的数据库转型之路
摘要:本文围绕学校 AI 数字人项目从 Sql Server 数据库替换至 KingbaseES 数据库的实践展开,涵盖迁移背景、两种数据库对比、替换实施步骤、应用效果展示、问题与解决措施等多方面内容,为教育领域类似项目提供了详实参考。 目录 1.背景与需求…...
stm32 lcd绘制波形和频谱
一、项目准备 主要利用LCD驱动中的画点和画连线函数,驱动是正点原子给我写好了的画点和画线的函数等些相关函数 void LCD_Draw_Circle(u16 x0,u16 y0,u8 r); //画圆 void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2); //画线 二、画波形图函数实…...
深入理解卷积神经网络的输入层:数据的起点与预处理核心
内容摘要 本文围绕卷积神经网络输入层展开,详细介绍其在网络中的重要作用,包括接收不同领域数据的形式及传递数据的过程。深入解读数据预处理的关键操作,如去均值、归一化和PCA/白化。助力读者透彻理解输入层,为构建高效卷积神经…...
基于大模型与异步技术的股票分析系统实现
在金融量化分析领域,高效的数据获取与智能的策略决策是核心竞争力。本文结合异步数据抓取技术与大模型工具集成,构建一套完整的股票分析系统,实现从海量数据采集到智能信息查询的全流程自动化。 一、量化分析的数据基石:异步高效…...
BUCK基本原理学习总结-20250509
一、电感伏秒平衡特性 处于稳定状态的电感,开关导通时间(电流上升段)的伏秒数须与开关关断(电流下降段)时的伏秒数在数值上相等,尽管两者符号相反。这也表示,绘出电感电压对时间的曲线,导通时段曲线的面积必须等于关断时段曲线的面积。 二、BUCK的基本概念和原理 基…...
BERT类模型
1. BERT类模型是否需要处理 [CLS] 或池化? 那首先搞懂 [CLS] 和池化 (1)[CLS] 的作用 BERT 的输入格式中,每个序列的开头会添加一个特殊的 [CLS] Token(Classification Token)。它的设计初衷是为分类任务…...
Taro 编译不平不同平台小程序
Taro 提供了针对不同小程序平台的编译命令,主要通过 --type 参数指定目标平台。以下是各平台常用命令及说明: --- ### **一、核心命令格式** 1. **直接使用 taro-cli** bash taro build --type [平台类型] taro dev --type [平台类型] # 开发模式&…...
PHP框架在分布式系统中的应用!
随着互联网业务的快速发展,分布式系统因其高可用性、可扩展性和容错性成为现代应用架构的主流选择。而PHP作为一门成熟的Web开发语言,凭借其简洁的语法、丰富的框架生态和持续的性能优化,逐渐在分布式系统中崭露头角。本文将深入探讨PHP框架在…...
PCB设计实践(十三)PCB设计中差分线间距与线宽设置的深度解析
一、差分信号的基本原理与物理背景 差分信号技术通过两条等幅反相的传输线实现信号传输,其核心优势体现在电磁场耦合的对称性上。根据麦克斯韦方程组的对称解原理,两条线产生的电磁场在远场区域相互抵消,形成以下特性: 1. 共模噪…...
在 Kubernetes 中使用 Docker 实现 GPU 支持的完整方案
目录 在 Kubernetes 中使用 Docker 实现 GPU 支持的完整方案 一、背景说明 二、目标 三、环境准备 四、安装 NVIDIA Container Toolkit(nvidia-docker2) 五、配置 Docker 支持 NVIDIA Runtime 六、测试 Docker 能否使用 GPU 七、部署 Kubernetes…...
Vision Transformer(ViT)
Vision Transformer(ViT)是一种将Transformer模型应用于计算机视觉任务的创新方法,由Google Research团队在2020年提出。它打破了传统卷积神经网络(CNN)在图像处理中的主导地位,通过全局注意力机制…...
(剪映)字幕实现卡拉OK效果
三种实现方式: 一、剪映自带“模板” 二、剪映自带“动画” 三、使用蒙版特效 具体操作步骤如下 模板的方式 一、模板的方式 1.在时间线轨道区 选中文本 2.在工具栏区中的文本-->模板中选择要实现的效果,左键单击,即可实现效果&am…...
Java结构化并发深度解析:原理、设计与实践
作为Java开发者,当我们需要处理复杂的并发场景时,传统的线程和ExecutorService模型往往导致代码难以维护和调试。Java 21引入的结构化并发(Structured Concurrency)通过创新的设计理念彻底改变了这一局面。本文将深入剖析其实现原理、架构设计,并通过复杂场景案例展示其强大…...
【Linux系列】跨平台安装与配置 Vim 文本编辑器
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
Level1.5算数运算符与赋值运算符
目录 一、算术运算符和赋值运算符 1.1算术运算符 - * / % // ** 1.2.赋值运算符 - * / % // ** 二、等比例缩小(变量火柴人案例) 三、颜色的三种表达方法取余%运算 1.颜色单词 turtle.pencolor(pink) 2.RGB颜色turtle.pe…...
基于GF域的多进制QC-LDPC误码率matlab仿真,译码采用EMS算法
目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下(完整代码运行后无水印): 本课题实现的是四进制QC-LDPC 仿真操作步骤可参考程序配套的操作视频。 2.算…...
CentOS 7 修改锁屏时间为永不
在 CentOS 7 中,默认情况下,系统会在一定时间不活动后自动锁屏。对于某些用户来说,可能希望禁用自动锁屏功能或者将锁屏时间设置为“永不”。本文将介绍如何通过图形界面和命令行两种方式修改 CentOS 7 的锁屏时间,确保系统永不自…...
STM32-ADC模数转换器(7)
对GPIO来说,它只能读取引脚的高低电平,使用了ADC模数转化器之后,就可以对高电平和低电平之间的任意电压进行量化,最终用一个变量来表示,读取这个变量,就能得到引脚输入的具体电压是多少了。 ADC模数转化器…...
前端SSE技术详解:从入门到实战的完整指南
前端SSE技术详解:从入门到实战的完整指南 一、初识SSE:比WebSocket更轻量的选择 很多开发者第一次听说Server-Sent Events(SSE)时,都会下意识问:“这和WebSocket有什么区别?” 就像选择交通工…...
mac u盘重装mac10.15Catalina系统
我的电脑提mac2017的air 重装过程 (文件夹中间有空格时为 Install\ macOS\ Catalina 才行) (有需要的,最好做一下备份,有些东西可以及时找到配置和文件之类的, u盘制作是在mac电脑上操作的) 一、先下载系统镜像文件或自行到官方…...
8051模板移植
8051模板移植 一,新建工程文件二,Keil配置 一,新建工程文件 在工程文件下建立Driver和User 打开Keil,点击扳手选择芯片型号 出现下图情况,选择是,然后会多出一个启动文件,以后有用 二&…...
轻松制作高质量视频,实时生成神器LTX-Video重磅登场!
探索LTX-Video:实时视频生成跨越新高度 在如今这个视觉内容主导的数字时代,视频生成成为推动创意表达的关键。而今天,我们将带您深入探索LTX-Video,一个强大的开源项目,致力于通过尖端技术将视频生成提升到一个全新的…...
两个数组的交集(暴力、set、哈希)
一.题目 给定两个数组 nums1 和 nums2 ,返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1: 输入:nums1 [1,2,2,1], nums2 [2,2] 输出:[2]示例 2: 输入…...
[架构之美]Spring Boot多环境5种方案实现Dev/Test/Prod环境隔离
[架构之美]Spring Boot多环境5种方案实现Dev/Test/Prod环境隔离(十六) 摘要:本文深入剖析Spring Boot多环境配置的5种实现方案,涵盖YAML分组配置、Maven Profile集成、Kubernetes适配等企业级实践,并附赠配置加密方案…...
LWIP的IP协议笔记
IP协议简介 IP协议是TCP/IP协议族的基石,它为上层提供无连接、不可靠的服务 无连接:指IP通信双方都不长久的维持对方的任何信息。这表示上层协议每次发送数据,都需要明确指出对方的IP地址 不可靠:指IP协议不能把IP数据报准确到…...
matlab介绍while函数
MATLAB 中的 while 语句介绍 在 MATLAB 中,while 语句是一种循环结构,用于在满足特定条件时反复执行一段代码块。与 for 循环不同,while 循环的执行次数是动态的,取决于循环条件是否为真。 语法 while condition% 循环体代码 e…...
每日算法刷题Day2 5.10:leetcode数组1道题3种解法,用时40min
4.LC 旋转矩阵(中等,学习) 面试题 01.07. 旋转矩阵 - 力扣(LeetCode) 思想: 法一: 额外空间数组来回赋值拷贝 法二: 1.翻转90度得到等式a[j][n-i-1]a[i][j],但是会改变a[j][n-i-1]原始值,再去看该位置变到哪一位置 分析可得,4个…...
【图书管理系统】深度讲解:图书列表展示的后端实现、高内聚低耦合的应用、前端代码讲解
1.约定前后端交互接口 [请求] /book/getListByPage [参数] currentPage1&pageSize10 [响应] 返回封装的result对象对应的Json数据 2. 整体逻辑 2.1 Controller的逻辑 (1)把接收的参数封装为PageRequest类,里面有属性:curren…...
本地大模型工具深度评测:LM Studio vs Ollama,开发者选型指南
引言 在大语言模型本地化部署的技术浪潮中,隐私保护与成本优化成为核心诉求。LM Studio与Ollama作为两款明星级本地大模型工具,凭借对开源模型的支持能力,成为开发者关注的焦点。本文将从技术架构、应用场景、实操体验三个维度展开深度对比&a…...
天线的PCB设计
目录 天线模块设计的重要性 天线模块的PCB设计 天线模块设计的重要性 当智能手表突然断连、无人机信号飘忽不定——你可能正在经历一场来自天线模块的"无声抗议"。这个隐藏在电子设备深处的关键组件,就像数字世界的隐形信使,用毫米级的精密结…...
《P1226 【模板】快速幂》
题目描述 给你三个整数 a,b,p,求 abmodp。 输入格式 输入只有一行三个整数,分别代表 a,b,p。 输出格式 输出一行一个字符串 a^b mod ps,其中 a,b,p 分别为题目给定的值, s 为运算结果。 输入输出样例 输入 #1复制 2 10 9输…...
推荐一款免费开源工程项目管理系统软件,根据工程项目全过程管理流程开发的OA 办公系统
在当今的工程项目管理领域,许多企业和团队面临着诸多难题。传统的管理方式往往依赖于人工记录和分散的工具,导致项目进度难以实时把控,任务分配不够清晰,合同管理混乱,事件提醒不及时,财务管理缺乏系统性&a…...
AZScreenRecorder最新版:功能强大、操作简便的手机录屏软件
AZScreenRecorder最新版是一款功能强大的手机录屏软件,专为安卓设备设计。它无需ROOT权限,支持无限录制时长,操作简单,录制过程中可以随时暂停,满足不同用户的个性化录屏需求。此外,用户还可以自定义分辨率…...
[sklearn机器学习概述]机器学习-part3
获取数据、数据处理、特征工程后,就可以交给预估器进行机器学习,流程和常用API如下。 1.实例化预估器(估计器)对象(estimator), 预估器对象很多,都是estimator的子类(1)用于分类的预估器sklearn.neighbors.KNeighbors…...
[模型选择与调优]机器学习-part4
七 模型选择与调优 1 交叉验证 (1) 保留交叉验证HoldOut HoldOut Cross-validation(Train-Test Split) 在这种交叉验证技术中,整个数据集被随机地划分为训练集和验证集。根据经验法则,整个数据集的近70%被用作训练集ÿ…...
PyTorch API 1 - 概述、数学运算、nn、实用工具、函数、张量
文章目录 torch张量创建操作索引、切片、连接与变异操作 加速器生成器随机采样原地随机采样准随机采样 序列化并行计算局部禁用梯度计算数学运算常量逐点运算归约操作比较运算频谱操作其他操作BLAS 和 LAPACK 运算遍历操作遍历操作遍历操作遍历操作遍历操作遍历操作遍历操作遍历…...
如何在mac上使用便利贴
可以在 App Store 下载便利贴应用实现在电脑上贴便条的效果。 以 「桌面便利贴」这款应用为例,创建的便利贴会像桌面上的文件一样展示在桌面上,随时可以查看。还可以修改便笺的颜色、透明度、字体、高亮等等。 我比较喜欢的功能是将便签固定在所有窗口的…...
Linux——Mysql索引和事务
目录 一,Mysql索引介绍 1,索引概述 1,索引的优点 2,索引的缺点 2,索引作用 3,索引分类 普通索引 唯一索引 主键索引 组合索引 全文索引 4,查看索引 5,删除索引 6&…...
vim 查看复杂的宏扩展
在一些复杂项目中,使用宏可以简化代码。但是对于刚接触项目的人来说,分析层层嵌套的宏,是件头疼的事情。 使用 vim 的多窗口功能,可以为此提供一些帮助。 如下图,分析4层嵌套的宏,DEFINE_I440FX_MACHINE -…...
【计算机视觉】OpenCV项目实战:基于OpenCV的图像分割技术深度解析与实践指南
基于OpenCV的图像分割技术深度解析与实践指南 项目概述与技术背景项目核心特点传统分割算法分类 环境配置与项目结构系统要求安装步骤项目结构解析 核心算法实现解析1. 阈值分割(Otsu方法)2. Canny边缘检测3. 分水岭算法 实战应用指南1. 基础分割流程2. …...
线性表-顺序表(Sequential List)
1 线性表 1.1 顺序表(Sequential List) 顺序表并不难理解,主要是知道顺序表是在内存中连续存储的一段数据,知道这个后,相应的算法也就非常简单了。 线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的…...
《用MATLAB玩转游戏开发:从零开始打造你的数字乐园》基础篇(2D图形交互)-俄罗斯方块:用旋转矩阵打造经典
《用MATLAB玩转游戏开发:从零开始打造你的数字乐园》基础篇(2D图形交互)-🎮 俄罗斯方块:用旋转矩阵打造经典 🧊 大家好!今天我将带大家用MATLAB实现经典的俄罗斯方块游戏。我们将从数学原理出发…...
通过user-agent来源判断阻止爬虫访问网站,并防止生成[ error ] NULL日志
一、TP5.0通过行为(Behavior)拦截爬虫并避免生成 [ error ] NULL 错误日志 1. 创建行为类(拦截爬虫) 在 application/common/behavior 目录下新建BlockBot.php ,用于识别并拦截爬虫请求: <?php name…...