我们来谈谈tcp

news2024/11/27 18:29:20

"让新离开地表,才能找到盘旋爬升的动力。" 


一、认识Tcp报头 

(1) 协议报头格式

        我们先来认识认识tcp协议报头字段。

         跟tcp协议字段报头比起来,udp可真是太轻松了。

协议字段作用
源/目的端口号从哪里来,到哪里去
32位序号/32位确认号就是一种序号(之后会细讲)
4位首部字段表示TCP头部多少字段,最大长度为:15 * 4 = 60
6位标志位区别不同的tcp报头类型
16位窗口大小对端接受缓冲区大小
16位校验和接收端校验不通过, 则认为数据有问题
16位紧急指针保存的是紧急数据的偏移量
40字节头部选项暂时忽略
数据有效载荷

(2) 相关字段的理解

如何理解4位首部字段?

        根据以上关于TCP协议字段,我们可以得出以下结论:

        TCP报头是有长度的:20字节。要进行正常的网络通信的一个条件是,要让协议报头与有效载荷完成分离,也就是 " 解包与分用 "。然而,TCP的协议报头不是说是20字节嘛?那么要解包分用直接拿掉头上的20字节不就得了? 

        但其实,这是不对的。

         

如何理解特定的port 与 bind? 网络协议栈与文件有何关系?

        我们在实际生活中,或多或少都知道,一些特别的网络协议栈,都会bind特定的服务端口。比如说: http\https 80:443 FTP:21 ssh:22 telnet:23 ……

        同样,在LInux环境下,编写自己的第一份tcp套接字编程时,使用read\write系统函数write\read,向socket句柄读取或者写入数据时,这压根同LInux文件操作没有任何区别!


二、TCP可靠性

        只要谈到TCP,尤其是说TCP和UDP有什么区别时,那TCP保证可靠性的特性那就不得不骄傲地提上几嘴。那么TCP是如何保证可靠性的呢?要理解可靠性,那么不得不先理解到 造成不可靠通信的原因。

如何理解不可靠?

        我们可以举一个生活中,通信不可靠的例子。说白了,所谓的通信,本质上是为了让通信双方知晓对端发来的消息。

        比如说你的舍友张三,此时正在你身旁的椅子上,饶有风趣地刷着抖音,看着视频,你一看现在时间已经晚上八点整了,把自律作为座右铭的你,此时想也不想对着手机屏幕说了句,

         "几点了?!走吃饭去。"

        此时,你可以确信无疑,你这句话张三是接收到了的。因为此时,你从他的眼里读出了无比坚定且期盼的眼神。

        同样的,现如今你正在楼层为5F的宿舍里,啪啪敲击着键盘,碍于敲写代码的激情,但却难以忍耐解渴的本性,索性望向窗外,此时你的目光正抓住了开开心心走回宿舍大门的张三,于是乎,你赶忙跑向阳台,对着楼下的张三喊着,

        "张三,你上来捎带帮我瓶水!"。

        你确定的是(或许存疑),张三是没有听到这话的,因为他毫无表情、没有丝毫迟疑地走进了宿舍大门,消失在建筑物的遮挡之中。

        对于第一种场景而言,当我发起与张三同学的对话,因为距离近,我可以从张三的表情或动作中,也或许他直接接上了我的回话,“走,吃饭去”,这样的直接了当中知晓,我"发送"的消息,他确乎是接收到了的。然而,到了第二种场景,我与张三的距离变长了,不是面对面了,这时,我向张三发送"消息",我又该怎么知道这个"消息",他是否知晓呢?

        反过来,两进程跨网络通信,它们通信数据的传输出现不可靠性的根本在于,"距离边长了"

不可靠性有哪些表现呢?

丢包、乱序、校验和错误、重复……

(1) 确认应答(ACK)机制 && 效率提升

        再次回到上述场景,我知晓张三确乎收到了我发送的 "消息"的原因是什么? 即张三给我进行了"回应"——换个词语,也就是应答!

        而在实际的网络通信过程中,Client端不止Server端发送一条消息。

        我们认为: 

① 只有收到了应答,“历史消息" 就可以100%确认对方已经收到了 ---> 这是可靠的

② 但,双方通信一定存在 "最新消息",即没有收到应答的部分 ---> 是不可靠的。

        因此,我们常听说啊什么, TCP是可靠的,其实本质上可靠性指的是 "相对的可靠" ,而不是"绝对的可靠"

        TCP可靠性保证的一定是:

        一个报文只要是收到应答,该报文一定可靠。

        同样,也许你会说,啊难道我发一条消息,收到一条应答后,才能再发其他消息吗?这样未免太慢了。 答案是当然不是,真实的TCP工作模式应该是这样的:
       

 序号与确认序号:

        实际中,也会遇到报文 "乱序"的情况。比如说你先发报文1,过一会儿又发了报文2,但由于报文2路由很快,对端就先接收到了报文2,而后接收到了报文1。可是对于对端而言,它可"不知道"正确的报文顺序,因为"没有明显的标识"。

        在TCP协议字段的报头里,分别有32位的序号和确认序号。

        TCP正因为有序号、确认序号这种数据段标识自身,因此,如何Sever端能够清晰地知道自己接收的报文是否存在 "乱序" 的情况。

        当客户端接收到了 "确认序号"也就意味着:

   该 "确认序号"之前的内容已经全部被接收了,下次发送数据的序号请从  "确认序号" 开始进行编写。

        

为什么需要两组序号 ?

        因为tcp是全双工的,不管是客户端还是服务端,都有自己的接收、发送缓冲区,即我可以想你发送消息,你也可以向我发送消息。

(2) 超时重传机制

         根据图示,我们可以得出下面两个结论:

主机A发送数据给B之后, 数据无法到达主机B
如果主机A在一个 "特定时间间隔内" 没有收到B发来的确认应答, 就会进行重发;

        对于主机A而言,它只知道结果,即我没有收到任何的应答包。

        可是,也有可能主机B收到消息,并做出应答,但却发生了丢包。

         因此,针对上述两种情况,一旦TCP检测到 在这个 "特定的时间间隔内" 都没有收到ACK应答,就会出发 "超时重传机制"。

        由此,如果出现 "网络拥塞"等原因,导致主机B可能收到多份 因为超时触发的"重传机制",也就意味着主机B收到的报文一定出现 "重复"的现象。当然,对于TCP而言,因为有每一个发送的报文都有自己相应的序号,对于主机B而言,只需要将重复序号的报文进行丢弃即可。

        

如何确定超时时间?

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

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

● Linux中(BSD Unix和Windows也是如此), 超时以500ms为一个单位进行控制, 每次判定超时重发的超时
● 时间都是500ms的整数倍.
● 如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.
● 如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.
● 累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接.

小结:

        根据以上的两个小节,我们似乎回答了一些网络通信中可能会出现的不可靠性问题:
        

 

(3) 连接管理机制

        当一看到这个 "连接管理"机制的宏观图时,我想学过网络的不禁大呼一生: "三次握手,四次挥手"。

三次握手与四次挥手:

①Client端发起连接请求,发送携带"SYN"信息的报头给Server端,并进入SYN_SENT。

②Server端收到该消息后。进入SYN_RCVD状态,并且向客户端响应 "SYN+ACK"应答。

③Client端收到ACK应答后,进入ESTABLISHED,并发送最后ACK,Server收到后也进入ESTABLISHED。

        至此,双方三次握手完毕,成功建立连接。

①Client端发送断开连接请求,发送携带"FIN"信息的报头给Server,并进入FIN_WAIT1状态。

②Server端收到消息后,进入ClOSE_WAIT状态,收到ACK的客户端进入FIN_WAIT2。

③Server端发送携带"FIN"信息的报头给Client,进入LAST_ACK。

④Client端收到ACK并发送最后ACK给Server后,进入TIME_WAIT状态,收到ACK后的Server直接进入CLOSED状态。

        至此,双方通信信道关闭,不再维护TCP连接。

注: 首先发起断开请求的 会进入TIME_WAIT状态

        其实三次握手、四次挥手看图示的过程都能够看懂,但更重要的不是过程,而是原因。

为什么要三次握手?不能是四次?五次?

        预备:

① tcp是保证可靠性的,但是是相对的可靠。也就意味着握手是可能失败的。

② 链接是需要被管理的!是需要被OS管理的!先组织,再描述(结构化数据),是有维护成本的(时空)。     

        我们要谈论三次握手为什么行,就得谈论其他次数握手是不行的局面!

握手一次:

        绝对不行!因为一旦连接建立就需要维护,这个成本维护是Server来负担的,一旦遭遇"SYN"泛红攻击,客户端只给发SYN而不建立连接,消耗的是你Server端的链接资源,以至于无法对外为其他正常请求提供服务。

握手二次:
        同上原因。

握手三次:
        a. 最小的成本检验双方接收、发送数据(全双工信道)是通畅的。

        b. 有效防止单击对服务器的SYN攻击。因为是你客户端需要ESTABLISHED,客户端此时承受链接维护的成本。

握手四次五次?

        当然这也就不用谈原因了,因为三次就够了,为什么还需要这么多次??

        你说,"啊,这不行,如果对方攻击该怎么办呢?"

记住, "TCP不是为了帮你处理网络安全的问题的,它是网路通信的传输控制协议"。

为什么需要四次挥手?

         断开连接同建立连接一样,在TCP中Clinet端与Server端地位都是对等的。
        "这个是双方的事情,都需要经得双方的同意"。

理解CLOSE_WAIT状态:
        CLOSE_WAIT状态是在接收到主动断开连接的一方发送的"FIN"消息后出现的。当被动断开的一方进行close() 后,那么状态就会发生改变。但,如果一个服务器出现了大量的CLOSE_WAIT状态,导致这个的原因可能是:

① 服务器有bug,没有写close关闭文件描述符的动作。

② 服务器有压力,可能一直推送消息给Client,来不及close

理解TIME_WAIT状态:

        TIME_WAIT状态出现在主动断开连接的一方。如果断开的一方是服务器,那么还会出现服务器bind error的问题(因为陷入到了TIME_WAIT状态,原端口还被占用着!)。

        当进入到TIME_WAIT状态后,说明四次挥手已经完成,为什么主动断开连接的一方还需要维持一段时间的 “time_wait”?

        a. 保证最后一条ACK能被收到.

         因为,如果客户端收不到ACK,超过一定的时间,就会出发"超时重传机制",但是此时你的Client端已经关闭了,不会再对FIN报文做出任何响应了,可是服务器仍然会对这个并不存在的连接付出维护成本。

        b.保证滞留报文的消散(教材理由).

        TCP协议规定,主动关闭连接的一方要处于TIME_ WAIT状态,等待两个MSL的时间后才能回到CLOSED状态.MSL是TCP报文的最大生存时间。就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失。(否则,如果是服务器的话,就会立刻收到上一个进程未被处理完的、迟到的数据,而这种数据其实是错误的)。

        同时也是在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失, 那么服务器会再重发一个FIN. 这时虽然客户端的进程不在了, 但是TCP连接还在, 仍然可以重发LAST_ACK);
 

四次挥手能不能变成三次?

        这是一个常见的问题,一般而言指的是将 "ACK+FIN" 一起发送给Client端。这也和TCP效率优化相关的机制有关。

        我们可以在Linux系统中查看内核设置的FIN_WAIT_TIME:

 

(4) 滑动窗口

        我们知道tcp拥有一定的机制保证数据传输的可靠性,如确认应答、超时重传、以及连接管理。可是我们也知道,tcp通信的双方都有各自接收、发送缓冲区的,也就意味着,是啊我tcp有能力让你的数据能够可靠地到对面,但是由于对方接收数据能力实在太差,上层应用数据处理慢,导致对端接收缓冲区已被打满,此时不能再接收到新的数据,而新的数据因此会被丢弃!

        显然,这也是我们不能容忍的!所以,发送数据的需要考虑的条件又得增加一条,

        你得考虑 "对端的接收能力"。你说,那我们怎么知道对端的缓冲区大小呢?答案其实是我们当然知道!

        在双方进行通信前,“三次握手” 就可以确定双方各自的 "窗口大小"。这里又提到"窗口大小",前面又提到tcp控制层的缓冲区,到底这是啥呀?

    

建模一:

 

         这里就会提出几个滑动窗口的问题:
        ● 滑动窗口是怎样设定的?

 

       ● 滑动窗口未来是如何变化的? 会变大嘛?会变小嘛?

        这里仅仅是讨论了滑动窗口两端边界的情况,有没有一种可能,发送端收到了中间的应答,没有收到win_start的应答呢? 

丢包情况:
        ● 数据收到了,但是ACK应答丢了。

        ● 数据真的丢了。

        如果遇到只收到了中间的应答,但是没有收到左侧发送报文的应答这种情况,其实完完全全不用慌张,因为确认应答机制的定义是: 确认序号之前的内容,全部被对端收到了。

        因此,即便你没有收到ACK_start,但是因为收到了ack_mid,你也就可以断定你左侧的报文数据是让对端收到了的。

        此时只需将滑动窗口的win_start 滑动到确认序号处即可。

        ● 滑动窗口必须滑动嘛?会不会不动?或者变为0? 

建模二:

(5) 拥塞控制

        虽然TCP有了滑动窗口这个大杀器, 能够高效可靠的发送大量的数据. 但是如果在刚开始阶段就发送大量的数据, 仍然可能引发问题。你可得记住,网络中可不止有你一台主机可以发起请求,如果当前的网络状态就已经比较拥堵,如果贸然发送大量的数据,是很有可能引起雪上加霜的。        
        你不是有超时重传嘛? 到时候传不就得了?可是,你是tcp有超时重传,他也是tcp有超时重传,大家普遍使用的都是tcp传输控制协议,发现丢包后都进行超时重传,这样不管重传多少次,已经出现问题的网络,又会增加更多的报文,只会加重网络的故障!

        因此,面对这样的情况,如果你有很大的文件传输没有收到应答,还应该重传嘛?答案是 不应该,不应该大量地传!

拥塞窗口:

        此时引入一个拥塞窗口的概念,发送开始的时候, 定义拥塞窗口大小为1,每次收到一个ACK应答, 拥塞窗口加1。
        有了上面的场景,我们就不得不再一次更正我们认知的发送数据方不仅仅要考虑对端是否呢个接收到,还得考虑网络的情况。

        窗口大小 = 对端接收窗口大小

        窗口大小 = Min(对端反馈的窗口大小,拥塞窗口大小)
 

         妈耶,你这样看那拥塞窗口增长的怕是有点慢诶,反而因为多发小报文导致tcp通信效率的降低。

慢启动:

        真实的拥塞窗口增值是指数级别的,所谓的 "慢启动",仅仅是刚开始的时候发送的报文少,一旦检测到网络状况良好后,增长速度是很快的。

        考虑到当增长速度快时,有可能导致网络出现拥塞的状况,通常会设置一个 “慢启动阈值”,一旦发送的报文大小超过了阈值,此时的增长就会 按线性递增,减缓增长速度。

         如果发生少量的丢包,那么重传的成本似乎并不大,也不会对加重网络拥塞的问题。

        当TCP通信开始后, 网络吞吐量会逐渐上升; 随着网络发生拥堵, 吞吐量会立刻下降;
        拥塞控制, 归根结底是TCP协议想尽可能快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案.

      


三、 TCP效率优化

(1) 延迟应答

        如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小。

        其实说白了就是,你可以等待一定的时间给客户端进行ack应答,在这个时间段里,你的上层逻辑可能可以取走更多的数据,那么此时你能响应的ack窗口就会增加。

        窗口越大,网络的吞吐量也就越大,传输的效率也就会越高。当然,这个大前提是 保证网络不拥塞。

(2) 捎带应答

        我们可以发现,在tcp建立连接时,第二次握手是 ACK+SYN,而在四次挥手时,反而是将ACK与FIN分开进行发放。因为有时候也会提到 四次挥手可否改为三次?答案是可以的,因为这一次ACK+FIN可以通过捎带应答一起发送给主动断开连接的一方。

 

(3) 滑动窗口     

        没想到吧,这儿还有我。

        我们都知道TCP是面向字节流的,而UDP是面向数据报的。一个很明显的特征是,对于UDP而言是会携带有效载荷的大小的,而UDP读取报文也是一个一个读,要么读成功要么读不成功,不会出现把报文读了一半的情况。

        创建一个TCP的socket, 同时操作系统会在内核中创建一个发送缓冲区和一个接收缓冲区。当上层数据要发送数据时,需要使用系统调用接口write将数据拷贝到内核缓冲区当中,在TCP看来,这些所谓的上层数据,就是一个一个的字节!至于什么时候法就与上层业务逻辑无关了,因为这是由TCP自己决定!

        ● 如果发送的字节数太长, 会被拆分成多个TCP的数据包发出;

        ● 如果发送的字节数太短, 就会先在缓冲区里等待, 等到缓冲区长度差不多了, 或者其他合适的时机发送出去;
        而最终控制这个收发数据的多少的,就是滑动窗口!发多更好还是发少更好?都不如发合适最好,控制的含义不仅仅关于 限制,也可能是放开。滑动窗口可以在网络通畅,对方接收数据能力强的时候多发数据,也可以在网路出现问题,对方处理数据能力弱的情况下少发数据,从而保证数据传输的可靠,另一层面也提高了TCP通信的效率。

        所以,udp协议通信效率一定高于tcp嘛?那可不一定。

四、TCP异常

        下面有几种状态:

        ● Client进程或者Server进程挂掉

        ● 电脑关机

        ● 被拔网线或者断电

        面对这些情况,tcp连接是如何进行处理的呢?

        学过系统的都知道,一旦一个进程退出或者异常崩溃,那么操作系统会将其开辟但未来得及释放的堆空间资源进行管理释放,同样如果上述Client或者Server端进程挂掉,该进程的系统资源都会经由操作系统进行管理释放掉。对于 ”电脑关机",很多时候如果你的电脑运行了很多程序,此时你选择关机,系统其实会提醒你 存在下面的一些进程还在运行,其实本质上是在等操作系统将这些进程杀掉,清理其申请的资源,所以它的情况和第一种无差别。

        通过tcp的连接管理机制我们知道,断开连接是需要双方都同意的!但此时如果你网线已经被拔了,你还怎么想服务端发送FIN字段报文?肯定不行。那么此时,服务端一定还是认为客户端存在的。维护一条压根不存在的连接,显然这个负担服务器是不能容忍的。

TCP自己也内置了保活定时器,会定期询问对方是否还在.如果对方不在,会把连接释放。

另外, 应用层的某些协议, 也有一些这样的检测机制. 例如HTTP长连接中, 也会定期检测对方的状态. 例如QQ, 在QQ断线之后, 也会定期尝试重新连接。

 


TCP总结:

为什么TCP这么复杂? 因为要保证可靠性, 同时又尽可能的提高性能.
可靠性:

● 校验和
● 序列号(按序到达)
● 确认应答
● 超时重发
● 连接管理
● 流量控制
● 拥塞控制

提高性能:

● 滑动窗口
● 延迟应答
● 捎带应答

基于TCP应用层协议HTTP、HTTP、SSH、Telnet、FTP、SMTP……

本篇到此结束,感谢你的阅读

祝你好运,向阳而生~

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

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

相关文章

前端vue入门(纯代码)21_vuex

努力不一定成功,但是,不努力一定很轻松!!! 【23.Vuex】 [可以去官网看看Vuex3文档](Vuex 是什么? | Vuex (vuejs.org)) 问题1:Vuex是什么? 【官方理解1】:Vuex 是一个专…

vue中的.env全局配置

关于文件名: .env 全局默认配置文件,不论什么环境都会加载合并 .env.development 开发环境下的配置文件 .env.production 生产环境下的配置文件 .env文件配置: 我这里要讲的env配置是用启动命令启动项目来配置不同的全局变量 我配置了两…

十七、Jenkins(centos7系统)运行python3代码

十七、Jenkins(centos7系统)运行python3代码 source /usr/python/envs/everyday/bin/activate #激活python3 虚拟环境 创建虚拟环境:https://blog.csdn.net/qq_42846555/article/details/131579627 source /usr/python/envs/everyday/bin/activate #激活python3 虚…

自我介绍,千万别来虚的!

大家好,我是鲏。 已经帮小伙伴改了 500 多份简历了,也发现了一些大家写简历时的共性问题。其中让我印象比较深刻的一个点就是 自我介绍 ,基本上所有同学的自我介绍都是这么写的: 读这篇文章的朋友们,你是不是也是这么…

困于“耐用焦虑”的绿源,还在歧路徘徊?

老牌两轮电动车品牌绿源上市之旅“多歧路”。 日前,北京市市场监督管理局公布北京市电动自行车产品质量监督抽查结果,绿源两款电动自行车因存在问题被点名,充电器和蓄电池、整车质量、控制系统等不符合标准。 而在此前,绿源还向港…

秒懂算法 | 围棋中的Alpha-Beta剪枝算法

01、Alpha-Beta剪枝算法 极小化极大算法会遍历所有的可能性,但是根据经验可以知道,并不是所有的选项都需要进行深入的考虑,存在着某些明显不利的选项,当出现这种选项时就可以换一种思路进行考虑了。Alpha-Beta剪枝算法的出现正是…

网络投票平台发起投票平台投票吧网络投票平台

小程序投票活动如何做?很多企业在运营当中,都会通过投票活动来进行推广,从而达到吸粉、增加用户粘度等效果。而此类投票活动,通过小程序就可以实现,操作简单。 我们现在要以“青春大不同”为主题进行一次投票活动&…

系统架构设计师-软件工程(3)

一、软件系统建模 1、结构化建模方法 结构化建模方法是以过程为中心的技术,可用于分析一个现有系统以及定义新系统的业务需求。结构化建模方法所绘制的模型称为数据流图(DFD)。对于流程较为稳定的系统可考虑结构化建模方法。 2、信息工程建模…

linux中的目录文件都是用来做什么的

1、linux目录系列 - /bin、/sbin目录 我们平时使用的一些命令,是以2进制的格式存放在bin目录下面。例如:cat、chmod、chown、cp、date、find、gzip、kill、ln、ls、mount、mv、ping、pwd、rm、su、tar、vi等。/sbin下存放的是超级用户权限的系统指令。主要放置一些系…

Python采集双色球历史开奖信息,看看哪个号中奖概率更大

目录标题 前言知识点:开发环境:基本流程:代码展示尾语 前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 知识点: 爬虫基本流程 requests的使用 动态数据抓包 开发环境: 解释器: python 3.8 编辑器: pycharm 2022.3 requests >>> pip install requests 第三…

Jenkins邮件配置报错com.sun.mail.smtp.SMTPSenderFailedException: 501

Jenkins邮件配置,配置完成各种信息之后,“通过发送测试邮件测试配置”点击Test configuration,报错 1、报错信息 com.sun.mail.smtp.SMTPSenderFailedException: 501 mail from address must be same as authorization userat com.sun.mail…

ARM_异常处理流程_编写软中断swi验证保存现场和恢复现场

keil .text .global _start _start:1.构建异常向量表b resetb undefb software_interruptb prefetch_abortb data_abortb .b irqb fiq reset:系统上电之后处于svc模式初始化svc模式下的栈指针ldr sp,0x400008002.从SVC模式切换到user模式 msr cpsr,#0xD0mrs r0,cpsrorr r0,r0,…

C#(五十四)之线程Mutex互斥

Mutex(互斥体): 排他性的使用共享资源称为线程间的互斥。 使用Mutex类要比使用monitor类消耗更多的系统资源,但他可以跨越多个应用程序,在多个应用程序间同步。 构造函数 Mutex() 使用默认属性初始化 Mutex 类的新…

算法与数据结构(六)

一、图 一、临接表 表示方法如下: 带权值的无向图的构建: #define MaxInt 32767 // 极大值 #define MVNum 100 // 最大定点数 typedef int ArcType; // 边的权值类型 typedef char VerTexType; // 顶点数据类型//弧(边)的结点结构 st…

adb: failed to install .\xxxxxx.apk: Failure [INSTALL_FAILED_USER_RESTRICTED

开发者模式和USB调试均已打开,adb安装时报错。看了一下,小米手机还需要开启USB安装才行。 问题已解决

注册-Springboot整合邮件发送

1.QQ邮箱开启服务 获取授权码 2.在配置文件进行相关配置 spring:mail:host: smtp.qq.comport: 587username: xxxpassword: xxxdefault-encoding: utf-8properties:mail:smtp:connectiontimeout: 5000timeout: 3000writetimeout: 5000 3.读取配置类 /*** 读取yml配置文件里面…

乞丐版的四层负载均衡,你了解多少?

大家好,我是蓝胖子,做开发的同学应该经常听到过负载均衡的概念,今天我们就来实现一个乞丐版的四层负载均衡,并用它对mysql进行负载均衡测试,通过本篇你可以了解到零拷贝的应用,四层负载均衡的本质以及实践。…

深入解析Redis的LRU与LFU算法实现

作者:vivo 互联网服务器团队 - Luo Jianxin 重点介绍了Redis的LRU与LFU算法实现,并分析总结了两种算法的实现效果以及存在的问题。 一、前言 Redis是一款基于内存的高性能NoSQL数据库,数据都缓存在内存里, 这使得Redis可以每秒轻…

矩阵的压缩存储

本文主要内容:本文主要介绍几种特殊矩阵的压缩存储。特殊矩阵指具有许多相同矩阵元素或零元素,并且这些相同矩阵元素的分布有一定规律性的矩阵,常见的特殊矩阵有对称矩阵、上(下)三角矩阵、对角矩阵等。压缩存储指为多…

Vite按需引入自定义组件unplugin-vue-components

1.安装插件 npm i unplugin-vue-components -D 2.vite.config.ts文件加如下代码 plugins: [vue({reactivityTransform: true}),Components({extensions: [vue, md],include: [/\.vue$/, /\.vue\?vue/, /\.md$/],dts: src/components.d.ts,deep: true, // 搜索子目录dirs: [s…