Linux学习记录——삼십유 传输层TCP协议(1)

文章目录

  • 1、TCP协议报文
    • 1、报头和有效载荷的分离
    • 2、TCP可靠性
    • 3、序号和确认序号
    • 4、16位窗口大小
    • 5、6个标志位和紧急指针
  • 2、TCP可靠性
    • 1、应答机制
    • 2、超时重传机制
    • 3、连接管理机制
      • 握手
      • 挥手
  • 3、流量控制


1、TCP协议报文

UDP属于TCP/IP协议族。
在这里插入图片描述

1、报头和有效载荷的分离

从头到选项上边这部分,总共是20个字节,5行,每行都是4个字节。源和目的端口号和UDP一样。数据就是TCP协议上层封装的信息,比如应用HTTP的响应,数据就是有效载荷。选项长度不定,选项里有一些保活用的东西,保证服务器客户端之间的链接不会一直没有信息来往。

选项可有可没有。读取前20个字节就是报头,如果没有选项,就和UDP一样的做法,如果有选项,就需要确定报头+选项的长度。4位首部长度占4个比特位,可选择的就是0000到1111,也就是最大为15,首部计算的基本单位是4字节,也就是最大为60,最小为0,这个数字表示的报头+选项的长度总共最大为60,报头占据20个字节,选项则最多占据40个字节。如果是标准报头,选项为0,报头为20,那么4位首部长度应当表示20个字节,也就是5 * 4,4是基本单位,那么它就表示为0101。

对于TCP协议,前20个字节必然是报头,提取后,用首部长度字段 * 4 - 20,等于0就直接拿有效载荷,如果不等于0,减20得到的数就是选项的字节数,那就继续读取选项,读完后剩下的就是有效载荷。

至于选项,首部长度是如何实现这种判断的,有很多种办法,其中一种就是柔性数组。柔性数组可以定义变长结构体,结构体中前面的这些部分都写好后,最后带一个柔性数组,当需要多少选项时,就多malloc多少,然后加上20个字节,填充进首部长度,这样就实现了报头 + 选项的结构体。

通过上图会发现,TCP中没有能够计算有效载荷长度的数,这是因为TCP面向字节流,在收到信息时,就已经知道总体的字节数了,所以有效载荷自然也就能知道了。

2、TCP可靠性

TCP可靠。不可靠的行为有少/大量丢包、乱序、重复、校验失败、发送太快/慢、网络出问题,这些问题的原因是通信双方距离变长。

可靠性的核心就是应答机制,无论是请求还是应答方,双方在进行交互时,发送的都是TCP报头 + 有效载荷。应答机制也对应丢包问题的解决。 丢包首先就要能够知道包已经被丢弃。

客户端C,服务端S,C对S发送报文,S必须发送应答,但应答也是报文,也有可能丢掉。发送并发送确认信息(应答)是必要的,C如果收到应答,那么就说明S一定收到了报文;如果收不到,C就认为,报文丢了。无论收到还是收不到,相互发送有时间成本,所以在一定的时间内,如果C没收到报文,就认为报文丢了。

通过以上得知,可靠性是通过收到应答保证的。C如果收到应答,就能够保证C发送给S的报文是一定被收到的,但不能保证S发出来的应答是否已经丢弃。这也就是局部可靠性。我们无法保证任何报文都可靠送达,只能保证局部可靠。

TCP中client和server的低位是对等的,S也是局部可靠性,S发送给C消息,C要给应答,同样地,S只能保证成功发送给C,但C的应答并不保证。

所以客户端保证发送到服务端的报文可靠,服务端保证发送到客户端的报文可靠。但以上的办法可以看出是串行的,效率低。

真实的情况:C并行发送多次报文,S也并行发送多次应答,这样时间重叠了,提高了效率。但多个报文经过网络,发送顺序并不一定是收到的顺序;客户端收到多个确认的时候,客户端并不知道是哪几个报文正确发送了。所以报文必须得带上序号,防止乱序情况,收到应答方也得确认序号。

3、序号和确认序号

上图中,报头中还有序号和确认序号,序号是客户端对自身报文的编号,服务端给的应答必须要有确认序号,C发送的序号是10,那么S发送的确认序号就得是11,S发送的序号是11,那么C的确认序号就得是12,序号按升序走,就能保证报文按序到达。

确认序号X的含义是X - 1之前的报文已经全部收到,下次发送请从X号开始发送。为什么序号是10,确认序号不能是10?假设C发送了10和11,S会回复11和12,如果11这个确认序号C没有收到,只收到了12,那么意思就是11之前的报文已经全部收到了,也就是10和11都收到了,下次发送C就会发12号报文,所以这里的确认序号允许少量的应答丢失,也能更细粒度地确认丢包的原因。

为什么序号和确认序号不用一个四字节来表示?TCP是全双工的,C和S都会同时发送和接收。以S来说,S发送的报文包括对C发送到S的报文的确认和S要发送给C的报文,两个报文可以分开发,但效率更低,所以要合并发,压缩成一个应答,这就是捎带应答。这样的情况,S必须要有序号和确认序号,两个序号干两个活,同时存在,所以需要分成两个序号。

4、16位窗口大小

传输层内部包含发送、接收缓冲区,传输层上面有系统调用层,再上面就是应用层。应用层也有缓冲区,使用send/write等系统接口的本质就是把应用层缓冲区的内容拷贝到传输层的发送缓冲区,然后继续向下发,通过网络发到另一个主机上的传输层的接收缓冲区,再通过read/recv等系统接口来到应用层的缓冲区。

发送的过程由传输层决定,发送多少,发送速度,也就是TCP协议决定,所以它是传输控制协议,应用层拷贝完就返回,全权交给网络自己去做。两方主机,如果对方主机TCP的接收缓冲区满了,那么我方的TCP再次发送时,报文到了那里就会被丢弃,因为缓冲区满了,但这些报文已经消耗了网络资源,所以这样就会出现低效的情况。相应的解决方案是流量控制,控制发送方发送的速度,让接收方有时间清理缓冲区。TCP之间有应答,发送方发送后,等到接收方给到应答再发送。因为有缓冲区的存在,且每个报文必须都有应答,就可以设置一个窗口大小来限制,窗口大小表示多少对方接收缓冲区剩余的空间,那么我方就发送少于这个空间的报文。一个接收方,窗口大小填自己的接收缓冲区的剩余空间大小。流量控制不仅限速,也加速(如果发送太慢了,或者接收方消化得很快,我方相对应慢)。


检验和就是用来检验报文是否合格的,成功就无事,失败就丢弃整个报文,这时候才是丢包,丢包之后不给应答,那么TCP的发送方就有超时重传机制。

保留的6位是留出来的位置,协议的定制者想好后再填,不填也行,就空着。

5、6个标志位和紧急指针

在这里插入图片描述

一个只占一个比特位。

假设客户端C,服务端S,一个服务端会收到不止一个服务端的请求。TCP是面向链接的,C会向S发送链接请求,然后进行正常通信,然后发送断开链接的请求等等。一个S,会在同一个时间段内收到很多各种各样的报文请求,即报文格式内容都不一样。报文类型不同,不同的报文也得给到不同的服务,报文的类型由标志位来标识。标志位总共6位,是哪一类型,哪个位置就是1,其它为0,比如00100,就是RST报文。

ACK:确认应答报文。如果携带数据就是捎带应答,不是就是纯ACK
SYN:连接请求报文。伴随3次握手
FIN:断开连接报文。伴随4次挥手

PSH。在接收端接收缓冲区满了之后,发送端得到报文说剩余空间为0,发送端就得等待,但等待多久?发送端每隔一段时间就发送不带数据只有报头的报文来找接收端,看看空间有没有留出来,如果多次发送,接收端的接收缓冲区剩余空间都是0,说明接收端的应用层读取数据太慢或者还没读取等问题,这时候发送端就发送一个PSH报文。提示接收端应用程序立刻从TCP缓冲区把数据读走,这就是PSH报文的作用。

RST。发送SYN报文后会发生3次握手,C向S发请求,S发应答,C再发请求,这个不一定能成功,如果成功,就建立了连接,这时候如果S释放了链接,但C不知道,C还会发送请求,还会维护链接,不过肯定没有S发送给C的任何报文,当S重新用这个链接时,C发过来了数据,但S会认为,不应当直接发送数据,应当先握手,此时S就知道C的这个链接是老的,是异常的,S就会发送一个RST报文,C得到RST报文就断掉现在的这个连接,重新跟S握手。RST就是reset,重置连接。

URG。紧急指针标志位。TCP报文都是按序处理的,根据序号来排队处理。有些报文需要紧急处理,就得插队,那么UGR报文就是用来表示紧急报文的,当报文是URG类型的,报头中的紧急指针也就有效。紧急指针是偏移量,表示紧急数据在有效载荷部分中的偏移量,这样接收方就可以直接找到紧急数据并处理。紧急数据的大小固定只有1个字节。URG报文发送方要特殊地发送,接收方要对应特殊地接收。发送法上传数据的中途取消上传或者暂停上传,它需要尽快实现这个行为,而不是和平常一样排队处理,这时候就可以发送URG报文,紧急数据这时候就是状态码,表示要取消还是暂停,紧急指针可以新开辟一个链路,只处理这个URG报文。紧急数据也叫带外数据。想查看一个服务器状态时也可以用这种报文,即使服务器忙,也可以开辟一个新链路去查看状态,返回状态码来得知,recv系统接口中有一个参数是flags,是一个标志位,其中有一个MSG_OOB,这个标志位就是让recv读取带外数据,发送的接口send也有这个flags,也有这个标志位MSG_OOB,就是发送紧急数据,send和recv都采用MSG_OOB才可以处理紧急数据。不过实际上,这个URG不常用,因为可发送的数据太少,不如开两个端口,一个正常处理,一个紧急处理。

2、TCP可靠性

1、应答机制

主机AB,应答机制体现在A到B和B到A,比如B到A,B会知道是否有应答,有应答,说明发送成功,没有应答说明失败,无论怎样,结果都知道,A到B也是如此,所以就能双端都有可靠性。应答可以是无关的,只要序号是对应的,回复了就行。

TCP不关心发送缓冲区的数据是什么。TCP是面向字节流的,以它的视角来看,发送缓冲区就是以字节为单位的,多个单位的空间,应用层数据拷贝过来后,TCP也当做一个字节流,放到缓冲区,缓冲区是一个数组,下标对应着每一个字节的数据,所以下标就会当作序号。以字节流拿到数据,以字节流发送数据。

2、超时重传机制

主机AB,A为发送方,B为接收方,发送方知道是否丢包的办法就是看有没有应答,有就没丢包,没有就说明发送的报文丢失了或者接收方的应答丢了。只要A没有收到应答,就会重发。

如果是因为B的应答丢失,A重发,B就收到了两次相同的报文,那么B就需要有去重功能,如果B收到相同序号的报文,就丢弃重复的那个。

A发送出去的数据,在得到应答前或者超时前都必须维护好这个数据,以便超时重传。那么超时重传的这个等待的时间间隔应该如何设置?为了得到合适的时间,TCP会动态计算这个最大超时时间,Linux以500ms为一个单位,每次判定超时重发的超时时间都是500ms的整数倍,第一次等待500ms,没等到就重发,并等待1000ms,没等到再重发,并等待1500ms。当多次这样做后都没有应答,就认为接收方没给应答。

3、连接管理机制

在这里插入图片描述

握手

客户端创建套接字,调用connect接口发起连接请求并等待其完成,也就是发起了3次握手,客户端向服务端发送SYN报头,也就是标志位SYN那里被置为1,但不包含数据,只有报头,服务端收到SYN报头后再发送SYN + ACK报头,客户端再发送ACK报头。

三次握手的目的是建立连接,握手的过程是双方的OS的TCP层自主完成的。同一时间段内,多个客户端要请求连接服务端,OS就会进行多个3次握手,建立多个连接,并用数据结构来管理它们。 通过以上得知,创建维护连接是有成本的,会消耗内存 + CPU资源。accept接口的作用就是等待建立完成,获取连接。

客户端发送连接请求,发送SYN报头后,客户端的状态变为SYN_SENT,服务端收到SYN报头后状态变成SYN_RCVD,客户端收到SYN + ACK报头并发送ACK报头后状态就变成 ESTABLISHED,服务端收到ACK报头后状态也变为ESTABLISHED,至此3次握手结束,两端都进行了3次接收或发送,两端也就都完成了3次握手。

很多表示握手的图,两端之间的线都是斜向下的,因为图的隐藏线是时间线,时间从上到下逐渐前进,发送请求是有时间差距的,客户端发送和服务端收到不是一个时间点,所以是斜向下。

3次握手中,如果第一次SYN发送失败,对服务器没有影响,客户端会重发;第二个SYN + ACK丢失,就说明没有建立起来连接,3次握手没成功,而且也有应答,所以这个也没什么问题;第三次ACK没有应答,所以客户端不知道有没有建立好连接,但只要发出ACK,客户端就认为3次握手成功,如果服务端收到,那就说明真正地成功了,如果服务端没收到,就没连接成功,这时候客户端认为成功了,就开始发送请求,服务端收到后认为握手没有成功,不应该开始交互,就意识到最后一次握手丢包了,服务端就发送连接重置报文,也就是RST报文,客户端就断掉连接,重新握手。多次重新握手的概率会逐渐叠加,所以不担心一直连接不上,除非两端的压力就是没办法很好地连接。连接不是必须一次成功,也不是必须连接上。

2次握手不行,客户端发送给服务端,服务端再回复给客户端,服务端发送出去后就认为建立完成,但如果丢失,客户端就知道没建立完成。这里的问题是客户端发送一次成功后,服务器就能发送回去,服务端就认为建立成功,既然这样,那么客户端可以发送海量SYN,然后对响应不做处理,不断发送,服务器一直认为建立成功,创建了海量连接,占据了大量的内存 + CPU资源,所以不行。这就是SYN洪水。

4次以上握手也不行。在3次握手中可以发现,最后一次发送报头的那一端就是先完成握手过程的一端,3次中就是客户端,而4次则是服务端,2次也是服务端,奇数次都是客户端先完成,偶数次都是服务端先完成。连接都有可能出现连接异常,偶数次握手由服务端最后发送报头,连接异常的问题就会出现在服务端上,所以要用奇数次握手,连接异常放在客户端上。服务端要跟很多个客户端建立连接,所以不能让服务端出现大问题。

3次握手相对来说不易被攻击,更安全,没有明显设计漏洞,一旦建立连接,出现异常,成本会出现在客户端,服务端成本较低;3次握手能够验证双方通信信道的通畅情况,且是验证全双工通信信道通畅的最小成本。3次握手通过两次SYN和SYN + ACK报头,两端都验证了自己的发送接收没有问题,2次握手服务端发送后并不知道客户端是否收到。

3次握手把这方面的安全隐患降到最低,但不是没有,还是可以有SYN洪水的,但这样的SYN洪水成本就高多了,攻击一直有,没法避免,只能每一部分都尽量将自己的安全问题降到最低,然后交给负责安全的人去处理外来干扰。

发送数据是把数据拷贝到TCP的发送缓冲区,由发送方的OS自主发送的,接收是由接收方的OS自主发送的。

挥手

上面的3次握手也可以看作4次握手,客户端SYN,服务端ACK,服务单SYN,客户端ACK。

客户端使用close时就开始了4次挥手,由客户端发起FIN报头,表明要断开连接,服务端发送ACK应答,表明已经知晓这个请求,服务端通过自己的调度断开连接后,就发起FIN报文告知客户端,客户端接收后就发送ACK应答,表明客户端已经知道连接断开了。

如上图,客户端发起FIN后,进入FIN_WAIT1状态,服务端收到后断开连接请求后变成CLOSE_WAIT状态。客户端要断开连接时,服务端无法阻止。服务端发送ACK,客户端收到后变成FIN_WAIT2状态,到服务端发送FIN报头后,服务端变成LAST_ACK状态,客户端收到后变成TIME_WAIT状态,客户端发送ACK应答,客户端变成CLOSED状态,服务端收到ACK后,就断开连接释放各种资源变成CLOSED状态。中间服务端发送给客户端的ACK和FIN报头,即使丢弃也有对应措施,最后一次客户端发送ACK没有应答,客户端就会等待一段时间,尽量保证服务端收到ACK再断开连接。

发出ACK后客户端就已经完成4次挥手,服务端收到ACK后才是4次挥手完成。如果服务端一直没法FIN,那么连接就断不开,服务端一直处于CLOSE_WAIT状态。当客户端处于FIN_WAIT2时,如果长时间服务端不关掉,那么客户端就自己断掉,所以服务端要及时close(fd)。客户端自己关闭了,服务端处于CLOSE_WAIT状态,文件描述符打开了多个,此时如果直接关掉服务器,那么服务端大概率处于LAST_ACK状态,然后给客户端发送FIN,告知客户端要断开连接了,但客户端此时早就CLOSED了,服务端就会重发好多次,等待响应,一直没有,那么服务端就不发了,断开连接,处于CLOSED状态。

服务端主动断开连接,TCP自动挥手,客户端会处于TIME_WAIT状态,此时连接断开了,不过资源没有完全释放,因为客户端还处于TIME_WAIT,维护连接的一些数据结构还没消除,所以这是一个边界状态,端口号还在被使用。此时想重新开启,就会发生绑定错误。为了能够立马重启服务器,无视TIME_WAIT状态,用setsockopt接口

在这里插入图片描述

level设置成SOL_SOCKET,服务器允许被复用;optname设置为SO_REUSEADDR,地址复用;optval设置成整型,optlen设为1。之前的Sock.hpp中

    void Socket()
    {
        _sock= socket(AF_INET, SOCK_STREAM, 0);
        if(_sock < 0)
        {
            logMessage(Fatal, "socket error, code: %d, errstring: %s", errno, strerror(errno));
            exit(SOCKET_ERR);
        }
        //添加下面的
        //设置地址是可复用的
        int opt = 1;
        setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
    }

服务器主动断开后,客户端为什么要处于TIME_WAIT而不是处于CLOSED状态?TCP协议规定,主动关闭连接的一方进入TIME_WAIT状态需要等到2MSL时间,MSL时间是一个报文在网络中存在的最大时间,也就是一端发给另一端的时间。客户端发送还需要接收,所以是2MSL。MSL时间是可以配置的,可以设置得大一些。 Linux中是60s,通过这个命令查看

cat /proc/sys/net/ipv4/tcp_fin_timeout

这样修改

sudo echo 10 > /proc/sys/net/ipv4/tcp_fin_timeout

等这个时间的原因是保证之前的报文都能够交付,让这些报文消失再彻底关闭。不消失的话,再重开服务器,服务器会收到之前有序号的报文,服务器会觉得这个序号之前的报文都已经完成了,所以会影响新发的报文,出现很奇怪的问题,不过这件事发生的概率很小。

连接尽量不要异常断开,比如上面服务端在CLOSE_WAIT状态待太久。在客户端是TIME_WAIT状态时,如果客户端发送的ACK丢失,那么服务端收不到回应,就会再次发送FIN的超时重发报文,客户端就知道ACK丢了,就再次发送ACK。如果服务端发送不了FIN,实际上概率也很小,因为刚刚才发了ACK,这样的就只能客户端等到时间结束自己关闭,最后异常断开连接。

3、流量控制

3次握手之后,才会开始发送带数据的报文,在握手时发送的都是报头,握手过程中双方就知道了之后发送数据时要发送多少,也就是在之后的第一次发送数据前就控制好了流量,之后再动态控制。

接收端发送的报文中,窗口大小填充了可以接收的缓冲区大小,窗口大小字段越大,网络吞吐量越高。如果缓冲区满了,窗口大小就是0,客户端就不发送消息,但会定期发送报头(不携带数据)询问缓冲区大小,也就是窗口探测报文。,长时间为0就催促接收端应用层赶快读走数据。

结束。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

邮件群发怎么做才有效果?如何做邮件群发?

邮件群发的注意事项有哪些&#xff1f;QQ邮箱群发邮件的方法&#xff1f; 在当今的数字营销时代&#xff0c;邮件群发已成为企业与客户保持联系的重要手段。但如何确保邮件群发的效果最大化呢&#xff1f;下面&#xff0c;蜂邮EDM将探讨几个关键要素&#xff0c;帮助您更有效地…

HackTheBox - Medium - Linux - Ambassador

Ambassador Ambassador 是一台中等难度的 Linux 机器&#xff0c;用于解决硬编码的明文凭据留在旧版本代码中的问题。首先&#xff0c;“Grafana”CVE &#xff08;“CVE-2021-43798”&#xff09; 用于读取目标上的任意文件。在研究了服务的常见配置方式后&#xff0c;将在其…

阿里云服务器在哪个城市?云服务器地域节点分布表

2024年阿里云服务器地域分布表&#xff0c;地域指数据中心所在的地理区域&#xff0c;通常按照数据中心所在的城市划分&#xff0c;例如华北2&#xff08;北京&#xff09;地域表示数据中心所在的城市是北京。阿里云地域分为四部分即中国、亚太其他国家、欧洲与美洲和中东&…

C++20新特性解析:深入探讨协程库的实现原理与应用

C20新特性解析&#xff1a;深入探讨协程库的实现原理与应用 一、C20的协程库简介二、C20协程基础知识2.1、协程的基本概念和使用方法2.2、C20中的协程支持2.3、协程与传统线程的对比 三、C20协程库的实现原理四、C20协程库的应用实例总结 一、C20的协程库简介 C20引入了对协程…

2024年 复习 HTML5+CSS3+移动web 笔记 之HTML5遍

2023年黑 马学习视频 ---作复习&#xff01;&#xff01;&#xff01; 前言 和 路向 第一天 基础标签 1.开发环境安装 2.标签语法 3.Html 基本骨架 4.标签的关系 5.注释 6.标题标签 7.段落标签 8.换行与水平线标签 9.文本格式化标签 10.图像标签 11.路径&#xff08;绝对和相…

k8s之pod的基础(下)

k8s的pod重启策略 Always deployment的yaml文件只能是Always pod的yaml三种模式都可以&#xff0c;不论正常退出还是非正常退出都重启 OnDailure&#xff1a; 只有状态码非0才会重启。正常退出是不重启的 Never 正常退出和非正常退出都不重启 容器的退出了&#xff0c;pod才…

【软件测试】软件开发各阶段的自动测试技术

说到自动化测试&#xff0c;你可能最为熟悉的就是GUI自动化测试了。比如&#xff0c;早年的C/S架构&#xff0c;通常就是用自动化测试脚本打开被测应用&#xff0c;然后在界面上以自动化的方式执行一系列的操作&#xff1b;再比如&#xff0c;现今的Web站点测试&#xff0c;也是…

模板元编程简介

从引入 template 关键字开始&#xff0c;C里就出现了泛型编程&#xff0c;而又泛型编程衍生出的模板元编程&#xff08;template meta_programming&#xff0c;简称“元编程”&#xff09;则是众多编程范式中最复杂、最强大和最具有权威的一种。所谓“元编程”——metaprogramm…

学习笔记——C++ 逢七过 问题

试用for循环语句解决以下案例&#xff1a; 案例描述&#xff1a;从1开始数到数字100&#xff0c;如果数字个位含有7&#xff0c;或者数字十位含有7&#xff0c;或者该数字是7的倍数&#xff0c;我们打印敲桌子&#xff0c;过&#xff0c;其余数字直接打印输出。 思路&#xf…

C++进阶--map和set的介绍及使用

map和set的介绍及使用 一、关联式容器与键值对关联式容器键值对pair树形结构的关联式容器 二、set2.1 set的介绍2.2 set的使用2.2.1 set的模板参数列表2.2.2 set的构造2.2.3 set的迭代器2.2.4 set的容量2.2.5 set修改操作2.2.6 set的使用举例 三、multiset3.1 multiset的介绍3.…

MySQL——用户管理

目录 一.用户管理 二.用户 1.用户信息 2.创建用户 3.删除用户 4. 修改用户密码 三.数据库的权限 1.给用户授权 2.回收权限 一.用户管理 如果我们只能使用root用户&#xff0c;root的权限非常大,这样存在安全隐患。这时&#xff0c;就需要使用MySQL的用户管理&#xff…

强化学习5——动态规划在强化学习中的应用

动态规划在强化学习中的应用 基于动态规划的算法优良 &#xff1a;策略迭代和价值迭代。 策略迭代分为策略评估和策略提升&#xff0c;使用贝尔曼期望方程得到一个策略的状态价值函数&#xff1b;价值迭代直接使用贝尔曼最优方程进行动态规划&#xff0c;得到最终的最优状态价…

windows下载官方正版notepad++

一、前言 notepad是一款非常好用的编辑器&#xff0c;简洁、快速、高效。可是很多时候我们想去官网下载时&#xff0c;百度出来的都是一堆第三方下载地址&#xff0c;捆绑流氓软件&#xff0c;要么就是付费&#xff0c;作为一款优秀开源软件&#xff0c;我们必须要知道正确的下…

蓝桥杯练习题(一)

&#x1f4d1;前言 本文主要是【算法】——蓝桥杯练习题&#xff08;一&#xff09;的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 …

物联网产品中,终端、网关、协议、PaaS、SaaS之间的关系

在互联网产品中&#xff0c;经常提到的终端、网关、协议、PaaS、SaaS之间&#xff0c;到底有什么关系呢&#xff1f; 一、基本概念 在百度/其他地方搜集的信息中&#xff0c;对于终端、网关、协议、PaaS、SaaS的解释各有不同&#xff0c;整理如下&#xff1a; 终端&#xff1…

AQS 抽象队列同步器

AQS AQS &#xff08;抽象队列同步器&#xff09;&#xff1a; AbstractQueuedSynchronizer 是什么 来自jdk1.5&#xff0c;是用来实现锁或者其他同步器组件的公共基础部分的抽象实现&#xff0c;是重量级基础框架以及JUC的基石&#xff0c;主要用于解决锁分配给谁的问题整体…

5年经验之谈 —— 探索自动化测试用例设计粒度!

自动化测试用例的粒度指的是测试用例的细致程度&#xff0c;即每个测试用例检查的功能点的数量和范围。 通常&#xff0c;根据测试用例的粒度&#xff0c;可以被分为3种不同的层次&#xff0c;从更低层次的细粒度到更高层次的粗粒度。 第一种&#xff1a;单元测试 - 细粒度 单…

编译ZLMediaKit(win10+msvc2019_x64)

前言 因工作需要&#xff0c;需要ZLMediaKit&#xff0c;为方便抓包分析&#xff0c;最好在windows系统上测试&#xff0c;但使用自己编译的第三方库一直出问题&#xff0c;无法编译通过。本文档记录下win10上的编译过程&#xff0c;供有需要的小伙伴使用 一、需要安装的软件…

2024年【化工自动化控制仪表】报名考试及化工自动化控制仪表考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 化工自动化控制仪表报名考试是安全生产模拟考试一点通生成的&#xff0c;化工自动化控制仪表证模拟考试题库是根据化工自动化控制仪表最新版教材汇编出化工自动化控制仪表仿真模拟考试。2024年【化工自动化控制仪表】…

outlook邮件群发单显技巧?群发怎么单显?

outlook邮件群发单显如何设置&#xff1f;QQ邮箱怎么群发单显&#xff1f; 在群发邮件时&#xff0c;如何让每个收件人只看到自己的名字&#xff0c;而不是其他人的名字&#xff0c;这就涉及到所谓的“单显”技巧。下面蜂邮EDM就为大家揭秘Outlook邮件群发单显的奥秘。 outlo…