计算机网络 自顶向下
HTTP
HTTP主要有1.0、1.1、2三个版本,在HTTP之上有HTTPS
1996年,HTTP 1.0协议规范RFC1945发布;
1999年,HTTP 1.1协议规范RFC 2616发布;
2015年,HTTP/2协议规范RFC 7540/7541发布。
HTTP/2还比较新,目前远没有达到普及的程度。在过去的近20年间,主流的协议一直是HTTP 1.1。
HTTP1.0的典型特征
1.明文的、文本协议,而不是2进制协议,人可以直接看懂协议内容。
2.“一来一回”。什么意思呢?客户端发起一个TCP连接,在连接上面发一个HTTP Request到服务器,服务器返回一个HTTP Response,然后连接关闭。每来一个请求,就要开一个连接,请求完了,连接关闭。
HTTP1.0的典型问题
(1)性能问题。连接的建立、关闭都是耗时操作。对于一个网页来说,除了页面本身的HTML请求,页面里面的JS、css、img资源,都是一个个的HTTP请求。现在的互联网上的页面,一个页面上有几十个资源文件是很常见的事。每来一个请求就开一个TCP连接是非常耗时的。虽然可以同时开多个连接,并发地发送请求,但连接数毕竟是有限的。
(2)服务器推送问题。不支持“一来多回”,服务器无法在客户端没有请求的情况下主动向客户端推送消息。但很多的应用恰恰都需要服务器在某些事件完成后主动通知客户端。
重开连接的性能问题: Keep Alive机制
1.客户端在HTTP请求的头部加上一个字段Connection: Keep-Alive。服务器收到带有这样字段的请求,在处理完请求之后不会关闭连接,同时在HTTP的Response里面也会加上该字段,然后等待客户端在该连接上发送下一个请求。
2.这会给服务器带来一个问题:连接数有限。如果每个连接都不关闭的话,一段时间之后,服务器的连接数就耗光了。因此,服务器会有一个Keep-Alive timeout参数,过一段时间之后,如果该连接上没有新的请求进来,则连接就会关闭。
3.连接复用之后又产生了一个新问题:以前一个连接就只发送一个请求,返回一个响应,服务器处理完毕,把连接关闭,这个时候客户端就知道连接的请求处理结束了。但现在,即使一个请求处理完了,连接也不关闭,那么客户端怎么知道这个http请求处理结束了呢?或者说,客户端怎么知道接收回来的数据包是完整的呢?答案是在HTTP Response的头部,返回了一个Content-Length: xxx的字段,这个字段可以告诉客户端HTTP Response的Body共有多少个字节,客户端接收到这么多个字节之后,就知道响应成功接收完毕。
HTTP1.1
1.keep-alive变成缺省机制
所以到了HTTP1.1之后,就把连接复用变成了一个默认属性。即使不加Connection:Keep-Alive属性,服务器也会在请求处理完毕之后不关闭连接。
除非在请求头部显示地加上Connection:Close属性,服务器才会在请求处理完毕之后主动关闭连接。
2.除了content-length机制,又引入了chunk机制
Content-Length有个问题:如果服务器返回的数据是动态语言生成的内容,则要计算Content-Length,这点对服务器来说比较困难。即使能够计算,也需要服务器在内存中渲染出整个页面,然后计算长度,非常耗时。
为此,在HTTP 1.1中引用了Chunk机制
( Http Streaming)。具体来说,就是在响应的头部加上Transfer-Encoding: chunked属性,其目的是告诉客户端,响应的Body是分成了一块块的,块与块之间有间隔符,所有块的结尾也有个特殊标记。这样,即使没有Content-Length字段,也能方便客户端判断出响应的末尾。
3.Pipeline机制
虽然有了连接复用机制,但在同一个连接上,请求是串行的,客户端发送一个请求,收到响应,然后发送下一个请求,再收到响应。这种串行的方式,导致并发度不够。
为此,HTTP 1.1引入了Pipeline机制。在同一个TCP连接上面,可以在一个请求发出去之后、响应没有回来之前,就可以发送下一个、再下一个请求,这样就提高了在同一个TCP连接上面的处理请求的效率。
Pipeline机制的问题: Head-of-line Blocking(队头阻塞)
客户端发送的请求顺序是1、2、3,虽然服务器是并发处理的,但客户端接收响应的顺序必须是1、2、3,如此才能把响应和请求成功配对,跟队列一样,先进先出。
一旦队列头部请求l发生延迟,客户端迟迟收不到请求1的响应,则请求2、请求3的响应也会被阻塞。如果请求2、请求3不和请求1在一个TCP连接上面,而是在其他的TCP连接上面发出去的话,说不定响应早返回了,现在因为请求1处理得慢,也影响了请求2、请求3。
4 http性能优化技术
因为队头阻塞问题,Pipeline不能用;另一方面,对于同一个域名,浏览器限制只能开6~8个连接。
但一个网页可能要发几十个HTTP请求,却只有6~8个连接可用。
如何提高
网页渲染的性能呢?
(1) Spriting技术
这种技术专门针对小图片,假设在一个网页里,要从服务器加载很多的小图片(比如各种小图标),可以在服务器里把小图片拼成一张大图,到了浏览器,再通过JS或者CSS,从大图中截取一小块显示。
(2)内联(Inlining)
内联是另外一种针对小图片的技术,它将图片的原始数据嵌入在CSS文件里面,如下所示:
(3)JS拼接
把大量小的JS文件合并成一个文件并压缩(前端开发工具很容易实现),让浏览器在一个请求里面下载完。
(4)请求的分片技术
前面说了,对于一个域名,浏览器会限制只能开6~8个连接。对于网站的开发者来说,要提高页面的加载速度,其中的一个方法就是多做几个域名,这就相当于绕开了浏览器的限制。
尤其是现在CDN用得非常广泛,网站的静态资源(img,js, css)可能都在CDN上面,可以做一批CDN的域名,这样浏览器就可以为每个域名都建立6~8个连接,从而提高页面加载的并发度。
5.如何实现“一来多回”?
对于Web来说,无论HTTP 1.0,还是HTTP1.1,都无法直接做到服务器主动推送,但实际又有很多这样的需求存在,应该怎么解决呢?下面列举了几种方法:
客户端定期轮询
比如客户端每5s向服务器发送一个HTTP请求,服务器如果有新消息,就返回。定期轮询的方式既低效,又增加了服务器的压力,现在已经很少采用。
FlashSocket/WebSocket
不再是HTTP,而是直接基于TCP,但也有一定的局限性,此处不再展开。
HTTP长轮询
客户端发送一个HTTP请求,如果服务器有新消息,就立即返回;如果没有,则服务器夯住此连接,客户端一直等该请求返回。然后过一个约定的时间之后,如果服务器还没有新消息,服务器就返回一个空消息(客户端和服务器约定好的一个消息)。客户端收到空消息之后关闭连接,再发起一个新的连接,重复此过程。这就相当于变相地用HTTP实现了TCP长连接效果,这也是目前Web最常用的服务器端推送方法。
HTTP Streaming
如上面所说,服务器端利用Transfer-Encodeing:chunked机制,发送一个“没完没了”的chunk流,就一个连接,但其Response永远接收不完。
与长轮询的差异在于,这里只有一个HTTP请求,不存在HTTP Header不断重复的问题,但实现时没有长轮询简单直接。
断点续传
当客户端从服务器下载文件时,如果下载到一半连接中断了,再新建连接之后,客户端可以从上次断的地方继续下载。具体实现也很简单,客户端一边下载一边记录下载的
数据量大小,一旦连接中断了,重新建立连接之后,在请求的头部加上Range: first offset -last offset字段,指定从某个offset下载到某个offset,服务器就可以只返回(first offset,lastoffset)之间的数据。
备注:HTTP 1.1的这种特性只适用于断点下载。要实现断点上传,就需要自行实现。
HTTP/2
http/2出现的背景
因为HTTP1.1的Pipeline不够完善,Web开发者们想出了各种方法去提高HTTP 1.1的效率。但这些方法都是从应用层面去解决的,没有普适性,因此有人想到在协议层面去解决这问题,而这正是Google公司的SPDY协议的初衷。
SPDY是Google公司开发的一个实验性协议,于2009年年中发布。2012年,该协议得到了Chrome、Firefox和Opera的支持,越来越多的大型网站(如Google、Twitter、Facebook)和小型网站开始在其基础设施内部署SPDY。观察到这一趋势后,HTTP工作组作提上议事日程,吸取SPDY的经验和教训,并在此基础上制定了HTTP/2协议。
之所以叫HTTP/2,没有叫HTTP 2.0,也是因为工作组认为该协议已经很完善,后面不会再有小版本。如果要有的话,下一个版本就是HTTP/3。因此,在HTTP/2标准出来之后,Google也弃用SPDY,全面转向HTTP/2。
核心特征之1:
为了兼容http 1.1,和http 1.1不在一个层级
既然HTTP 1.1已经成了当今互联网的主流,因此HTTP/2在设计过程中,首先要考虑的就是和HTTP 1.1的兼容问题,所谓兼容,意味着:·不能改变http:// 、https:// 这样的URL范式。
不能改变HTTP Request/Http Response的报文结构。HTTP协议是一来一回,一个Request对应一个Response,并且Reqeust和Response的结构有明确的规定。
如何能做到在不改变Reqeust/Response报文结构的情况下,发明出一个新的HTTP/2协议呢?这点正是理解HTTP/2协议的关键所在。
HTTP/2和HTTP1.1并不是处于平级的位置,而是处在HTTP1.1和TCP之间。相当于在HTTP 1.1和TCP之间多了一个转换层,这个转换层就是SPDY,也就是现在的HTTP/2。
核心特征之2:
2进制分帧,解决http 1.1的队头阻塞问题
1.对于每一个域名,在浏览器和服务器之间,只维护一条TCP连接。
2.然后把http1.1的字符格式的报文给TCP之前转换成二进制,并且分成多个帧(多个数据块)来发送。
有了这个二进制分帧之后,在TCP层面,虽然是串行的;但从HTTP层面来看,请求就是并发地发出去、并发地接收的,没有了HTTP 1.1的Pipeline的限制,请求1、2、3虽然是按顺序发出去的,但响应1、2、3可以乱序地返回。
2进制分帧是否彻底解决了“队头阻塞”问题?
1.并没有彻底解决!只是把“队头阻塞”问题从HTTP Request粒度细化到了“帧”粒度,降低了队头阻塞发生的概率。
只要用TCP协议,就绕不开“队头阻塞”问题,因为TCP协议是先进先出的!如前面图所示,如果帧F3(队头的第一个帧)在网络上被阻塞了(或者丢包了),则服务器会一直等F3,如果F3不来,后面的包都不会成功被接收。反向队头的FF1也是同样的道理。
2.为什么说降低了队头阻塞发生的概率?前面说到请求1的响应1迟迟不能回来,原因可能有两种:
原因1:服务器对请求1处理得慢;
原因2:服务器对请求1处理得很及时,但网络传输慢了。
对于原因2,如果刚好请求1的第一个帧又处在队头,则即使二进制分帧也解决不了队头阻塞问题;
但对于原因1,请求2、请求3的响应分帧之后,是先于请求1的响应发出去的,那么请求2和请求3的响应就不会被请求1阻塞,从而就避免了队头阻塞问题。
HTTPS解决了HTTP的哪些问题
Http由于是明文传输,所以安全上存在以下三个问题:
- 窃听风险
- 篡改风险
- 冒充风险
HTTPS在HTTP与TCP层之间加入了 SSL/TLS 协议,可以很好的解决了上述的风险:
- 信息加密:交互信息无法被窃取,但你的号会因为「自身忘记」账号而没。
- 校验机制:无法篡改通信内容,篡改了就不能正常显示,但百度「竞价排名」依然可以搜索垃圾广告。
- 身份证书︰证明淘宝是真的淘宝网,但你的钱还是会因为「剁手」而没。
可见,只要自身不做「恶」,SSL/TLS协议是能保证通信是安全的。
HTTPS是如何解决上面的三个风险的?
- 混合加密的方式实现信息的机密性,解决了窃听的风险。
- 摘要算法的方式来实现完整性,它能够为数据生成独一无二的「指纹」,指纹用于校验数据的完整性,解决了篡改的风险。
- 将服务器公钥放入到数字证书中,解决了冒充的风险。
“https和http相比,就是传输的内容多了对称加密,可以这么理解吗?”
1.建立连接时候:https 比 http多了TLS的握手过程;
2.传输内容的时候:https 会把数据进行加密,通常是对称加密数据;
TCP核心原理
网络传输的本质是不可靠的
客户端发了数据包1、2、3,这三个包经过互联网的传输,到了服务器端,接收到的是3和1。
其中发生了两件事情:
丢包:数据包2丢失了。
时序错乱:客户端先发的是数据包1,后发的包3;服务器却先收到了包3,后收到的是包1。
为什么会丢包呢?网络中有成千上万个路由节点,节点发生故障是很正常的事情;
为什么时序会错乱呢?三个数据包被发送到网络上,走的是不同的网络链路,谁快谁慢是不确定的,所以后发的可能先到。
所以说,“不可靠”是网络传输的常态!
TCP是“可靠传输”,如何做到的?
“可靠”传输具有三重语义:
(1)数据包不丢。
(2)数据包不重。比如服务器不会收到两次数据包2,有且只会收到一次。
(3)顺序不乱。
如何在一个“不可靠”的网络上实现一个“可靠”的网络通道?
怎么不丢?
1.网络丢包是一定会出现的,对上层应用来说,如何确保不丢呢?
只有一个办法,重发!服务器每次收到一个包,就要对客户端进行确认,反馈给客户端已经收到了数据包;如果客户端在超时时间内没有收到ACK,则重发数据。
2.当客户端发送数据包1后,服务器确认,收到数据包1了;当客户端发送数据包2后,服务器确认,收到数据包2......这样每个数据包都要一一确认,效率太低了。怎么办呢?
客户端对发送的每个数据包编一个号,编号由小到大单调递增,基于编号就能进行顺序的确认。
比如服务器几乎同时收到了数据包1、2、3,它只用回复客户端
(ACK=3),意思是所有小于或等于3的数据包都已经收到了;又过了一会,服务器收到了数据包4、5、6,它只用回复客户端(ACK=6),意思是说所有小于或等于6的数据包都收到了。
怎么不重?
1.为什么会重复?
因为只要超过了约定时间,客户端还没有收到服务器的确认,客户端就会重发。但可能此时服务器的ACK已经在网络上了,只是还没有到达客户端而已。如果客户端重发,则服务器会收到重复消息,就需要判重。
2.如何判重?
和已经收到的数据包逐一比对,核实是否有重复?这显然不现实。
其实解决方法很简单,就是顺序ACK。服务器给客户端回复ACK=6,意思是所有小于或等于6的数据包全部收到了,之后凡是再收到这个范围的数据包,则判定为重复的包,服务器收到后丢弃即可。
怎么不乱?
假设服务器收到了数据包1、2、3,回复客户端(ACK=3),之后收到了数据包5、6、7,而数据包4迟迟没有收到,这个时候怎么办呢?服务器会把数据包5、6、7暂时存放,直到数据包4的到来,再给客户端回复ACK=7;如果数据包不来,服务器的ACK进度会一直停在那(保持ACK=3),等到客户端超时,会把数据包4、5、6、7全部重新发送,这样服务器收到了数据包4,回复ACK=7,同时数据包5、6、7重复了,通过上面说的判重的办法,丢弃掉数据包5、6、7。
总之,服务器虽然接收数据包是并发的,但数据包的ACK是按照编号从小到大逐一确认的,所以数据包的时序是有保证的。
最终,通过消息顺序编号+客户端重发+服务器顺序ACK,实现了客户端到服务器的数据包的不重、不漏、时序不乱;反过来,从服务器到客户端的数据包的发送与接收,用相同的原理来实现。
TCP的这种思想可以说朴素而深刻,分布式系统中消息中间件的消息不重、不漏的实现机制和它有异曲同工之妙。
什么叫1条TCP连接?
可以看到,在物理层面,数据包1、2、3走的是不同网络链路,在客户端和服务器之间并不存在一条“物理管道”。只是在逻辑层面,让TCP之上的应用层看起来就像再客户端和服务器之间架起了”一个可靠的连接“。
这个连接是“假”的,是通过数据包的不重、不漏时序不乱的机制,给上层应用造成的一个“假象”
每1条连接是一个状态机
1.每条连接用(客户端IP,客户端Port,服务器IP,服务器Port)4元组唯一确定,在代码中是一个个的Socket。其中有一个关键问题要解决,既然“连接”是假的,在物理层面不存在;但在逻辑层面连接是存在的,每条连接都需要经历建立阶段、正常数据传输阶段、关闭阶段,要完整地维护在这三个阶段过程中连接的每种可能的状态。
2.每条连接都是一个“状态机”,客户端和服务器都需要针对这条连接维护不同的状态变迁,在不同的状态下执行相应的操作。
状态机的转换图
共11种状态,有些状态是客户端/服务端都有,有些状态只存在客户端,有些状态只存在服务器
(1)首先,客户端和服务器都处于CLOSED状态;
(2)连接建立好之后,双方都处于ESTABLISHED状态,开始传输数据;
(3)最后连接关闭,双方再次回到CLOSED状态。为什么开始是处于CIOSED状态,而没有一个NTT(初始)状态呢﹖因为连接是复用的,每个连接用4元组唯一标识,关闭之后,后面又会开启,所以没有必要引入“初始”状态。
3次握手
从图中可以看出,
客户端的状态转移过程是CLOSED →SYN_SENT → ESTABLISHED
服务器的状态转移过程是CLOSED →LISTEN →SYN_RCVD →ESTABLISHED
1.图中的ACK的意思和前之所讲的稍微有些差异:前文中的ACK=7,表示告诉对方编号小于或等于7的包都收到了;这里的ACK=x+1,表示小于或等于x的包都收到了,接下来要接收x+1。所以,虽然意思相同,但换了一种说法。
2.seq=x表示发出去的包的编号是x。因为TCP是全双工的,通信双方一方面要发送自己的编号的包,一方面要确认对方的包,为了优化传输,会把两个包合在一起传输,所以就有了同一个包里,同时包含有seq=y,ACK=x+1。表示当前这个包是发出去的第y个包,同时也是对对方的第x个包的确认(接下来要接收x+1)
为什么是3次握手,而不是2次,或者4次?-网络2将军问题
客户端:“Hi,服务器,我想建立一个连接。”
服务器:“好的,可以。”
但问题是,服务器知道“好的,可以”这句话它发出去了,但是客户端是否收到,服务器是不确定的。所以2次不够,需要改成3次,同样的问题,客户端没有办法确认上图中的最后一次ACK(第三次)对方是否收到了。
这就是经典的网络的2将军问题:无论是两次,还是三次,还是四次.....永远都不知道最后发出去的那个ACK包对方是否收到了。
想要知道最后一次是否收到,只有让对方回复一个ACK,但回复的这个ACK是否收到,只能让对方为这个ACK再回复一个ACK,如此循环往复,问题无解。。。
既然2次,3次,4次都没法彻底解决问题,那为什么是3次?
因为三次握手恰好可以保证客户端和服务器对自己的发送、接收能力做了一次确认。
第一次,客户端给服务器发了seq =x,无法得到对方是否收到,此时服务端知道客户端的发送能力没问题;
第二次,对方回复了seq=y,ACK=x+1。这时客户端知道自己的发送和接收能力没有问题,但服务器只知道自己的接收能力没问题;
第三次,客户端发送了ACK=y+1,服务器收到后知道自己第二次发的ACK对方收到了,自己的发送能力也没问题。
“网络2将军问题”的工程应用
客户端给服务器发送了一个HTTP请求,或者说客户端向DB写入一条记录,然后超时了没有得到响应,请问服务器是写入成功了,还是没有成功呢?答案是不确定。
1.场景1:该请求服务器根本没有收到,发送时网络有问题。
2.场景2:该请求服务器收到了,服务器写入成功了,但回复给客户端时,网络有问题。
3.场景3:网络没有问题,服务器接收到了请求,写入成功了,但回复给客户端时,服务器宕机了。
无论哪种场景,客户端看到的结果是一样的:它发出的数据没有得到响应。对于客户端来说,只有一个办法,就是再重试,直到服务器返回成功,客户端才能确认请求被成功处理了。
“成功”了客户端知道成功,但“失败/超时“了不代表失败!
4次挥手:客户端主动发起关闭,从Half-Close到Close
客户端的状态转移过程为:ESTABLISHED →FIN_WAIT_1→FIN_WAIT_2→ TIME_WAIT →CLOSED
服务器的状态转移过程为:ESTABLISHED →CLOSE_WAIT →LAST_ACK→CLOSED
为什么是四次挥手呢?因为TCP是全双工的,可以处于Half-Close状态。
第一次:客户端对服务器说:“Hi,服务器,我要关了。”
第二次:服务器回复:“好的,你的信息我收到了。”
第三次:服务器回复:“Hi,客户端,我也要关了。”
第四次:客户端回复:“好的,你的信息我也收到了。”
如果只发生了第一次和第二次,意味着该连接处于Half-Close状态,此时客户端处于FIN_WIAT_2状态,服务器处于CLOSE WAIT状态,客户端通往服务器的通道关闭了,但服务器通往客户端的通道还未关闭,仍然可以传输数据。
双方同时发起关闭
还有一种场景,客户端和服务器同时主动发起了关闭,双方都会处于FIN_WAIT_1状态,此时又收到了对方的ACK,这时双方都会切到CLOSING状态,
之后一起进入TIME_WAIT状态,经过一段时间后进入CLOSE状态。
问题1:为什么要有个TIME_WAIT状态,而不是直接CLOSE?
当双方都进入CLOSE状态后,仍可能有数据包还在网络上“闲逛”。而一个连接是由(客户端P、客户端Port、服务器IP、服务器Port)4元组唯一标识的,连接关闭之后再重开,应该是一个新的连接,但用4元组无法区分出新连接和老连接。这会导致,之前闲逛的数据包在新连接打开后被当作新的数据包,这样一来,老连接上的数据包会“串”到新连接上面,这是不能接受的。
怎么解决这个问题呢?
在整个TCP/IP网络上,定义了一个值叫作MSL (Maximum Segment
Lifetime),任何一个IP数据包在网络上逗留的最长时间是MSL,这个值默认是120s。意味着一个数据包必须最多在MSL时间以内,从源点传输到目的地,如果超出了这个时间,中间的路由节点就会把该数据包丢弃。有了这个限定之后,一个连接保持在TIME_WAIT状态,再等待2′倍的MSL的时间进入CLOSE状态,就会完全避免旧的连接上面存在闲逛的数据包串到新的连接上。
问题2:为什么是2倍的MSL时间
因为网络的2将军问题,上图中的第四次发送的数据包,服务器是否收到是不确定的。服务器采取的方法是在无法收到第四次的情况下重新发送第三次的数据包,客户端重新收到第三次数据包,再次发送第四次的数据包。
第四次数据包的传输时间+服务器重新发送第三次数据包的时间,最长是两个MSL,所以要让客户端在TIME_WAIT状态等待2′MSL的时间。
问题3:为什么客户端有TIME_WAIT状态,而服务器端没有呢?
原因是没有必要。任何一个连接都是一个4元组,同时关联了客户端和服务器,客户端处于TIME_WAIT状态后,意味着这个连接要到2倍的MSL时间之后才能重新启用,服务器端即使想立马使用也无法实现。
问题4:为什么要避免大量连接处于TIME_WAIT状态?
通过上面的分析会发现,一个连接并不是想关就能立刻关的,关闭后还要等2'MSL时间才能重开。
这就会造成一个问题:如果频繁地创建连接,最后可能导致大量的连接处于TIME_WAIT状态,最终耗光所有的连接资源。
为了避免出现这种问题,可以采取如下措施:
(1)不要让服务器主动关闭连接。这样服务器的连接就不会处于TIME_WAIT状态。
(2)客户端做连接池,复用连接,而不要频繁地创建和关闭,这其实也是HTTP 1.1和HTTP/2采用的思路。
状态机的转换图
共11种状态,有些状态是客户端/服务端都有,有些状态只存在客户端,有些状态只存在服务器
(1)首先,客户端和服务器都处于CLOSED状态;
(2)连接建立好之后,双方都处于ESTABLISHED状态,开始传输数据;
(3)最后连接关闭,双方再次回到CLOSED状态。为什么开始是处于CIOSED状态,而没有一个INIT(初始)状态呢?因为连接是复用的,每个连接用4元组唯一标识,关闭之后,后面又会开启,所以没有必要引入“初始”状态。
udp与quic与http/3核心原理
QUIC (Quick UDP Internet Connection)
udp的几个典型特点
1.“无连接”
所以也不需要像tcp那样,维护复杂的连接状态机。
2.无队头阻塞问题
因为无连接,所有的包并发在网络上传输,而不是像TCP那样在一个连接上面串行传输
3.不可靠可以丢包、乱序
4.没有tcp的拥塞控制
备注:
1.udp虽然不可靠,但基于udp的程序,可以在应用层面自己实现可靠机制:ack +重传
2.为什么udp经常用于多媒体/音视频领域?
(1)性能快
(2)音视频有编解码技术,少量丢包,仍然可播放
QUIC优势
1.彻底解决“队头阻塞”问题
前言:
(1) http 1.1的pipeline有队头阻塞问题(请求1,2,3,返回的顺序也必须是1,2,3 )
(2) http/2的2进制分帧,部分解决了“队头阻塞”问题,但因为用的TCP,没彻底解决。
**只要用TCP,就没办法完全避免队头阻塞。
QUIC直接放弃TCP,构建在UDP之上
2. 0-RTT
1.TCP 连接建立,3次握手,即1.5RTT
2.TLS 1.2 -> TLS 1.3:
2RTT(RSA)->1RTT(ECDH) -> ORTT(PSK)
QUIC把这2类RTT都省了,具体来说:
(1)新网站,第一次连接,需要1个RTT,类似TLS 1.3中的原理
(2)旧网站,非第一次连接,客户端缓存了STK(类似TLS中的PSK),O-RTT
备注:STK(Source Token),类似TLS中的PSK
3.连接迁移能力
TCP是通过4元组来唯一标识一个连接,当客户端在4G和Wifi之间来回切换时,客户端的ip发生变化,导致连接失效,需要重建连接(在2个网络环境之间的切换不够平滑)
QUIC不用4元组标识连接,用了一个新定义的64位的
ConnectionlD标识。发生网络切换的时候,这个ID保持不变,就可以继续发送数据。
4.QUIC如何做到不丢包?
TCP的不丢包,是通过顺序ACK+重传来实现的,那QUIC呢?磁盘存储领域经典的Raid5和Raid6算法。如图所示,每发送5个数发送一个冗余包。一个冗余包。冗余包是对5个数据包做异或运算得到的。这样一来,服务器收到6个包,如果5个当中,有一个丢失了,可以通过其他几个包计算出。
但这种丢包的恢复办法有一个限制条件:每5个当中只能丢失一个。如果把它改成每发送10个数据包,再生成一个冗余包,就是每10个当中只能丢失一个。
5.QUIC是用户态协议,修改更容易
TCP是内核态的,由操作系统提供。要修改、优化TCP,需要修改内核并重启机器。
QUIC是用户态的协议,只依赖内核的UDP。要修改各种参数、策略、算法,更容易。
不足
还很不成熟,目前只大厂的某些少量业务在试用。
要大规模推广,难度还很大,需要已经存在的各种客户端、服务器框架支持。
DNS
DNS协议、内网DNS、DNS劫持、httpDNS...
__EOF__

本文链接:https://www.cnblogs.com/LiPengFeiii/p/15946736.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)