tcp的无延时发送_高并发架构的TCP知识介绍

这是关于高并发架构网络协议基础知识的第二篇,编程路上的基础心法!

做为一个有追求的程序员,不能只满足增删改查,我们要对系统全方面无死角掌控。掌握了这些基本的网络知识后,相信一方面日常排错中会事半功倍,另一方面日常架构中不得不考虑的高并发问题,理解了这些底层协议也是会如虎添翼。

本文不会单纯给大家讲讲TCP三次握手、四次挥手就完事了。如果只是哪样的话,我直接贴几个连接就完事了。我希望把实际工作中的很多点能够串起来讲给大家。当然为了文章完整,我依然会从 三次握手 起头。

再说TCP状态变更过程

不管是三次握手、还是四次挥手,他们都是完成了TCP不同状态的切换。进而影响各种数据的传输情况。下面从三次握手开始分析。

本文图片有部分来自网络,若有侵权,告知即焚

三次握手

来看看三次握手的图,估计大家看这图都快看吐了,不过为什么每次面试、回忆的时候还是想不起呢?我再来抄抄这锅剩饭吧

9baeab0a5bb8209ce090df81d97bd25c.png

首先当服务端处于 listen 状态的时候,我们就可以再客户端发起监听了,此时客户端会处于 SYN_SENT 状态。服务端收到这个消息会返回一个 SYN 并且同时 ACK 客户端的请求,之后服务端便处于 SYN_RCVD 状态。这个时候客户端收到了服务端的 SYN&ACK,就会发送对服务端的 ACK,之后便处于 ESTABLISHED 状态。服务端收到了对自己的 ACK 后也会处于 ESTABLISHED 状态。

经常在面试中可能有人提问:为什么握手要3次,不是2次或者4次呢?

首先说4次握手,其实为了保证可靠性,这个握手次数可以一直循环下去;但是这没有一个终止就没有意义了。所以3次,保证了各方消息有来有回就足够了。当然这里可能有一种情况是,客户端发送的 ACK 在网络中被丢了。那怎么办?

  1. 其实大部分时候,我们连接建立完成就会立刻发送数据,所以如果服务端没有收到 ACK 没关系,当收到数据就会认为连接已经建立;

  2. 如果连接建立后不立马传输数据,那么服务端认为连接没有建立成功会周期性重发 SYN&ACK 直到客户端确认成功。

再说为什么2次握手不行呢?2次握手我们可以想象是没有三次握手最后的 ACK, 在实际中确实会出现客户端发送 ACK 服务端没有收到的情况(上面的情况一),那么这是否说明两次握手也是可行的呢?
看下情况二,2次握手当服务端发送消息后,就认为建立成功,而恰巧此时又没有数据传输。这就会带来一种资源浪费的情况。比如:客户端可能由于延时发送了多个连接情况,当服务端每收到一个请求回复后就认为连接建立成功,但是这其中很多求情都是延时产生的重复连接,浪费了很多宝贵的资源。

因此综上所述,从资源节省、效率3次握手都是最合适的。话又回来三次握手的真实意义其实就是协商传输数据用的:序列号与窗口大小

下面我们通过抓包再来看一下真实的情况是否如上所述。

123
20:33:26.583598 IP 192.168.0.102.58165 > 103.235.46.39.80: Flags [S], seq 621839080, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1050275400 ecr 0,sackOK,eol], length 020:33:26.660754 IP 103.235.46.39.80 > 192.168.0.102.58165: Flags [S.], seq 1754967387, ack 621839081, win 8192, options [mss 1452,nop,wscale 5,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,sackOK,eol], length 020:33:26.660819 IP 192.168.0.102.58165 > 103.235.46.39.80: Flags [.], ack 1754967388, win 4096, length 0

抓包: sudo tcpdump -n host www.baidu.com -S

  • S 表示 SYN

  • . 表示 ACK

  • P 表示 传输数据

  • F 表示 FIN

四次挥手

挥手,就是说数据传完了,同志们再见!

1039a4a327180d97991d0cdbf472ae8e.png

这里有个问题需要注意下,其实客户端、服务端都能够主动发起关闭操作,谁调用 close() 就先发送关闭的请求。当然一般的流程,发起建立连接的一方会主动发起关闭请求(http中)。

关于4次挥手的过程,我就不多解释了,这里有两个重要的状态我需要解释下,这都是我亲自经历过的线上故障,close_wait 与 time_wait

先给大家一个命令,统计tcp的各种状态情况。下面表格内容就来自这个命令的统计。

netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’

Tcp状态连接数
CLOSE_WAIT505
ESTABLISHED808
TIME_WAIT3481
SYN_SENT1
SYN_RECV1
LAST_ACK2
FIN_WAIT22
FIN_WAIT11


大量的CLOSE_WAIT
 这个在我之前的一篇文章 线上大量CLOSE_WAIT原因分析 已经有过介绍,它会导致大量的socket无法释放。而每个socket都是一个文件,是会占用资源的。这个问题主要是代码问题。它出现在被动关闭的一方(习惯称为server)。

大量的TIME_WAIT 这个问题在日常中经常看到,流量一高就出现大量的该情况。该状态出现在主动发起关闭的一方。该状态一般等待的时间设为 2MSL后自动关闭,MSL是Maximum Segment Lifetime,报文最大生存时间,如果报文超过这个时间,就会被丢弃。处于该状态下的socket也是不能被回收使用的。线上我就遇到这种情况,每次大流量的时候,每台机器处于该状态的socket就多达10w+,远远比处于 Established 状态的socket多的多,导致很多时候服务响应能力下降。这个一方面可以通过调整内核参数处理,另一方面避免使用太多的短链接,可以采用连接池来提升性能。另外在代码层面可能是由于某些地方没有关闭连接导致的,也需要检查业务代码。

上面两个状态一定要牢记发生在哪一方,这方便我们快速定位问题。

最后这里还是放上挥手时的抓包数据:

1234
20:33:26.750607 IP 192.168.0.102.58165 > 103.235.46.39.80: Flags [F.], seq 621839159, ack 1754967720, win 4096, length 020:33:26.827472 IP 103.235.46.39.80 > 192.168.0.102.58165: Flags [.], ack 621839160, win 776, length 020:33:26.827677 IP 103.235.46.39.80 > 192.168.0.102.58165: Flags [F.], seq 1754967720, ack 621839160, win 776, length 020:33:26.827729 IP 192.168.0.102.58165 > 103.235.46.39.80: Flags [.], ack 1754967721, win 4096, length 0

不多不少,刚好4次。

TCP状态变更

网络上有一张TCP状态机的图,我觉得太复杂了,用自己的方式搞个简单点的容易理解的。我从两个角度来说明状态的变更。

  • 一个是客户端

  • 一个是服务端

看下面两张图的时候,请一定结合上面三次握手、四次挥手的时序图一起看,加深理解。

客户端状态变更

d583c21ac8c010bc2419713a981d65f4.png

通过这张图,大家是否能够清晰明了的知道 TCP 在客户端上的变更情况了呢?

服务端状态变更

239ea15a82e034a99bfb751e310d2468.png

这一张图描述了 TCP 状态在服务端的变迁。

TCP的流量控制与拥塞控制

我们常说TCP是面向连接的,UDP是无连接的。那么TCP这个面向连接主要解决的是什么问题呢?

这里继续把三次握手的抓包数据贴出来分析下:

123
20:33:26.583598 IP 192.168.0.102.58165 > 103.235.46.39.80: Flags [S], seq 621839080, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1050275400 ecr 0,sackOK,eol], length 020:33:26.660754 IP 103.235.46.39.80 > 192.168.0.102.58165: Flags [S.], seq 1754967387, ack 621839081, win 8192, options [mss 1452,nop,wscale 5,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,sackOK,eol], length 020:33:26.660819 IP 192.168.0.102.58165 > 103.235.46.39.80: Flags [.], ack 1754967388, win 4096, length 0

上面我们说到 TCP 的三次握手最重要的就是协商传输数据用的序列号。那这个序列号究竟有些什么用呢?这个序号能够帮助后续两端进行确认数据包是否收到,解决顺序、丢包问题;另外我们还可以看到有一个 win 字段,这是双方交流的窗口大小,这在每次传输数据过程中也会携带。主要是告诉对方,我窗口是这么大,别发多了或者别发太少。

总结下,TCP的几个特点是:

  • 顺序问题,依靠序号

  • 丢包问题,依靠序号

  • 流量控制,依靠滑动窗口

  • 拥塞控制,依靠拥塞窗口+滑动窗口

  • 连接维护,三次握手/四次挥手

顺序与丢包问题

这个问题其实应该很好理解。由于数据在传输前我们已经有序号了,这里注意一下这个序号是随机的,重复的概率极地,避免了程序发生乱入的可能性。

由于我们每个数据包有序号,虽然发送与到达可能不是顺序的,但是TCP层收到数据后,可以根据序号进行重新排列;另外在这个排列过程中,发现有了1,2,3,5,6这几个包,一检查就知道4要么延时未到达,要么丢包了,等待重传。

这里需要重要说明的一点是。为了提升效率,TCP其实并不是收到一个包就发一个ack。那是如何ACK的呢?还是以上面为例,TCP收到了1,2,3,5,6这几个包,它可能会发送一个 ack ,seq=3 的确认包,这样次一次确认了3个包。但是它不会发送 5,6 的ack。因为4没有收到啊!一旦4延时到达或者重发到达,就会发送一个 ack, seq=6,又一次确认了3个包。

流量控制与拥塞控制

这两个概念说实话,让我理解了挺长时间,主要是对它们各自控制的内容以及相互之间是否有作用一直没有闹清楚。

先大概说下:

  • 流量控制:是根据接收方的窗口大小来感知我这次能够传多少数据给对方;—— 滑动窗口

  • 拥塞控制:而拥塞控制主要是避免网络拥塞,它考虑的问题更多。根据综合因素来觉得发多少数据给对方;—— 滑动窗口&拥塞窗口

举个例子说下,比如:A给B发送数据,通过握手后,A知道B一次可以收1000的数据(B有这么大的处理能力),那么这个时候滑动窗口就可以设置成1000。那是不是最后真的可以一次发这么多数据给B呢?还不是,这时候得问问拥塞窗口,老兄,现在网络情况怎么样?一次运1000的数据有压力吗?拥塞窗口一通计算说不行,现在是高峰期,最多只能有600的货上路。最终这次传数据的时候就是 600 的标注。大家也可以关注抓包数据的 win 值,一直在动态调整。

当然另外一种情况是滑动窗口比拥塞窗口小,虽然运输能力强,但是接收能力有限,这时候就要取滑动窗口的值来实际发生。所以它们二者之间是有关系的。

所以具体到每次能够发送多少数据,有这么一个公式:

LastByteSend - LastByteAcked <= min{cwnd,rwnd}

  • LastByteSend 是最后一个发送的字节的序号

  • LastByteAcked 最后一个被确认的字节的序号

这两个相减得到的是本次能够发送的数据,这个数据一定小于或等于 cwnd 与 rwnd 中最小的一个值。相信大家能够理清楚。

那么这部分知识对于实际工作中有什么作用呢?指导意义就是:如果你的业务很重要、很核心一定不要混布;二是如果你的服务忽快忽慢,而确信依赖服务没有问题,检查下机器对应的网络情况;三是窗口这个速度控制机制,在我们进行服务设计的时候,非常具有参考意义。是不是有点消息队列的感觉?(很多消息队列都是匀速的,我们是否可以加一个窗口的概念来进行优化呢?)

是什么限制了你的连接

到了最关键的地方了,精华我都是留到最后讲。下面放一张网上找的socket操作步骤图,画的太好了我就直接用了。

1ec8ec92fca3f35b6a053e58613f41fe.png

我们假设我的服务端就是 Nginx ,我来尝试解读一下。当客户端调用 connect() 时候就会发起三次握手,这次握手的时候有几个元素唯一确定了这次通信(或者说这个socket),[源IP:源Port, 目的IP:目的Port] ,当然这个socket还不是最终用来传输数据的socket,一旦握手完成后,服务端会在返回一个 socket 专门用来后续的数据传输。这里暂且把第一个socket叫 监听socket,第二个叫 传输socket 方便后文叙述。

为什么要这么设计呢?大家想一想,如果监听的socket还要负责数据的收发,请问这个服务端的效率如何提升?什么东西、谁都往这个socket里边丢,太复杂!

提高连接常用套路

到了这一步,我们现在先停下来算算自己的服务器机器能够有多少连接呢?这个极限又是如何一步步被突破呢?

先说 监听socket ,服务器的prot一般都是固定的,服务器的ip当然也是固定的(单机)。那么上面的结构 [源IP:源Port, 目的IP:目的Port] 其实只有客户端的ip与端口可以发生变化。假设客户端用的是IPv4,那么理论连接数是:2^32(ip数) * 2^16(端口数) = 2^48。

看起来这个值蛮大的。但是真的能够有这么多连接吗?不可能的,因为每一个socket都需要消耗内存;以及每一个进程的文件描述符是有上限的。这些都限制了最终的连接数。

那么如何进行调和呢?我知道的操作有:多进程、多线程、IO多路服用、协程等手段组合使用。

多进程

也就是监听是一个进程,一旦accept后,对于 传输socket 我们就fork一个新的子进程来处理。但是这种方式太重,fork一个进程、销毁一个进程都是特别费事的。单机对进程的创建上限也是有限制的。

多线程

线程比进程要轻量级的多,它会共享父进程的很多资源,比如:文件描述符、进程空间,它就是多了一个引用。因此它的创建、销毁更加容易。每一个 传输socket 在这里就交给了线程来处理。

但是不管是多进程、还是多线程都存在一个问题,一个连接对应一个进程或者协程。这都很难逃脱 C10K 的问题。那么该怎么办呢?

IO多路复用

IO多路复用是什么意思呢?在上面单纯的多进程、多线程模型中,一个进程或线程只能处理一个连接。用了IO多路复用后,我一个进程或线程就能处理多个连接。

我们都知道 Nginx 非常高效,它的结构是:master + worker,worker 会在 80、443端口上来监听请求。它的worker一般设置为 cpu 的cores数,那么这么少的子进程是如何解决超多连接的呢?这里其实每个worker就采用了 epoll 模型(当然IO多路复用还有个select,这里就不说了)。

处于监听状态的worker,会把所有 监听socket 加入到自己的epoll中。当这些socket都在epoll中时,如果某个socket有事件发生就会立即被回调唤醒(这涉及epoll的红黑树,讲不清楚不细说了)。这种模式,大大增加了每个进程可以管理的socket数量,上限直接可以上升到进程能够操作的最大文件描述符。

一般机器可以设置百万级别文件描述符,所以单机单进程就是百万连接,epoll是解决C10K的利器,很多开源软件用到了它。

这里说下,并不是所有的worker都是同时处于监听端口的状态,这涉及到nginx惊群、抢自旋锁的问题,不再本文范围内不多说。

关于ulimit

在文章的最后,补充一些单机文件描述符设置的问题。我们常说连接数受限于文件描述符,这是为什么?

因为在linux上一切皆文件,故每一个socket都是被当作一个文件看待,那么每个文件就会有一个文件描述符。在linux中每一个进程中都有一个数组保存了该进程需要的所有文件描述符。这个文件描述符其实就是这个数组的 key ,它的 value 是一个指针,指向的就是打开的对应文件。

关于文件描述符有两点注意:

  1. 它对应的其实是一个linux上的文件

  2. 文件描述符本身这个值在不同进程中是可以重复的

另外补充一点,单机设置的ulimit的上线受限与系统的两个配置:

fs.nr_open,进程级别

fs.file-max,系统级别

fs.nr_open 总是应该小于等于 fs.file-max,这两个值的设置也不是随意可以操作,因为设置的越大,系统资源消耗越多,所以需要根据真实情况来进行设置。


至此,本篇长文就完结了。这跟上篇 高并发架构的CDN知识介绍 属于一个系列,高并发架构需要理解的网络基础知识。

后面还会写一下 HTTP/HTTPS 的知识。然后关于高并发网络相关的东西就算完结。我会开启下一个篇章。


如果你想对网络协议了解更多,推荐一个课程:

11a3b6d3af82027198b9cc306f4d78b5.png

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

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

相关文章

如何对一个变量数据进行正则判定_生存分析数据中的BuckleyJamesMultipleRegression Model...

一、模型简介目前&#xff0c;生存分析领域&#xff0c;最常用的是Cox比例风险回归模型&#xff0c;该模型具有良好的特性&#xff0c;不仅可以分析各种自变量对生存时间的影响&#xff0c;而且对基准风险分布不作任何要求(半参数模型)。Cox模型使用时要满足一定的条件&#xf…

格兰杰因果关系检验r语言_R语言系列第四期:R语言单样本双样本差异性检验

之前详细介绍了利用R语言进行统计描述&#xff0c;详情点击&#xff1a;R语言系列第三期&#xff1a;①R语言单组汇总及图形展示、R语言系列第三期&#xff1a;②R语言多组汇总及图形展示、R语言系列第三期&#xff1a;③R语言表格及其图形展示从这个部分我们就开始为大家介绍统…

java 配置jmstemplate_SpringBoot集成JmsTemplate(队列模式和主题模式)及xml和JavaConfig配置详解...

1.导入jar包&#xff1a;org.springframework.bootspring-boot-starter-activemqorg.apache.activemqactivemq-pool2.填写配置文件(application.properties)#设置JMS(AMQ)spring.activemq.broker-urltcp://localhost:61616spring.activemq.useradminspring.activemq.passwordad…

切面是异步还是同步操作‘_分布式中采用Logback的MDC机制与AOP切面结合串联日志...

导读&#xff1a;在实际开发中&#xff0c;打印日志是十分重要的。在生产环境中&#xff0c;如果日志打得好可以快速地排查问题&#xff0c;而在分布式的场景下&#xff0c;一个请求会跨越多个节点&#xff0c;既一个业务可能需要多个节点协调配合处理。那么日志将会分散&#…

java 图类_Java集合类,一张图说清楚!

作者&#xff1a;skywang12345https://www.cnblogs.com/skywa...2019-03-23 10:32:24Java集合是java提供的工具包&#xff0c;包含了常用的数据结构&#xff1a;集合、链表、队列、栈、数组、映射等。Java集合工具包位置是java.util.*&#xff0c;Java集合主要可以划分为4个部分…

python 取整_马克的Python学习笔记#数字,日期和时间

对数值进行调整在Python中对整数和浮点数进行数字计算是很容易的。但是&#xff0c;如果你需要对分数&#xff0c;数组或者日期和时间进行计算&#xff0c;这就会稍微复杂点。对于简单的取整操作&#xff0c;我们可以使用内建的round(value, ndigits)函数就可&#xff0c;举个例…

各路由协议的协议号_厂房转让协议

厂房转让协议转让方(甲方)&#xff1a;________________受让方(乙方)&#xff1a;________________甲乙双方本着平等互利的原则&#xff0c;经协商一致就甲方将其权属的工业用地、厂房等转让与乙方及有关事项达成如下协议:一、工业用地及厂房产权基本情况本协议转让的工业用地位…

java web开发常见问题_JavaWeb学习笔记(五)--Web开发其他常见问题

一、把web应用打成war包使用JDK自带jar命令&#xff0c;进入到web应用里面&#xff0c;执行命令&#xff1a;jar -cvf 包名.war . # .表示当前目录所有的文件 直接用jar可查看帮助执行完成后生成一个demo.war文件&#xff0c;把这个文件拷贝到Tomcat的webapps下&#xff0c;Tom…

uwsgi怎么通过浏览器访问某个脚本_4个Shell小技巧帮你提高机器学习效率:写好脚本,事半功倍...

晓查 发自 凹非寺 量子位 报道 | 公众号 QbitAI在机器学习的实践过程中&#xff0c;用好Shell能帮你很多节省时间。最近&#xff0c;有位来自ETHZ的学生分享了一些Shell小技巧。对程序员来说&#xff0c;这些技巧更重要的是让你的思维从琐碎小事中解脱出来&#xff0c;大大提高…

间接寻址级别不同_被遗忘的利息税,国债与存款的利率区别,同大额存单的4点大不同...

2020年6月10日的储蓄式电子国债发行又一次与理财人擦肩而过&#xff0c;因为疫情管控原因&#xff0c;此次暂时不发行&#xff0c;那么下一个认购国债的窗口&#xff0c;就是7月10日&#xff0c;仍然是储蓄式电子国债&#xff0c;期限还是3年期和5年期两种。那么能如期发行吗&a…

抽象类可以用new创建对象吗_宠物可以用人类的湿巾吗?猫咪有泪痕可以用纸巾擦掉吗?...

宠物还有专用的湿巾&#xff1f;当然喽&#xff01;不养宠物的小伙伴可能是无法理解的&#xff0c;人类的生活条件好了&#xff0c;宠物的生活条件在很多方面比人类还更上一层台阶呢&#xff01;喜欢逛宠物店和宠物展的小伙伴都会有这样的感慨&#xff0c;那就是人生不如喵生狗…

java什么时候需要同步_JAVA中线程在什么时候需要同步和互斥

JAVA中线程在什么时候需要同步和互斥关注:265 答案:6 mip版解决时间 2021-01-27 08:10提问者时光易老2021-01-27 03:32JAVA中线程在什么时候需要同步和互斥?(假如这题是考试题&#xff0c;要怎样回答&#xff1f;)详细点最佳答案二级知识专家樱花雨梦2021-01-27 04:13例如访…

5g虚拟技术旅游_5G造就文旅新时代,驴迹科技探索智慧出行创新领域

随着我国5G技术的成熟与普及&#xff0c;5G为文旅产业提供新的解决方案&#xff0c;使之焕发新的活力。以5G“新基建”为依托&#xff0c;结合VR虚拟实境以及云计算、高清视频等技术交叉应用&#xff0c;对旅游业的发展带来广泛而深刻的影响&#xff0c;给游客更新鲜、更具有科…

分块排序算法 java_十大经典排序算法最强总结(含JAVA代码实现)

转载自&#xff1a;https://www.cnblogs.com/guoyaohua/p/8600214.html0、排序算法说明0.1 排序的定义对一序列对象根据某个关键字进行排序。0.2 术语说明稳定&#xff1a;如果a原本在b前面&#xff0c;而ab&#xff0c;排序之后a仍然在b的前面&#xff1b;不稳定&#xff1a;如…

synchronized锁升级_synchronized详解以及锁的膨胀升级过程

点击上方"码之初"关注&#xff0c;选择"设为星标"与精品技术文章不期而遇来源&#xff1a;www.cnblogs.com/cxiaocai/p/12189848.html架构之路远且艰辛&#xff0c;但是学习的脚步始终不能停止&#xff0c;今天聊一聊synchronized。synchronized是jvm内部的…

改变php二维数组的值_php如何修改二维数组中的值?

php修改二维数组中值的方法&#xff1a;1、通过【for($i 0; $i < count(Array()); $i)】语句修改&#xff1b;2、通过foreach($users as &$user)语句修改。php修改二维数组中值的方法&#xff1a;1、二维数组可以通过for($i 0; $i < count(Array()); $i)这种形式…

jlabel字怎么变化_怎样才能把字写好?详解最科学的练字方法及步骤

一&#xff1a;正确的学习之路1&#xff1a;临帖从古到今&#xff0c;临帖是学习书法最基本的方法&#xff0c;没有一个书法家是没有临过帖的。2&#xff1a;专注专注学一个书法家的字&#xff0c;专心致志&#xff0c;认真临写&#xff0c;持之以恒&#xff0c;直到形同神似。…

找不到具有指定id_JAVA如何整合es指定字段不分词搜索?

一、问题在做一个需求的时候&#xff0c;需要按照电话号码查询用户关系&#xff0c;所以我这边先讲相关信息同步到es&#xff0c;但是电话号码是加密的&#xff0c;所以显示的字符串是杂乱的&#xff0c;既有字母&#xff0c;又有斜杠等号等字符&#xff0c;在进行分词查询的时…

vant 项目_vueCli4+vant+router+vuex+移动端适配

教程的开始 各位同学请先安装node、npm、vuecli4 巴拉巴拉...废话不多说立即开始随便找个地方 cmd&#xff0c;powerShell也可以 命令行走起1. 创建vue项目 随便起个名字就叫my-vue吧&#xff0c;傻瓜式回车键就行&#xff0c;也可以根据自己的喜好选择eslint。vue create my-v…

电路结构原理_精密半波、全波整流电路结构原理图解

利用二极管(开关器件)的单向导电特性&#xff0c;和放大器的优良放大性能相结合&#xff0c;可做到对输入交变信号(尤其是小幅度的电压信号)进行精密的整流&#xff0c;由此构成精密半波整流电路。若由此再添加简单电路&#xff0c;即可构成精密全波整流电路。二极管的导通压降…