udp协议/tcp协议

news/2024/5/17 0:18:45 标签: udp, tcp/ip, 网络, tcp, c++, 后端, 数据结构

        udptcp作为传输层的两大重要协议,是众多学习网络编程者不可错过的学习内容,协议的概念想必不用再过多解释,即程序员和程序员之间进行网络通讯时的标准,那么经历了应用层,也就是肉眼能看到、用户能直接操作的层,接下来是传输层,所谓传输,就是管理client和server如何中的数据是如何传输,怎么传输,所以这两个协议也是管理这些的。

1.端口号

        端口号标识了一个主机上进行通信的不同应用程序。也就是说数据从对端主机应用层的某一个端口自顶向下传来,经过应用层、传输层、数据链路层、物理层的层层打包,再经过路由的路径选择,一步一步到达本主机,再经历一遍刚刚的过程,不过要反过来,经过物理层、数据链路层、传输层、应用层的层层解包,最终被应用层的协议读到正文数据,而也是被某个端口读到的,所以我们不难发现端口就好像是一个机器上的一个个小部门,也可以负责数据的通讯。

        而为了好好管理这些可以通讯的端口,可以让它们有序、正确的为我们服务,即收发数据,将为这些端口编号,经常使用的那些端口也就成为大家耳熟能详的了,比如http协议的默认端口号8080。

        上图为各个应用层协议及每个协议默认的端口号,而下层就是传输层+数据链路层,所以不难发现ip地址+端口号就可以确定某个应用。

        那么端口号的划分返回为0~1023,知名的应用层协议由于为了用户使用的方便性,不可轻易改变,确定后要一直使用,所以HTTP,SSH,FTP等这些广为人知的应用层协议,它们的端口号都是固定的。而1024~65535,这些端口号为操作系统动态分配的端口号。客服端程序的端口号,就是由操作系统从这个范围自动分配的。

        所以我们来回答两个问题:

        ①一个进程是否可以bind多个端口号?

                可以。我们可以将应用层的服务当作一个个进程,只要经过此端口访问到的进程都是指向同一个进程,不会造成差错。

        ②一个端口号是否可以bind多个进程?

                不可以。一个端口号只能绑定一个进程,如果一个端口号绑定了多个进程,那么用户经过唯一指定的ip路径+端口号访问到的资源将不一致,服务与服务之间会造成冲突。

2.netstat -nltp指令

        在Linux系统中,使用netstat可以查询到本机上正在运行的网络服务,并可以查询到它们使用的是什么协议,端口号是什么,目前所处的状态等。

        而通常会在netstat后跟上-nltp,n(number)代表能显示成数字就显示成数字,不带n就按照文件名显示。l(listen)代表查询监听状态下的套接字,不带l就查询已经建立好的。t(tcp)代表查询使用tcp协议的套接字进程。t也可以替换成u(udp),也就是使用udp协议的套接字进程。p(process)代表这些网络套接字本质都是进程。

3.udp协议

        已经了解到udp协议是传输层的两大主要协议之一,那么既然是管理传输的,自然而然会对其传输的细节产生好奇,数据究竟是如何交付给上层的?谁在管理?传输的格式是怎样的?了解这些问题之前,需要先来看一下udp协议的报头:

        udp协议的报头由三部分五部分构成,源端口号和目的端口号代表此数据从对端主机的哪个端口来,要到本机的哪个端口去。16位udp长度代表此数据包总共有多少个字节,由于协议的报头已经占了8个字节,所以此长度最小就为8,再有就是数据的长度。16位校验和和tcp的校验和功能相同,主要是做一些校验工作,不必过多了解。

        由于Linux内核是C语言写的,那么从C语言的角度看,udp报头又可以用一个熟悉的方式来表示:

struct udp_hdr
{
    uint32_t src_port:16;
    uint32_t dst_port:16;
    uint32_t total:16;
    uint32_t check:16;
}

        了解过udp协议报头后,上述的问题也就可以回答了,数据是如何做到封装和解包的?答:将报头和有效载荷分离。数据如何做到向上交付?答:根据目的端口号,交付给上层应用。

4.udp协议的传输特点

        udp协议在传输网络数据时类似于寄信,我们都知道平时在写信给别人时信尽可能多写,因为寄一次信并不容易,尽可能将想表达的内容写出来,对方读到的也是完整的信件内容,如果还有没有表达完的内容,中间就算丢失了,产生损坏了,送信的人根本不管,所以udp协议下数据的传输没有可靠性。

        所以udp协议的特点:①无连接:知道对端ip+port和本端的ip+port就直接传输,不需要建立连接。②不可靠:没有确认机制,没有重传机制,如果因为网络问题造成该报文无法发送给对方,udp协议也不会给应用层发送任何错误信息,换而言之发生错误后用户根本无法得知。③ 面向数据报:不能够灵活地控制读写的次数和数量,类似上面讲的送信机制,送多少次收多少次,读就读完整报文,不能多收或少收,即不能多读数据也不能少读数据。

5.面向数据报

        应用层交给udp多长的报文,udp原样发送,既不会拆分,也不会合并。

        如果发送端调用一次send发送100个字节,那么接收端也必须对应的调用一次recvfrom接收这100个字节的数据,而不能循环调用recvfrom,更不能自己选择接收的字节数,如果不想产生丢包问题,就必须要调用,且一次就要读完。

        所以可以体会到,貌似数据的传输不归应用层管,也不归用户关,看似我们将数据发送给对方,可是数据要在下层经历层层打包解包,而数据何时发、怎么发、发多少,这个问题将全权交给传输层协议来管理。

6.udp协议的缓冲区

        udp协议并没有真正意义上的发送缓冲区,由于udp协议面向数据报的特点,调用send函数会将数据交给内核,由内核将数据传给网络层协议进行后续的传输动作。

        udp有接收缓冲区,但是这个接收缓冲区不能保证接收udp报文和发送udp报文的顺序一致,如果缓冲区满了,再到达udp的数据就会被丢弃。

        udp协议既可以读也可以写,send和recvfrom可以同时调用,属于全双工协议。

7.基于udp的应用层协议

        NFS:网络文件系统、TFTP:简单文件传输协议、DHCP:动态主机配置协议、BOOTP:启动协议(用于无盘设备启动)、DNS:域名解析协议

8.TCP协议

        了解过udp的传输特点和机制后,进入到传输层应用范围最广的tcp协议,为什么说tcp如此适用呢?因为它弥补了许多udp做不到的功能,传输数据更加安全可靠,更适合用户传输数据。首先还是先来看tcp协议的报头:

        相比udp协议,tcp协议增加了许多报头数据,udp报头数据只占8字节,而tcp报头要占20字节,如果加上选项,则要占60字节,当然选项是可选择的,并不作为了解重点,而其他部分则是学习tcp的重点了。

9.4位首部长度

        作为tcp协议报头打头阵的数据,用来表示tcp报头的长度,只有4位,范围:0000~1111,代表0~15,单位为4字节,所以最大值为正好为60,也就是tcp报文的最大长度,那么如果不用选项的话,只有20字节,用20除以4等于5,也就是4位首部长度,所以4位首部长度经常用0101来填写,如果tcp协议带选项,那么选项的长度就应该是4位首部长度的值减去标准长度的值。

10.tcp协议确认应答机制

        之前说过tcp协议弥补了udp协议不可靠的特点,那么是哪些机制使得tcp协议更加可靠呢?其一就是tcp独有的确认应答机制,我们知道udp协议是面向数据报的,收发数据不会进行任何报告,这样就会导致用户和操作系统根本不知道数据有没有正常收到,有没有正常发送,而tcp协议的确认应答机制顾名思义就是基于序号对已发数据和接收数据进行应答,通过应答来保证上一条数据已经被对方读到了。

        tcp协议并不是百分之百可靠的,但只要一条消息有应答就代表该消息百分之百被对方收到了,所以tcp的确认应答机制是常规可靠的。

        所以序号和确认序号,就是针对对方发来的数据进行排序,依次带上编号进行应答,是对历史确认报文的序号+1,收到确认应答的tcp报文之后,可以通过确认序号来辨别是对哪个报文的确认。

        例如发送了13号,代表13号之前的报文已经全部收到,下次就可以从13号以后的报文开始发送。

        那如果client端发送了3000个报文,但是0~1000,2000~3000server都受到了,但是1000~2000的报文丢失了,那么确认序号该怎么发送呢?答:发送2000!并不会因为丢失了中间数据而忘记它,这也是tcp协议可靠的代表性之一。

        无论是确认应答还是正式的正文的报文,都是完整的tcp报文,也就是说即使是给对方发送确认序号,发送的也是一个完整的tcp报文。

        那么可以发现这个序号有两个,既然只负责确认,这个序号可以只有一个吗?不可以,因为tcp协议同udp协议一样为全双工协议,既要负责给对方发数据也要负责收数据,互相确认,这样的动作可以同时进行。双方通信时,一个报文既可以携带要发送的数据,也可能携带对历史报文的确认。

11.tcp协议的缓冲区

        udp协议的缓冲区相较tcp协议有很大的区别,此区别由于它们本身协议的特性决定,因为udp协议是面向数据报的,tcp协议是面向字节流的,即udp发送报文要么不发,要么一次性发完,而tcp协议则是由缓冲区决定,我们又知道传输数据的机制完全交由传输层决定,发多少、怎么发,完全交给tcp协议管理,所以tcp协议相较udp很明显的区别之一:由缓冲区来管理发送数据的多少。

        tcp协议是自带发送缓冲区和接收缓冲区的(malloc的两端空间)

        write/read:与其叫做发送接收接口,不如理解成拷贝函数应用层进行send,并不是把数据发送到网络上,而是把数据拷贝到tcp的发送缓冲区。

        了解过这些我们肯定又对“数据发送并不受用户控制”这个概念有了更加深刻的理解,所以我们在发送数据时,是应用层将数据拷贝给tcp的发送缓冲区,由tcp来做决定发送的时间,发送多少的决策,而这些决策又是由众多外界因素决定,例如对方接收缓冲区的大小、网络状况等等。而对端也是一样,接收缓冲区接收到了对方发来的数据,不会立即交付上层,而是暂存在接收缓冲区,再由应用层使用read等函数向上读取。

12.16位窗口大小

        知道tcp协议在收发数据时是有缓冲区这个概念后,接着引出窗口这个概念,因为tcp协议收发数据是面向字节流的,而字节流和数据包明显的不同就是,数据报不发则已,要发就全发,而字节流发与不发,发的多与少统统由tcp协议决定,所以tcp一定要有一个工具是用来管理字节流的收发,这就是缓冲区的作用,而发多少,收多少,这就是由窗口大小来决定了。

        在应答报文中,可以在报头上填上自己的接收缓冲区的剩余大小,换句话说也就是接收能力,并通过对方缓冲区的剩余大小来决定接下来的发送速度和发送多少。

        我们知道数据的接收和发送并不接受用户的控制,而是全权交给tcp来决定,换句话说我们肉眼所看到的“数据已经发出”,或者“数据已经收到”,其实不然,虽然看似数据已经发出,但是其实数据是存在tcp的发送缓冲区中,而tcp在等待很多东西,比如对方缓冲区的窗口大小,网速问题等,而如果接收方的窗口大小不够存正在处于发送端发送缓冲区的数据,则先不会发送,会通过下文即将要介绍的标志位中的PSH报文,通知对方上层尽快接收处于接收缓冲区的数据,发送端还有数据没有发完,所以窗口大小是和缓冲区相辅使用的。

        如果一方不断发数据的过程中,另一方来不及接收,那么数据就只能被丢弃。

13.6位标志位

        tcp协议站在发送和接收的角度是面向字节流的,因为它是按照缓冲区的大小和接受能力,将数据(在底层其实也就是字节流)依次放在缓冲区中,但是站在大体角度来说,与udp不同的是,udp只有收发数据具有明显特点,所以udp协议叫做面向数据报,而tcp站在不同的角度是会有不同的特点的,站在收发数据的角度tcp是面向字节流,而如果站在tcp建立链接的角度来看,tcp协议则是面向链接的!

        什么是面向链接,即链接之于tcp协议来说非常重要,可以说tcp协议的主要构成就是链接,通过许多接收端和发送端的链接来完成数据的传送。

        在编写网络套接字时,socket通信前要先调用connect函数,这就是建立链接的过程,如何建立链接?链接是如何一步一步建立好的?即tcp的三次握手!

        tcp的三次握手

        在任何时刻,在已经建立好链接的双方,都会有成千上百的数据被发送,而发数据之前最重要的就是确保收发双方主机的健康情况,不确定这些,也就不会给收发数据的双方提供保障。

        而之前说过,tcp报文不论是携带正文与否,都是一个正常的tcp报文,那么之于server而言,如何区分这些报文,究竟是要建立链接的报文,还是要和我正常通信的报文,就是sever端的一大问题了,即采用的是6位标志位来区分。

        那么先来介绍这6个标志位分别代表什么吧:

        1.ACK:表明发送的报文就是一个确认的报文,而并不是链接断开/请求的报文。

        2.SYN:表明发来的是一个链接请求的报文,要进行三次握手。

        3.RST:重制链接异常

        4.PSH:告知对方尽快将接收缓冲区的数据进行向上交付。

        5.URG:表明该报文中携带了紧急数据,需要被优先处理(要结合16位紧急指针来处理)。

        6.FIN:表明发来的是一个链接断开的报文,要进行四次挥手。

        所以当tcp要进行三次握手时,需要一方先发送SYN,表明想和对方建立链接,而对方收到请求后,也需要给对端发送回对于本次申请的回应,并且也向对方申请建立链接的请求,也就是ACK+SYN,前面的ACK是针对第一次SYN的回应,第二个SYN是向申请方同样申请建立链接,而第一次申请的主机由于自己的请求对方已经收到并且也收到了相同的建立链接的请求,所以也要给对方回应ACK,代表了对第二个SYN的回应,至此,三次握手已经完成,代表双方主机已经建立完成链接,可以正常通信了。

        其实看似是三次握手,其实是四次,只不过第二次将SYN+ACK合起来使用。

        而之前提到过,即使是链接请求的报文,之于tcp的角度,也和正常携带数据的报文一般无二,而发送数据是有成本的,最简单而言,要为其创建管理相关报文的空间,而且管理它们也是有成本的,要为其在内核创建相关的数据结构,维护双方的链接是有成本的(时间+空间)。

        所以要想攻击某个服务器时,可以冒充client端对其不停的发送SYN,发送完后并不接收server端的ACK,也就是说server要一直为我建立着链接,但是三次握手一直处于待完成的阶段,一直占用着server端的内存,消耗其内部资源。

        但是实际情况是如果client端发送大量的SYN时,server端并不会认为链接已经建立完成,也就不会发回SYN+ACK,所以此时server端不会为此套接字创建数据结构,server端的资源也就不会被浪费。

        tcp的四次挥手

        明白了建立,接下来了解链接断开的过程成本就会小很多了,也就是tcp的四次挥手,那么四次挥手的过程也是由收发双方共同完成,以client为例,先发送FIN请求链接断开,server发送ACK,再由server端继续发送FIN,最后由client发送ACK,完成四次挥手。

        其实不难发现,三次握手看似是三次,其实是四次,而四次挥手看似是四次,其实也可以像三次挥手一样当成三次处理。

        所以之于tcp协议角度的三次握手和四次挥手也是tcp自动完成的,用户层完全不参与,用户的发送行为,完全不会影响tcp的收发逻辑。

        所以为什么是三次握手呢?为什么不是两次/一次?有两个理由:①确认双方主机是否健康。②验证全双工,三次握手可以看到双方收发数据的最小次数。

        说完链接建立和断开的过程,标志位其实已经了解了三个了,其他的例如RST,意为在发送报文的过程中,如果client已经发送,但是server端等待了很长时间都没有收到,就会给client端发送一个RST,代表链接产生异常,已经很久没有收到你的数据了,可能产生网络问题、数据丢失等问题。

14.超时重传

       当发送完对应的报文,对方主机没有ACK,那么对方就一定没有收到对应的数据吗?可能是数据真的丢失了,也可能是主机A没有收到应答,但是总而言之主机A都会认为是数据丢失了。

        ①那么如果数据丢失了,tcp协议将会采用超时重传,也就是结合RST标志位,向对方主机发送数据异常的标志,一定时间后要求会重传数据包,对方也就收到了。

        ②那么如果是应答ACK丢失了,主机B再重传一份,主机A可能会收到重复数据,收到重复数据之于可靠的tcp协议来说也是不可靠的。

        那么如何避免收到重复数据呢:按照序号去重。

        网络都是虚拟的,网络快慢也是不断变化的,所以网络通信的效率肯定是变化的,发送的数据得到的应答的时间也是浮动的,超时重传的时间一定也是浮动的。

        在最理想的情况下,找到一个最小时间,保证“确认应答一定能在这个时间内返回”,但是这个时间的长短,随着网络情况的变化,是有差异的,如果超时时间设的太长,会影响整体的重传效率,但如果设置的太短,有可能会频繁发送重复的包。

        所以tcp协议为了保证无论在任何环境下都能比较高性能的通信,因此会动态计算这个最大超时时间。Linux系统中超时以500ms为一个单位进行计算,每次判定超时重发的时间都是以500ms的整数倍。如果重发一次之后,仍然得不到应答,等待2*500ms再进行重传,下一次则是4*500ms,以此类推。如果累积到一定重传次数,tcp协议会认为网络或对端主机出现异常,会强制关闭链接。

15.TIME_WAIT状态

        请求/断开链接的本质:双方达成链接都应该请求/断开的共识,就是一个通知对方的机制。

        三次握手和四次挥手是协商请求/断开链接的最小次数。

        那么经过四次挥手,主动断开链接的一方要进入TIME_WAIT状态,即代表等待对方确认,等待两个MSL的时间后回到CLOSE_WAIT状态。

        MSL代表了报文在网络中的最大生存时间,那么为什么是2MSL呢?①尽量保证历史发送数据在网络中消散(在发送最后一个ACK之前,双方已经进入到最后一次挥手阶段,历史数据不会增多,其存活时间最多为2MSL)。②尽量保证最后一个ACK被对方收到。

        所以之前的一个端口只被一个进程绑定就不难理解了。

16.滑动窗口

        tcp协议的收发缓冲区中,由于数据的发送数量和时间全权交由tcp协议决定,所以如何管理收发是很大的问题,除了确认序号外,滑动窗口也是管理tcp收发数据的另一大机制。

        窗口代表了在收发缓冲区中的数据并不是一次性发送,而是处于窗口中的数据可以发送,但是收发的数量由滑动来决定,当数据发送一些后,窗口的起始向后移动,窗口的末尾向后移动,也就模拟了动态的滑动过程,也就是窗口越大,网络的吞吐量就越大。

        例如,win_start += 确认序号,代表了已经发送了的数据,win_end += win,win代表了对方接收缓冲区的大小,总体代表了后续可以发送的数据。

17.快重传和超时重传

        我们都知道丢包这个概念,即在网络状态不稳定的过程中,数据经过网络的传送可能会发生丢失的情况,那么tcp协议针对这种情况也有独有的处理手段,一般情况,丢失数据会分为这两种情况:

        情况一:数据包已经到达,但是ACK丢失了

        这种情况不必担心,因为可以通过后序ACK的补发进行确认。

        情况二:数据包直接丢失

        如果数据包直接丢失,那么确认序号则会在此断开,例如此次发送的数据序号位1000,则对端发送的确认序号将会是1001,即使2000~9000的数据都已经安全到达,对端还是依旧会发送1001来提醒发送端1000号报文丢失了,那么对端将会发送3个同样的确认应答序号,在发送端收到这3个序号后,则发送端得知数据已经丢失,那么则会采取重传的机制将数据重新补发。

        这种机制就叫做“快重传”。

        那么快重传和超时重传有什么区别呢?快重传在场景中采用的概率极高,而且速度也比超时重传快很多,但是即使是这样,也不能取消超时重传,超时重传代表了收发双方其中某一方已经很长时间没有回应了,作为兜底的重发机制!

18.流量控制

         接收端处理数据的速度是有限的,如果发送端发的太快, 导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应.
        因此TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制。
        
        接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 "窗口大小" 字段,通过ACK端通知发送端。
        接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;
发送端接受到这个窗口之后, 就会减慢自己的发送速度。
        如果接收端缓冲区满了,就会将窗口置为0。这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。
        什么时候可以得知对方的接收能力?取决于对方什么时候给我发送第一个报文(三次握手就已经交互了,握手期间,协商窗口大小,根据对方的窗口大小来设置自己的滑动窗口大小的初始值)。
19.拥塞控制
         即使引入了滑动窗口,使得发送大量数据也能够高效运行,但是如果在一开始就发送大量数据呢?对于接收方仍然是一大问题。
        因为参与网络的并不是只有我们,全球有几十亿台计算机,在同一时间大量的收发数据,难免会产生数据碰撞和丢包的问题,而且这个问题是我们无法完全解决的,所以tcp协议引入慢启动机制,在一开始不知道对方接收缓冲区大小的情况下先不发送很多数据,先发送一两条,就好像交朋友一样,不能一上来就开很重的玩笑,在了解到对方能接受的程度后,玩笑也能成为友谊增进的甜味剂。
        所以此处引入拥塞窗口的概念,即发送开始的时候,定义拥塞窗口的大小为1,每次收到一个ACK应答,拥塞窗口加1,每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小作比较,取较小值作为实际发送的窗口大小,这样一来就能保证数据尽可能安全的在网络中传输。
        在已经经历了大量的收发数据后,拥塞窗口肯定是会一直增大的,因为在网络中最终肯定是要支持大量的数据传输的,所以既然是慢启动,那么在启动时慢,启动之后就会变得非常快,在经历过一定数量后,拥塞窗口会采用指数级的速度增长,但是为了不让其增长的过快,我们都知道指数增长到了后期将会呈现不可收拾的场面,所以要设定一个阈值,经过了这个阈值,拥塞窗口将不再按照指数的方式增长,而是按照现行的方式增长。
        
20.延迟应答
         如果每次回答速度都很快的话,那么此时窗口大小可能就比较小。
        比如此时接收缓冲区的大小为500字节,占用了500字节,如果接收端采取立即返回的策略,那么将会给对端返回500字节,但是在刚返回之后,接收端上层立即将数据读取,接收缓冲区的大小又变成了1000字节,那么此时收发两端得知的窗口大小就会产生差异。
        为了避免这种差异,tcp协议采取延迟应答的策略,即收到数据包后不要立即返回,收到一批后返回一次,接下来仍然是收到一批后再返回一次,那么这个“一批”就是由tcp底层特殊的算法来规定,一般超时时间取200ms,这样的话收发双方所得知的窗口大小就能在一定程度上保持一致。
21.捎带应答
        在延迟应答的基础上,由于我们说过tcp协议是支持全双工的, 为了进一步提高效率,引出了捎带应答的机制,其实上文中有一个机制已经体现出了捎带应答的机制,就是tcp协议的三次握手和四次挥手,SYN和ACK在第二次是同时发送的,也就是说并不是一次只能发送一个报文,可以捎带着将下次需要的报文在本次就发送。
22.Listen的第二个参数
         我们在写网络套接字时,listen函数肯定是不陌生的,意为收听,也就是等待对方进行连接,所以此函数非常重要,代表了双方建立连接的起点。
        int listen(int sock, int baklog);第二个参数baklog代表了在tcp层建立正常链接的个数+1。只要一个链接建立好,即使还没有被accept走,它的状态就是SYN_RECV。
        所以针对链接,linux也有一套管理系统,分别用全链接队列(保存处于established状态的请求)和半链接队列(保存处于SYN_RECV和SYN_SENT状态的请求队列)来管理。
        而全链接队列的长度会受到listen的第二个参数的影响,全链接队列满了的时候,就无法继续让当前链接的状态进入established了。
        
23.tcpudp对比
         讲了这么多,肯定会有一种感觉:tcp协议优点全面优于udp协议,那么tcp协议肯定是相比udp协议更加可靠的,但是这两个协议的特点不能简单地进行比较。
        tcp用于可靠传输的情况,应用于文件传输,重要状态更新等场景。
        udp用于对高速传输和实时性要求较高的通信领域,例如视频传输、广播传输等。

http://www.niftyadmin.cn/n/5138085.html

相关文章

vue-query的使用

vue-query,类似于vuex/pinia,以缓存为目的,但侧重的是对网络请求的缓存。 这是我预想的使用场景:假设在各个页面都需要发起相同的请求,去获取数据,而这种数据在一定时间内不会发生变化,那么这种…

win11系统msvcp120.dll丢失的解决方法,亲测有效的详细方法

在计算机使用过程中,我们常常会遇到一些错误提示,其中之一就是“msvcp120.dll丢失”这个错误通常会导致某些应用程序无法正常运行。为了解决这个问题,我们需要采取一些修复措施。本文将介绍五个修复msvcp120.dll丢失的方法,帮助大…

浪潮信息G7服务器智能高效的运维秘籍

数据中心的运维压力到底有多大?过去,IT圈里流传着这样一句话:一入运维深似海,从此下班是路人。随着人工智能、大数据、云计算等技术的成熟应用,数据中心走向集约化、规模化的趋势,数据中心的IT设备越来越繁…

盘古M900测试及FT D2000对比

盘古M900测试使用华为W525整机.硬件配置为: CPU:华为盘古M900 内存:板贴DDR4 8G(镁光) SSD: 长江存储 PC005 256G NVME 安装UOS 系统:uniontechos-desktop-20-professional-W525-1050-update5-arm64.…

PythonWEB

文章目录 前端简介1. 什么是网页2. 网页的组成3. 网页的优势4. 前端三剑客5. 编写步骤6. HTTP协议 HTML51. HTML介绍2. 元素3. 使用4. 基本结构解析5. 常用标签文本标签容器标签列表标签表格标签表单标签 对于文件数据的提交需要满足以下两个条件:6. 标签分类 前端简…

旅行社信息展示服务预约小程序的作用是什么

出行旅游近些年人次非常多,除了自己出行外,旅行社成为众多人的选择,而随着消费者线上信息获取度增加,因此对商家来说也需要线上发展实现赋能。 那么通过【雨科】平台做个旅行社小程序有什么效果呢? 1、品牌宣传、内容…

cron 表达式解释

Cron 表达式是一种用于指定定期运行任务的字符串表示法,通常用于调度任务或作业。Cron 表达式包括多个字段,每个字段表示时间的不同部分,如分钟、小时、日期等。这些字段由空格分隔,并形成一个由五或六个字段组成的字符串。 在标…

Vant Weapp 的van-cell 与 van-cell-group的边框

场景&#xff1a; 用van-cell循环出来的单元格&#xff0c;最上面有一条边框线&#xff0c;且找不到该元素&#xff1b; <van-cell-group border"{{false}}"> 直接在这写属性 <van-cell> </van-cell> </van-cell-group> 效果图&#xff1…