当前位置: 首页 > news >正文

TCP报文格式与核心机制

TCP与UDP都是传输层的重要协议,TCP的特性包括有连接、可靠传输、面向字节流、全双工。

TCP的报文格式如下:

一、报文格式 

1.源端口号、目的端口号 

源端口和目的端口是五元组中重要的两个性质,源端口即数据是从哪里来的,目的端口即数据要发送到哪去。

一般情况下,端口号都是两个字节,即16个bit位,可以表示0-65535的数字,通常使用1024-65535之间的数字作为端口号。

在编写代码时,服务器的端口号通常是程序员自定义的,但客户端的端口号是由操作系统自己生成的。

2.首部长度

首部长度即TCP报头(除去载荷)部分的长度。以四个字节为一个单位,所以TCP报头的最大为60个字节。

3.保留位

由于UDP报文的长度为固定的64KB,于是就导致当数据量过大时,UDP就装不下了。TCP在此基础上吸取教训,设计了保留位。即这些空间现在不用,但先保留这么大的空间,以防后面需要使用。

4.标志位

TCP标志位是TCP报头最核心的部分,即URG、ACK、PSH、RST、SYN、FIN,与TCP的可靠传输有着密切联系。在后面的TCP核心机制中会详细介绍。

5.选项

选项是可有可无的,但选项的大小必须为4的倍数。正是由于选项的存在,就导致TCP报头的大小是不确定的,也就使得首部长度的存在变得合理。由于TCP报头最大为60字节,并且报头的固定空间为20字节,于是选项最大为40字节。

6.校验和

与UDP一样,是检验数据在发送的过程中是否变化。

但与UDP不同的是,UDP对发生变化的数据报是直接丢弃的,但TCP会出触发重新发送的操作,在后面的核心机制中会详细介绍。

二、核心机制

1.确认应答

1)当A给B发消息时,由于A并不知道B是否已经收到了消息,于是就需要B给A发送一个确认收到的消息,这样A就知道B收到了他发的短信。TCP也是一样,当两台设备进行通信时,发送方发送数据后,接收方在接收到数据后就需要给发送方发送一个应答报文(acknowledge,ack),这里的ack就是TCP报头中的标志位,当ack为1时,就代表返回的报文是应答报文。图示如下:

2)在进行网络通信时,有时会出现后发先至的情况(由于网络数据会经过路由器和交换机等网络设备,但数据的传输并不一定会经过同一条道路,对于不同的道路,有的设备拥堵,有的设备畅通,就导致数据在路上消耗的时间是不一样的,也就导致到达接收方的顺序是不一样的),即A给B发了若干条消息,虽然B给A回应的消息是按照A的消息顺序进行回应的,但由于存在后发先至的情况,B的回应消息到达A时并不是按照B发送的顺序到达的,如下图所示:

由图可知,B的回应消息到达A时顺序发生了改变,就导致A无法将发送消息与回应消息进行对应。

对于这种情况,TCP给出了解决方法,即给传输的数据进行编号。

对于编号,就涉及到TCP报头中的序号和确认序号。确认序号只存在于应答报文中,当ack为1时,就说明该报文为应答报文。并且只对TCP在和部分进行编号,TCP报头不参与编号。

由于TCP是面向字节流的,于是编号是对每个字节进行编号的,并且编号是连续递增的。TCP报头中的序号就是这段载荷的第一个字节的编号,确认序号就是对回应的那条消息的载荷的最后一个字节编号加1。对于A消息,B是A的应答报文,如果A的载荷的第一个字节编号为1,最后一个字节编号为1000,那么A报文的序号就是1,B报文的确认序号就是1001。那么下一次A再发送数据时,报文序号就会从1001开始继续编号。

引入编号后,接收方就可以根据报文序号进行排序。在内存或操作系统的内核中,会存在接收缓冲区,接收的数据会先进入接收缓冲区,将数据编号从小到大排序完成后,就可以调用方法读取数据,这时读取的数据就是有序的了。

2.超时重传

当A与B进行通信时,A给B发送消息可能会出现丢包情况(当路由器/交换机工作繁忙时,当路由器/交换机的转发数据超过了其能承受的上限,就会将最新进来的数据丢弃),即A给B发送的消息B没收到,或者B发给A的确认应答(以下统称ack)A没收到。这种情况下就会触发超时重传操作。

当发送方发送数据后,在一定的时间阈值T内没有收到接收方发送的ack,就会延长T到T1并进行重传,当T1时间后还没有收到ack就会再一次延长T1到T2进行重传。由于丢包的概率是很小的,当超时次数达到一定程度/超时时间达到一定程度,就不会继续重传了,而是会放弃这次传输,并且此时的网络已经存在严重故障了。

有上面知道,引发超时重传的原因可能有两个,即A给B发送的消息B没收到,或者B发给A的ack A没收到。如果是前面一种情况,就相当于B只收到了一次数据,这时合理的;但如果是后面一种情况,B就会收到两个一样的数据,并且这两份数据载荷的序号是一样的,这就不合理了。于是就有了下面的操作。

当B接收到数据后,数据会先存放在接收缓冲区,TCP会在接收缓冲区内部进行去重操作。若接收的数据在缓冲区中已经存在了,就会将这个数据丢弃,若不存在就会直接放进缓冲区中。

超时重传和确认应答是TCP能够进行可靠传输所依赖的两个最核心的机制。

3.连接管理

连接管理分为确认连接和断开连接。

1)建立连接

所谓连接,是一种抽象的概念。建立连接的过程就是通信双方保存对端信息(IP、端口号等)的过程。TCP建立连接是通过三次握手完成的。

当客户端想要与服务器进行通信时,就会给服务器发送同步报文段(sync,即在TCP报头中的标志位syn为1时,下面简称syn),当服务器接收到syn后,就会先给客户端发送ack,表示已经收到了客户端的信息,然后再发送syn给客户端,当客户端收到服务器的syn后,就会给服务器发送ack,经过这四次发送,就可以让服务器与客户端建立连接了。图示如下:

但我们说的是三次握手,上面进行了四次发送,是否可以将其中的两次进行合并呢?答案是可以的。当服务器接收到客户端的syn后,由于syn与ack都是由操作系统内核进行返回,就会将后面的ack与syn进行合并发送,即在报头中的ack与syn同时为1。这样可以提高传输的效率。图示如下:

CLOSED:假象的,不存在的状态,表示设备还没有连接的状态;

LISTEN:表示服务器可以接收到客户端发来的syn;

SYN_SEND:发送了syn,正常情况下这种状态留存时间很短,是看不到的;

SYN_RCVD:接收到syn,正常情况下这种状态留存时间很短,是看不到的;

ESTABLISHED:客户端与服务器连接建立完成,可以发送业务数据。

三次握手的作用

①确保通信线路是畅通的。

②检验双方的接收、发送能力是否正常。

在客户端向服务器发送了syn后,服务器返回了ack和syn,表示客户端的发送能力与服务器的接收能力是正常的;

客户端接收到服务器的syn与ack后返回了ack,就说明客户端的接收能力与服务器的发送能力是正常的。

③协商关键信息。

通常协商的是报头序号是从几开始。一般情况下TCP报头序号不是从0开始的。

在客户端与服务器第一次建立连接完成后开始发送若干组数据,若其中有一组数据传输较慢,在第一次连接断开后还没有发送到,并且此时客户端与服务器建立了第二次连接,在第二次连接中也发送了若干组数据,在发送过程中,第一次连接的那组数据才被服务器接收到。这时,服务器对这组数据的处理方式应该是丢弃,但服务器是如何知道这组数据是第一次发送的呢?

这时在客户端与服务器建立连接的过程中,就可以协商报头序号从几开始。若第一次从10000开始,那么第二次就从60000开始。由于在传输过程中报头序号是递增的,于是当发现接收到的数据比这次连接协商的报头序号小时,就说明这个数据来晚了,需要被丢弃。

注意:为什么是三次握手,不是两次、四次呢?

若是两次,由作用②可知,当服务器给客户端您发送syn与ack后,就代表服务器的发送能力与客户端的接受能力是正常的,但此时服务器不知道客户端的接受能力是正常的,于是就需要客户端再向服务器发送syn,就可以让服务器知道客户端的接受能力没有问题。

若是四次,就是将服务器发给客户端的syn与ack分开发送,但会降低传输效率。

2)断开连接

断开连接的过程就是各自将对端的信息删除。TCP断开连接是通过四次挥手完成的。

在建立连接中,通常是客户端发起建立连接的请求,但是在断开连接中,客户端与服务器都有可能发起断开连接的请求。

当A与B想要断开连接时,A就会先给B发送结束报文(TCP报头标志位FIN为1,下面简称FIN),B收到FIN后,就会先给A发送ACK,再发送FIN,当A收到B发送的FIN后,就会给B发送ACK,经过这四次通讯后,A与B就断开了连接。图示如下:

与三次握手类似的,B发给A的ACK与FIN能否合并呢?

答案是有可能能,也有可能不能。

能是因为TCP的另一个核心机制:延时应答,后面会介绍;

不能是因为ACK与FIN发送的时机是不一样的。ACK通常是由操作系统内核返回,只要B收到了A发过来的FIN,就会马上回复一个ACK。但FIN的发送是则是代码中调用close方法或进程结束,这两个时间的触发时机通常不是一起的。

核心状态:

CLOSE_WAIT:当A给B发送FIN后,由于B的代码要执行到close方法还有一段时间,这也就会有一个时间段。但通常情况下,这个时间段应该要非常短,即代码感知到A发送了FIN后就应该要尽快执行close方法。若在开发中看到CLOSE_WAIT状态存在时间过长或存在大量CLOSE_WAIT状态,就说明代码中可能存在BUG。

TIME_WAIT:在A与B进行四次挥手的过程中,也有可能会出现丢包情况,由以下几种丢包情况,

①A发给B的FIN丢包了,即B没有收到FIN,也就不会给A发送ACK,那么A在一定时间内没有收到ACK就会触发超时重传操作,即重新发送FIN;

②B发给A的ACK丢包了,即A没有收到ACK,那么A就会默认第一个FIN丢包了,一定时间之后也会触发超时重传操作,即重新发送FIN;

③B发给A的FIN丢包了,即A没有收到FIN,那么A也就不会给B发送ACK,当B在一定时间内没有收到ACK,就会认为FIN丢包了,也会触发超时重传操作,即重新发送FIN;

④A发给B的ACK丢包了,此时A已经将B的信息删除了,那么B没有收到ACK后也会认为FIN丢包了,那么此时如果B再重新发送FIN给A后,A也就无法收到FIN,导致B一直收不到ACK。对于这种情况,就需要引入TIME_WAIT,即当A收到B发的FIN后,不会马上把B的信息删除掉,而是会等待一段时间,即 2 * MSL(网络上任何两个结点传输过程中消耗的最大时间),通常是分钟级别的。如果在这段时间内A又收到了B发送的FIN,就会重新发送ACK。当等待这么长时间之后,A才会将B的删除掉。但是B由于没有收到A发过来的ACK,依然会保存A的信息,但A与B是无法进行通信的了。

4.滑动窗口

算法中的滑动窗口就是从这里演变出来的。

由于TCP是基于可靠性传输的,那么就会损失一部分传输效率。引入滑动窗口就是为了降低这部分损失。但其效率一眼比不上UDP。

当A给B发送数据时,如果是按照发一个数据包等一个ACK的模式,就会使得等待的时间过长(图左),从而导致效率低下。那么就可以一次发若干组数据,等到接收到第一组数据的ACK后再发送一组数据,接收到第二组数据的ACK后再发送一组数据(图右),这样就可以将等待多组ACK的时间压缩成等待一组ACK的时间。图示如下:

在A与B传输过程中,当A接收到1001后,就会将5001-6000的数据发送出去,就相当于窗口向右移动了一位,当A接收到2001后,就会将6001-7000的数据发送出去,图示如下:

当B先给A发送了1001,后发送了2001,但2001比1001先到达A,那么A就会认为1-1000与1001-2000的数据都已经被B接收到了,于是就会将窗口向右移动两位。

但是在发送过程中,也有可能会出现丢包情况,这里的丢包分为下面两种情况:

①B给A发送的ACK丢包了,这是没有问题的。确认序号的含义是小于确认序号的数据都已经收到了。若先发送的ACK丢包了,只要能收到后发送的ACK,那么就代表之前的数据都已经收到了;

②A给B发送的若干组数据中有一组数据丢失了。当1001-2000这一组数据丢包后,B就会不断的给A发送1001,而不会因为接收到了后面的数据而发送后面的ACK。当A发现B总是在返回同一个ACK时,就会将1001-2000进行重新发送,当B接收到这组数据后,就会直接返回5001的ACK,就代表前面的数据都已经收到了,A可以从5001开始重新发送数据了。这就是在滑动窗口中特有的重传操作:快速重传。图示如下:

当发生丢包后,是不会影响B读取A发送数据的顺序的,即A是按什么顺序发送的,B就是按什么顺序读取的。因为在接收缓冲区中给1001-2000的数据预留了一定的空间,当B接收到这组数据后,就会放在预留的空间上。图示如下:

注意:

超时重传与快速重传是不矛盾的。

超时重传是当数据量不大时的操作,没有必要构成滑动窗口;

快速重传是当数据量很大时的操作,需要构成滑动窗口。

5.流量控制

当发送方发送数据时,接收方就会将数据暂时存在接收缓冲区中,然后在接收缓冲区中进行读取数据。那么接收缓冲区就相当于蓄水池,发送方发送数据就相当于进水,接收方读取数据就相当于放水。当进水速度过快而出水速度过慢,就会出现水越来越多的情况,最后蓄水池装不下导致水溢出。这种情况就相当于发送方发送数据过快而接收方读取数据过慢,导致接收缓冲区被数据占满,那么新的数据就会出现丢包情况,这时就需要对发送方发送数据的速度进行控制。

在TCP报头中,窗口大小这个属性就代表了接收缓冲区的剩余大小是多少。在选项中,也有窗口拓展因子这一特殊属性。

当A给B发送数据时,B在给A返回ACK的同时也会返回接收缓冲区剩余的大小。这个剩余大小就会填入到窗口大小中。当A接收到B返回的窗口大小后,就会将窗口大小与窗口拓展因子进行计算,即窗口大小<<窗口拓展因子,得出来的数值就是滑动窗口中的窗口大小,A之后就会按照这样大小的窗口进行数据发送。当B返回给A的窗口大小为0时,就代表接收缓冲区已经装满了,再进行发送就会丢包了。于是A就不再发送业务数据,但会间断地发送窗口探测的数据包,目的只是为了让B发送ACK以及当前接收缓冲区的剩余空间。当接收缓冲区剩余空间不为0时,A就会继续发送业务数据。

6.拥塞控制

流量控制是依据接收方的接受能力来控制发送方的发送速度,拥塞控制是根据通信链路的转发能力来控制发送方的发送速度。

当两台设备进行通信时,数据会经过若干个路由器或交换机,这些机器的转发能力是有上限的,当发送方发送速度过快时,就会出现丢包情况。

当我们想知道一个通信链路的转发上限时,就可以采取做实验的方式。

我们现让A以速度v来发送数据,若此时B没有出现丢包情况,就增大v,当B出现了丢包情况时,就马上减小v(比一开始的速度大),然后继续增大v,经过几次后,就基本可以确定这条通信链路的转发上限了。图示如下:

一开始是慢启动,即发送方以较小的速度发送数据,然后发送速度呈指数增长, 当速度达到初始的阈值(ssthress)时,就让速度线性增长,当B出现丢包后,接下来有两种做法:

新:将发送速度减小到新的阈值,然后再让其线性增长,循环往复;

旧:将发送速度减小到一开始的速度,在让其呈指数增长,但这次增长的没有第一次的快,循环往复;

经过多轮试验后,就可以找到适合的窗口大小了。

当我们确定通信链路的转发上限后,与流量控制的窗口大小进行比较,取较小值作为A的窗口大小。

7.延时应答

在一般情况下,当接收方收到数据后,就会马上返回一个ACK,但是通过延时应答可能会提高效率。

若不使用延时应答,那么当发送方发送数据后,就会将数据存放在接收缓冲区中,如果这时接收方马上就返回一个ACK,也就会返回当前情况下的窗口大小(接收缓冲区的剩余容量)。如果接收方延缓ACK的发送,那么在延缓的这段时间内,接收方就会读取接收缓冲区中的数据,使得接收缓冲区中的数据减少,那么其剩余容量就会增大,那么等到接收方再返回ACK时,就会返回一个较大的窗口大小,那么当发送方收到ACK后,就会使用一个较大的窗口发送数据,这时就会提高通信的效率。

但是在延缓情况下,可能发送方依然在发送数据,就会导致接收缓冲区中的剩余容量进一步减少,从而会返回一个更小的窗口大小,导致发送方使用更小的窗口发送数据。在这种情况下,就会降低通信的效率。

于是引入延时应答机制,并不会一定地提高通信效率,而是有可能会提高通信效率。

延时应答也会受到两个因素的限制,即数量限制与时间限制。

数量限制:每隔N个包应答一次;

时间限制:超过最大延迟时间就应答一次。

在数据报较多时,就会使用第一种;当数据报较少时,就会使用第二种。

8.捎带应答

发送方在发送请求报文后,接收方接受到业务数据就会返回一个ACK,之后再返回一个响应报文。

由于响应报文只是在报头将ACK设为1、窗口大小设为接收缓冲区剩余容量、选择合适的确认序号等,与载荷无关,但响应报文只是在载荷中加入数据,于是可以将ACK与响应报文结合起来一起发送,这就是捎带应答,即在返回业务数据地同时将上次的ACK顺带发送过去。

引入捎带应答后,也可以提高TCP的传输效率。 

9.面向字节流

TCP的一个传输特性就是面向字节流。但这也存在一个问题,就是粘包问题。由于TCP在读取数据时是按照字节进行读取的,就不好区分每组数据之间的界限,就可能会将下一组数据读到这一组数据中。

当A给B发送数据时,连续发送aaa、bbb、ccc这三组数据,那么当B进行第一次读取时,就有可能会读到以下几种情况:aa、aaa、aaab等,在这几组数据中,只有aaa是正确的。那么应该如何防止这种情况发生呢?

1)可以定义好每组数据之间的分隔符,若规定组与组之间以 \n 进行分割,那么A传输过来的数据就是aaa\nbbb\nccc\n,当B在读取时,在读到第一个 \n 时,就代表第一组数据已经读取完成,接下来就是第二次读取;

2)在每组数据之前加上包的长度,若A发送给B的数据为aa、bbb、cccc,那么就将每一组的长度放在最前面从一并发送,即2aa3bbb4cccc,那么当B在进行读取时,就会先读到2,然后才会读两个a,这样第一次读取就已经结束。第二次读取时,就会先读到3,然会就会向后读3个b,到这里第二次读取就已经结束。

这两种情况在HTTP中也有所体现,在GET方法中,没有正文,就会以空行结束;在POST方法中,由于存在正文,就会在响应头中的属性Content-Length中标明正文的长度。

对于UDP而言,就不存在粘包问题。因为UDP是面向数据报进行传送的,每次读取就会按照一个数据报进行读取。

10.异常情况的处理

在TCP通信过程中,会出现以下几种异常情况:

1)某个进程崩溃了

在这种情况下,与进程主动退出没有本质区别,都会回收文件描述符表的每个资源,调用close方法,然后四次挥手断开连接。虽然进程已经没了,但是通信双方的信息依然保存着,并且四次挥手是在操作系统内核中完成的,那么即使进程崩溃,四次挥手依然能完成。

2)主机关机

通常情况下,主机关机与进程结束差不多,都会进行四次握手,但会出现四次握手还没有结束主机A就已经不工作了。在这种情况下,当B重新发送多次FIN后都没有收到ACK,就会认为此时网络出现严重故障,那么B就会将A的信息删除掉,即B主动释放连接。

3)主机掉电

主机掉电与主机关机不同,主机掉电是直接拔掉电源,对于没有备用电池的电脑,拔掉电池后会使主机直接不工作。

当接收方发生主机掉电:即发送方发送的任何数据都没有ACK,这时发送方就会发送复位报文(即重新建立连接,报头的标志位RST为1,下面简称RST),同样的,发送后也不会又ACK返回,这时发送方就会直接释放TCP连接;

当发送方发生主机掉电:即接收方不会接收到任何数据,这时接收方就会向发送方发送“心跳包”,即周期性的数据报,不携带载荷,只是为了触发ACK,但依然没有ACK返回,这时接收方就会发送RST,同样的也不会有ACK返回,此时接收方就会释放TCP连接。(TCP保活机制)

4)网线断开

接收方网线断开:与接收方主机掉电一样;

发送方网线断开:与发送方主机掉电一样。

三、剩余属性

在经过上面的介绍后,还剩下一个属性、两个标志位没有介绍。

1、紧急指针、URG

在正常情况下,TCP的读取顺序是按照接收顺序读取的,但紧急指针相当于“插队”,即先从紧急指针的需要进行读取,同时将URG标志位置为1.

2、PSH

催促标志位,当这一位为1时,接收方就会尽快将这个数据读取到应用程序中。

相关文章:

TCP报文格式与核心机制

TCP与UDP都是传输层的重要协议&#xff0c;TCP的特性包括有连接、可靠传输、面向字节流、全双工。 TCP的报文格式如下&#xff1a; 一、报文格式 1.源端口号、目的端口号 源端口和目的端口是五元组中重要的两个性质&#xff0c;源端口即数据是从哪里来的&#xff0c;目的端…...

【2024年华为OD机试】 (B卷,100分)- 金字塔,BOSS的收入(Java JS PythonC/C++)

一、问题描述 微商模式收入计算 题目描述 微商模式中&#xff0c;下级每赚 100 元就要上交 15 元。给定每个级别的收入&#xff0c;求出金字塔尖上的人的收入。 输入描述 第一行输入 N&#xff0c;表示有 N 个代理商上下级关系。接下来输入 N 行&#xff0c;每行三个数&am…...

缓存、数据库双写一致性解决方案

双写一致性问题的核心是确保数据库和缓存之间的数据同步&#xff0c;以避免缓存与数据库数据不同步的问题&#xff0c;尤其是在高并发和异步环境下。本文将探讨双写一致性面临的主要问题和解决方案&#xff0c;重点关注最终一致性。 本文讨论的是最终一致性问题 双写一致性面…...

开放银行数据保护与合规实践案例

总体原则 开放银行的数据处理基本原则指的是数据处理者在数据生命周期的各阶段进行各种数 据处理时均应遵循的根本准则&#xff0c;是指导监管机构制定规范、进行管理以及开放银行进 行具体数据处理行为的纲领。根据《民法典》《个人信息保护法》《数据安全法》 《网络安全法…...

51c自动驾驶~合集47

我自己的原文哦~ https://blog.51cto.com/whaosoft/13083194 #DreamDrive 性能爆拉30%&#xff01;英伟达&#xff1a;时空一致下的生成重建大一统新方案~ 从自车的驾驶轨迹中生成真实的视觉图像是实现自动驾驶模型可扩展训练的关键一步。基于重建的方法从log中生成3D场景…...

2024年AI与大数据技术趋势洞察:跨领域创新与社会变革

目录 引言 技术洞察 1. 大模型技术的创新与开源推动 2. AI Agent 智能体平台技术 3. 多模态技术的兴起:跨领域应用的新风口 4. 强化学习与推荐系统:智能化决策的底层驱动 5. 开源工具与平台的快速发展:赋能技术创新 6. 技术安全与伦理:AI技术的双刃剑 7. 跨领域技…...

【protobuf】二、proto3语法详解①

文章目录 前言Ⅰ. 字段规则Ⅱ. 消息类型的定义和使用1、定义2、使用1️⃣消息类型可作为字段类型使⽤2️⃣可导入其他 .proto 文件的消息并使用 -- import 3、创建通讯录 2.0 版本的 .proto 文件4、通讯录 2.0 版本的读写实现 -- 第一种验证方式5、decode选项 -- 第二种验证方式…...

React 中hooks之useLayoutEffect 用法总结以及与useEffect的区别

React useLayoutEffect 1. useLayoutEffect 基本概念 useLayoutEffect 是 React 的一个 Hook&#xff0c;它的函数签名与 useEffect 完全相同&#xff0c;但它会在所有的 DOM 变更之后同步调用 effect。它可以用来读取 DOM 布局并同步触发重渲染。 2. useLayoutEffect vs us…...

实战经验:使用 Python 的 PyPDF 进行 PDF 操作

文章目录 1. 为什么选择 PyPDF&#xff1f;2. 安装 PyPDF3. PDF 文件的合并与拆分3.1 合并 PDF 文件3.2 拆分 PDF 文件 4. 提取 PDF 文本5. 修改 PDF 元信息6. PDF 加密与解密6.1 加密 PDF6.2 解密 PDF 7. 页面旋转与裁剪7.1 旋转页面7.2 裁剪页面 8. 实战经验总结 PDF 是一种非…...

数据结构与算法之排序: LeetCode 15. 三数之和 (Ts版)

三数之和 https://leetcode.cn/problems/3sum/description/ 描述 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0请你返回所有和为 0 且不重复的三元…...

51c嵌入式~单片机~合集6

我自己的原文哦~ https://blog.51cto.com/whaosoft/13127816 一、STM32单片机的知识点总结 本文将以STM32F10x为例&#xff0c;对标准库开发进行概览。主要分为三块内容&#xff1a; STM32系统结构寄存器通过点灯案例&#xff0c;详解如何基于标准库构建STM32工程 STM3…...

SQL Server Management Studio 表内数据查询与删除指令

查询指令 //select * from 表名称 where 列名称 数据名称 select * from Card_Info where num CC3D4D删除指令&#xff0c;删除数据库有风险&#xff0c;操作不可逆&#xff0c;建议删除前备份&#xff0c;以免删错。 //Delete * from 表名称 where 列名称 数据名称 Delete f…...

Timesheet.js - 轻松打造炫酷时间表

Timesheet.js - 轻松打造炫酷时间表 前言 在现代网页设计中&#xff0c;时间表是一个常见的元素&#xff0c;用于展示项目进度、历史事件、个人经历等信息。 然而&#xff0c;创建一个既美观又功能强大的时间表并非易事。 幸运的是&#xff0c;Timesheet.js 这款神奇的 Java…...

产品经理面试题总结2025【其一】

一、产品理解与定位 1、你如何理解产品经理这个角色&#xff1f; 作为一名互联网产品经理&#xff0c;我理解这个角色的核心在于成为产品愿景的制定者和执行的推动者。具体来说&#xff0c;产品经理是连接市场、用户和技术团队之间的桥梁&#xff0c;负责理解市场需求、用户痛…...

第16章:Python TDD实现多币种货币运算

写在前面 这本书是我们老板推荐过的&#xff0c;我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后&#xff0c;我突然思考&#xff0c;对于测试开发工程师来说&#xff0c;什么才更有价值呢&#xff1f;如何让 AI 工具更好地辅助自己写代码&#xff0c;或许…...

【Web】2025-SUCTF个人wp

目录 SU_blog SU_photogallery SU_POP SU_blog 先是注册功能覆盖admin账号 以admin身份登录&#xff0c;拿到读文件的权限 ./article?filearticles/..././..././..././..././..././..././etc/passwd ./article?filearticles/..././..././..././..././..././..././proc/1…...

C++实现矩阵Matrix类 实现基本运算

本系列文章致力于实现“手搓有限元&#xff0c;干翻Ansys的目标”&#xff0c;基本框架为前端显示使用QT实现交互&#xff0c;后端计算采用Visual Studio C。 目录 Matrix类 1、public function 1.1、构造函数与析构函数 1.2、获取矩阵数值 1.3、设置矩阵 1.4、矩阵转置…...

【GORM】初探gorm模型,字段标签与go案例

GORM是什么&#xff1f; GORM 是一个Go 语言 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;它让我们可以使用结构体来操作数据库&#xff0c;而无需编写SQL 语句 GORM 模型与字段标签详解 在 GORM 中&#xff0c;模型是数据库表的抽象表示&#xff0c;字段标签&am…...

html全局遮罩,通过websocket来实现实时发布公告

1.index.html代码示例 <div id"websocket" style"display:none;position: absolute;color:red;background-color: black;width: 100%;height: 100%;z-index: 100; opacity: 0.9; padding-top: 30%;padding-left: 30%; padding-border:1px; "onclick&q…...

基于VSCode+CMake+debootstrap搭建Ubuntu交叉编译开发环境

基于VSCodeCMakedebootstrap搭建Ubuntu交叉编译开发环境 1 基于debootstrap搭建目标系统环境1.1 安装必要软件包1.2 创建sysroot目录1.3 运行debootstrap1.4 挂载必要的虚拟文件系统1.5 复制 QEMU 静态二进制文件1.6 进入目标系统1.7 使用目标系统&#xff08;以安装zlog为例&a…...

C#中System.Text.Json:从入门到精通的实用指南

一、引言 在当今数字化时代&#xff0c;数据的高效交换与处理成为软件开发的核心环节。JSON&#xff08;JavaScript Object Notation&#xff09;凭借其简洁、轻量且易于读写的特性&#xff0c;已然成为数据交换领域的中流砥柱。无论是前后端数据交互&#xff0c;还是配置文件…...

【深度学习】Huber Loss详解

文章目录 1. Huber Loss 原理详解2. Pytorch 代码详解3.与 MSELoss、MAELoss 区别及各自优缺点3.1 MSELoss 均方误差损失3.2 MAELoss 平均绝对误差损失3.3 Huber Loss 4. 总结4.1 优化平滑4.2 梯度较好4.3 为什么说 MSE 是平滑的 1. Huber Loss 原理详解 Huber Loss 是一种结合…...

Maven下载配置

目录 Win下载配置maven的环境变量 Mac下载安装配置环境变量 MavenSetting.xml文件配置 Win 下载 https://maven.apache.org/ 在主页面点击Download 点击archives 最好不要下载使用新版本&#xff0c;我使用的是maven-3.6.3&#xff0c;我们点击页面下方的archives&#xff0…...

JS基础(5):运算符和语句

一.运算符 1.赋值运算符 加减乘除都是一样的&#xff0c;&#xff0c;-&#xff0c;*&#xff0c;/ 2.一元运算符&#xff1a;经常用来计数 自增&#xff1a; 每次只能加一 自减&#xff1a;-- 前置自增 后置自增 结…...

游戏引擎学习第81天

仓库:https://gitee.com/mrxiao_com/2d_game_2 或许我们应该尝试在地面上添加一些绘图 在这段时间的工作中&#xff0c;讨论了如何改进地面渲染的问题。虽然之前并没有专注于渲染部分&#xff0c;因为当时主要的工作重心不在这里&#xff0c;但在实现过程中&#xff0c;发现地…...

网络安全 | 什么是正向代理和反向代理?

关注&#xff1a;CodingTechWork 引言 在现代网络架构中&#xff0c;代理服务器扮演着重要的角色。它们在客户端和服务器之间充当中介&#xff0c;帮助管理、保护和优化数据流。根据代理的工作方向和用途&#xff0c;代理服务器可分为正向代理和反向代理。本文将深入探讨这两种…...

前缀和——模板 二维前缀和

一.题目描述 【模板】二维前缀和_牛客题霸_牛客网 二.题目解析 这道题和上一道题有点异曲同工之妙。输入一个m行n列的矩阵&#xff0c;然后进行q次操作&#xff0c;每次操作输入4个数&#xff0c;作为两个点的坐标&#xff0c;计算这两个点为对角线的矩阵的和。 三.算法原理 …...

oracle使用case when报错ORA-12704字符集不匹配原因分析及解决方法

问题概述 使用oracle的case when函数时&#xff0c;报错提示ORA-12704字符集不匹配&#xff0c;如下图&#xff0c;接下来分析报错原因并提出解决方法。 样例演示 现在有一个TESTTABLE表&#xff0c;本表包含的字段如下图所示&#xff0c;COL01字段是NVARCHAR2类型&#xff0…...

高等数学学习笔记 ☞ 定积分与积分公式

1. 定积分的基本概念 1.1 定积分的定义 1. 定义&#xff1a;设函数在闭区间上有界。在闭区间上任意插入若干个分点&#xff0c;即&#xff0c; 此时每个小区间的长度记作(不一定是等分的)。然后在每个小区间上任意取&#xff0c;对应的函数值为。 为保证每段的值(即矩形面积)无…...

MLMs之Agent:Phidata的简介、安装和使用方法、案例应用之详细攻略

MLMs之Agent&#xff1a;Phidata的简介、安装和使用方法、案例应用之详细攻略 目录 Phidata简介 Phidata安装和使用方法 1、安装 2、使用方法 (1)、认证 (2)、创建 Agent (3)、运行 Agent (4)、Agent Playground Phidata 案例应用 1、多工具 Agent 2、多模态 Agent …...

如何在不暴露MinIO地址的情况下,用Spring Boot与KKFileView实现文件预览

在现代Web应用中&#xff0c;文件预览是一项常见且重要的功能。它允许用户在不上传或下载文件的情况下&#xff0c;直接在浏览器中查看文件内容。然而&#xff0c;直接将文件存储服务&#xff08;如MinIO&#xff09;暴露给前端可能会带来安全风险。本文将介绍如何在不暴露MinI…...

ESP8266固件烧录

一、烧录原理 1、引脚布局 2、引脚定义 3、尺寸封装 4、环境要求 5、接线方式 ESP8266系列模块集成了高速GPI0和外围接口&#xff0c;这可能会导致严重的开关噪声。如果某些应用需要高功率和EMI特性&#xff0c;建议在数字I/0线上串联10到100欧姆。这可以在切换电源时抑制过冲…...

Python 模拟真人鼠标轨迹算法 - 防止游戏检测

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…...

三天急速通关Java基础知识:Day1 基本语法

三天急速通关JAVA基础知识&#xff1a;Day1 基本语法 0 文章说明1 关键字 Keywords2 注释 Comments2.1 单行注释2.2 多行注释2.3 文档注释 3 数据类型 Data Types3.1 基本数据类型3.2 引用数据类型 4 变量与常量 Variables and Constant5 运算符 Operators6 字符串 String7 输入…...

免费使用 Adobe 和 JetBrains 软件的秘密

今天想和大家聊聊如何利用 Edu 教育邮箱免费使用 Photoshop、Illustrator 等 Adobe 系列软件&#xff0c;以及 JetBrains 开发工具。 首先&#xff0c;Adobe 的软件是设计师的必备工具。无论是处理图像的 Photoshop&#xff0c;还是进行矢量设计的 Illustrator&#xff0c;它们…...

Pytorch 自学笔记(三):利用自定义文本数据集构建Dataset和DataLoader

Pytorch 自学笔记&#xff08;三&#xff09; 1. Dataset与DataLoader1.1 torch.utils.data.Dataset1.2 torch.utils.data.DataLoader Pytorch 自学笔记系列的第三篇。针对Pytorch的Dataset和DataLoader进行简单的介绍&#xff0c;同时&#xff0c;介绍如何使用自定义文本数据集…...

gradle项目的创建和基本结构简介

文章目录 创建gradle项目&#xff08;命令行&#xff09;创建gradle项目&#xff08;IDEA&#xff09;项目基本结构和功能Gradle 构建流程测试类体验 创建gradle项目&#xff08;命令行&#xff09; yangMacdeMac-mini gradleStudy % gradle init Starting a Gradle Daemon (s…...

wow-agent---Day3 Zigent 智能代理开发框架

这个框架是课程讲解的&#xff0c;但资料比较少&#xff0c;觉得框架比较小众&#xff0c;所以这里只分析代码&#xff0c;打算把更多的精力放在metagpt的学习上&#xff0c;毕竟还是要学教为主流的框架&#xff0c;这对后续维护升级都有帮助&#xff0c;当然感兴趣作为研究&am…...

python 入门

1. Python 概述 1.1 简介 python 是一种面向对象的解释型编程语言&#xff0c;由吉多范罗苏姆开发&#xff1b; 1991 年&#xff0c;公开发行版发布&#xff1b; 因其可以将其他语言制作的模块轻松联接在一起&#xff0c;又被称作胶水语言&#xff1b; 1.2 优点 简单易学&…...

sentinel微服务保护

学习链接 SpringCloudRabbitMQDockerRedis搜索分布式 文章目录 学习链接1.初识Sentinel1.1.雪崩问题及解决方案1.1.1.雪崩问题1.1.2.超时处理1.1.3.仓壁模式1.1.4.断路器1.1.5.限流1.1.6.总结 1.2.服务保护技术对比1.3.Sentinel介绍和安装1.3.1.初识Sentinel官网地址github地址…...

接口测试Day10-封装IHRM登录

-登录接口 普通方式实现 登录接口对象层 思路&#xff1a; 动态变化的&#xff0c;写入参数固定不变&#xff0c;直接写到方法实现内响应结果&#xff0c;通过返回值 return 分析&#xff1a; 封装实现&#xff1a; 登录接口测试用例层 封装断言方法 1、创建 文件 assert_uti…...

什么是IP地址、子网掩码、网关、DNS

简单解释 IP地址在网络中用于标识一个节点(或者网络设备的接口) IP地址用于IP报文在网络中的寻址 一个IPv4地址有32 bit。 IPv4地址通常采用“点分十进制”表示。 IPv4地址范围:0.0.0.0~255.255.255.255 网络部分:用来标识一个网络&#xff0c;代表IP地址所属网络。 主机部分:…...

python编程-OpenCV(图像读写-图像处理-图像滤波-角点检测-边缘检测)角点检测

角点检测&#xff08;Corner Detection&#xff09;是计算机视觉和图像处理中重要的步骤&#xff0c;主要用于提取图像中的关键特征&#xff0c;以便进行后续的任务&#xff0c;比如图像匹配、物体识别、运动跟踪等。下面介绍几种常用的角点检测方法及其应用。 1. Harris角点检…...

软路由系统iStoreOS 一键安装 docker compose

一键安装命令 大家好&#xff01;今天我来分享一个快速安装 docker-compose 的方法。以下是我常用的命令&#xff0c;当前版本是 V2.32.4。如果你需要最新版本&#xff0c;可以查看获取docker compose最新版本号 部分&#xff0c;获取最新版本号后替换命令中的版本号即可。 w…...

Invicti-Professional-V25.1

01 更新介绍 此更新包括对内部代理的更改。内部扫描代理的当前版本为 25.1.0。内部身份验证验证程序代理的当前版本为 25.1.0。#新功能现在&#xff0c;单击扫描摘要屏幕中的预设扫描图标会将您重定向到具有过滤视图的 “最近扫描” 页面&#xff0c;从而改进导航和对相关扫描…...

【QT】: 初识 QWidget 控件 | QWidget 核心属性(API) | qrc 文件

&#x1f525; 目录 1. 控件概述 控件体系的发展阶段 2. QWidget 核心属性 2.1 核心属性概览2.2 用件可用&#xff08;Enabled&#xff09; 2.3 坐标系&#xff08;Geometry&#xff09; **实例 1: 控制按钮的位置**实例 2: 表白 程序 2.4 窗口标题&#xff08;windowTiltle&a…...

Spring WebFlux

文章目录 一、概述1、Spring体系定位2、Spring MVC和WebFlux差异 二、入门1、依赖2、ReactorHttpHandlerAdapter&#xff08;main启动&#xff09;3、DispatcherHandler&#xff08;SpringWebFlux启动&#xff09;4、WebFilter 三、DispatcherHandler理解1、handle 前置知识&am…...

【AI | pytorch】torch.polar的使用

一、torch.polar的使用 torch.polar 是 PyTorch 中用来生成复数张量的一个函数&#xff0c;但它与数学中的复数表达式 ( z re^{i\theta} ) 是等价的。 具体来说&#xff0c;torch.polar(abs, angle) 接受两个实数张量参数&#xff1a; abs&#xff1a;表示复数的模长&#…...

AWTK fscript 中的 输入/出流 扩展函数

fscript 是 AWTK 内置的脚本引擎&#xff0c;开发者可以在 UI XML 文件中直接嵌入 fscript 脚本&#xff0c;提高开发效率。本文介绍一下 fscript 中的 iostream 扩展函数 1.iostream_get_istream 获取输入流对象。 原型 iostream_get_istream(iostream) > object示例 va…...

【多线程】线程池

一、什么是线程池 线程池&#xff08;Thread Pool&#xff09;是一种多线程并发执行的设计模式&#xff0c;它通过维护一个线程集合来执行多个任务&#xff0c;避免频繁地创建和销毁线程&#xff0c;提高系统性能和响应速度。 就好比如你经营了一家餐饮店&#xff0c;你名下有…...