Http Https Tcp概述
参考资料:
- https://juejin.im/post/5d7085f6f265da03dd3d92f6
- https://www.cnblogs.com/ttltry-air/archive/2012/08/20/2647898.html
- https://www.zhihu.com/question/302412059
- https://juejin.im/post/5ab308e9f265da238e0da39b
- https://www.w3ctech.com/topic/1563
- https://draveness.me/whys-the-design-https-latency
Http/1.1 和 Http/2 的新特性
Http/1.1相对 Http/1.0的功能升级
- 缓存处理: HTTP1.1引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略
- 带宽优化:不同于http/1.0必须传递资源对象, HTTP1.1在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
- 新增错误状态码
- 新增Host请求头处理:解决一台物理机上多台虚拟主机的问题
-
长连接:HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive
- 服务器都会配置一个KeepAlive Timeout参数和KeepAlive Requests参数限制单个连接持续时长和最多服务的请求次数
- 如果服务器设置的timeout时长为0,就退化到非持久连接。非持久连接会在响应头部增加一个头信息Connection: Close通知客户端在接受完当前响应后连接需要立即关闭
- 同样浏览器也不会因为服务器将KeepAlive Timeout配置了无限长就不管不问一直持续保持连接。每个浏览器都有它自己的内置限制,具体限制浏览器厂商各有不同。
Http/1.1存在的问题:
- Pipeling 是顺序执行的,前面的请求超时会阻塞后面的请求,这称为"队头堵塞"(Head-of-line blocking)
- Keep-alive 在下载图片的时候,保持不必要的长连接会增加服务器压力
HTTP/2 的新特性:
-
二进制文件传输:二进制协议解析起来更高效
-
头部压缩: HTTP/2 使用 encoder 来减少需要传输的 header 大小,通讯双方各自cache 一份 header fields 表,既避免了重复 header 的传输,又减小了需要传输的大小
-
多路复用 (Multiplexing): 所有就是请求的都是通过一个 TCP 连接并发完成。允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息。即连接共享,即每一个 request 都是是用作连接共享机制的。一个 request 对应一个 id,这样一个连接上可以有多个 request,每个连接的 request 可以随机的混杂在一起,接收方可以根据 request 的 id 将 request 再归属到各自不同的服务端请求里面。
-
请求优先级 允许给每个 request 设置优先级,这样重要的请求就会优先得到响应。比如浏览器加载首页,首页的 html 内容应该优先展示,之后才是各种静态资源文件,脚本文件等加载,这样可以保证用户能第一时间看到网页内容
-
服务器推送 (Server push):服务端能通过 push 的方式将客户端需要的内容预先推送过去,也叫“cache push”。 服务器可以对一个客户端请求发送多个响应。服务器向客户端推送资源无需客户端明确地请求,服务端可以提前给客户端推送必要的资源,这样可以减少请求延迟时间,例如服务端可以主动把 JS 和 CSS 文件推送给客户端,而不是等到 HTML 解析到资源时发送请求
TCP协议
TCP请求头有6种标示位
- SYN(synchronous建立联机) : SYNchronization的缩写, TCP请求头重的标志位。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此, SYN置1就表示这是一个连接请求或连接接受报文。
- ACK(acknowledgement 确认) :TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1
- FIN(finish结束): 用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
- PSH(push传送)
- RST(reset重置)
- URG(urgent紧急)
三次握手
第一次:客户端 —>>> 服务端(客户端:我想跟你通信SYN=1,我的***时x)
SYN=1, ACK=0, seq=随机选取一个***作为自己的初始序号=x
第二次:客户端 <<<— 服务端 (服务端:可以通信ACK=1,我的***时Y,我希望下次接收到的***是x+1,你那边准备好了?)
SYN=1, ACK=1, seq=随机选取一个***作为自己的初始序号=y, ack=期望接收客户端的包***为=x+1
第三次:客户端 —>>> 服务端(客户端:准备好了ACK=1,我这条消息的***是x+1,我希望消磁接受来自服务端的***是y+1)
ACK=1, seq=我这条消息的***=x+1, ack=期望接收服务端的包***为=y+1
四次挥手
第一次:客户端 —>>> 服务端(客户端:我项结束此次你通信 FIN=1,我的***时u)
FIN=1, seq=客户端自己当前的序号=u
第二次:客户端 <<<— 服务端 (服务端:我确认收到你结束通信的消息了ACK=1,我的***时y,我希望下次接收到的***是x+1,我可能还有数据没有发送给你)
ACK=1, seq=服务度端当前的需要=y, ack=期望接收客户端的包***为=u+1
第三次:客户端 <<<— 服务端 (服务端:这是我发送的最后的数据,可以结束通信了FIN=1,我当前的***是w,我希望下次接收到的***是u+1)
FIN=1, ACK=1, seq=服务度端当前的需要=w, ack=期望接收客户端的包***为=u+1
第四次:客户端 —>>> 服务端(客户端:我知道你要关闭了ACK=1,我这条消息的***是u+1,我希望消磁接受来自服务端的***是w+1)
ACK=1, seq=我这条消息的***=u+1, ack=期望接收服务端的包***为=w+1
注意此时 TCP 连接还没有释放,必须经过 2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的 TCB(Task Control Block)任务控制块后,才进入 CLOSED 状态。
常见问题:
为什么要三次握手:
-
了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。(为了防止服务端等待的资源浪费)
例如:
client 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 server。本来这是一个早已失效的报文段。但 server 收到此失效的连接请求报文段后,就误认为是 client 再次发出的一个新的连接请求。于是就向 client 发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要 server 发出确认,新的连接就建立了。由于现在 client 并没有发出建立连接的请求,因此不会理睬 server 的确认,也不会向 server 发送数据。但 server 却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client 不会向 server 的确认发出确认。server 由于收不到确认,就知道 client 并没有要求建立连接。” -
另一种解答思路
”这个问题的本质是, 信道不可靠, 但是通信双发需要就某个问题达成一致. 而要解决这个问题, 无论你在消息中包含什么信息, 三次通信是理论上的最小值. 所以三次握手不是TCP本身的要求, 而是为了满足在不可靠信道上可靠地传输信息" 这一需求所导致的. 请注意这里的本质需求,信道不可靠, 数据传输要可靠. 三次达到了, 那后面你想接着握手也好, 发数据也好, 跟进行可靠信息传输的需求就没关系了. 因此,如果信道是可靠的, 即无论什么时候发出消息, 对方一定能收到, 或者你不关心是否要保证对方收到你的消息, 那就能像UDP那样直接发送消息就可以了.”。这可视为对“三次握手”目的的另一种解答思路。后面一段话意思就是如果想确定双通道通畅,必须使用三个包的发送接收,也就是三次握手
为什么是 4 次挥手
接收到FIN时意味将没有数据再发来,但是还是可以继续发送数据。
握手的时候,A 和 B 打个招呼,B 可以直接把自己的 SYN 信息和对 A 的回应 ACK 信息一起带上,但是挥手的时候,A 说我要断开了,B 还没发完最后的数据,因此需要先回应一下 A,我收到你的断开的请求了,但是你要等我把最后的内容给你,所以这里分开了 2 步:
(1)回应 A;
(2)发送自己的最后一个数据
TCP 和 UDP 的区别
- TCP 是面向连接的,udp 是无连接的即发送数据前不需要先建立链接。
- TCP 保证数据正确性,UDP 可能丢包,TCP 保证数据顺序,UDP 不保证。也就是说,通过 TCP 连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP 尽最大努力交付,即不保证可靠交付 Tcp 通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
- TCP 只能是 1 对 1 的,UDP 支持 1 对 1,1 对多。
- TCP 是面向字节流,UDP 面向报文,UDP 具有较好的实时性,工作效率比 TCP 高.并且网络出现拥塞不会使得发送速率降低(因此会出现丢包,对实时的应用比如 IP 电话和视频会议等)。
- TCP 对系统资源要求较多,UDP 对系统资源要求较少。
- TCP 的首部较大为 20 字节,而 UDP 只有 8 字节。
客户端突然挂掉了怎么办?
正常连接时,客户端突然挂掉了,如果没有措施处理这种情况,那么就会出现客户端和服务器端出现长时期的空闲。解决办法是在服务器端设置保活计时器,每当服务器收到客户端的消息,就将计时器复位。超时时间通常设置为2小时。若服务器超过2小时没收到客户的信息,他就发送探测报文段。若发送了10个探测报文段,每一个相隔75秒,还没有响应就认为客户端出了故障,因而终止该连接。
为什么 TIME_WAIT 状态需要经过 2MSL(最大报文段生存时间)才能返回到 CLOSE 状态
TIME_WAIT 状态就是用来重发可能丢失的 ACK 报文。原因是,担心网络不可靠而导致的丢包,最后一个回应 B 的 ACK 万一丢了怎么办,在这个时间内,A 是可以重新发包的,但是超过了最大等待时间的话,就算收不到也没用了,所以就可以关闭了。
HTTPS
HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息。TLS/SSL中使用了非对称加密,对称加密以及HASH算法。
- 浏览器将自己支持的一套加密规则发送给网站。
- 网站从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
- 浏览器获得网站证书之后浏览器要做以下工作:
a) 验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致等),如果证书受信任,则浏览器栏里面会显示一个小锁头,否则会给出证书不受信的提示。
b) 如果证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密。
c) 使用约定好的HASH算法计算握手消息,并使用生成的随机数对消息进行加密,最后将之前生成的所有信息发送给网站。 - 网站接收浏览器发来的数据之后要做以下的操作:
a) 使用自己的私钥将信息解密取出密码,使用密码解密浏览器发来的握手消息,并验证HASH是否与浏览器发来的一致。
b) 使用密码加密一段握手消息,发送给浏览器。 - 浏览器解密并计算握手消息的HASH,如果与服务端发来的HASH一致,此时握手过程结束,之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密。
HTTPS请求RTT时间
首先理解一个概念:RTT 是Round Trip Time的缩写,通俗地说,就是通信一来一回的时间。
TCP三次握手 = 1.5RTT
在 TLS 1.2 中,我们需要 2-RTT 才能建立 TLS 连接10,但是 TLS 1.3 通过优化协议,将两次往返
延迟降低至一次,大幅度减少建立 TLS 连接所需要的时间,让客户端可以在 1-RTT 之后就能向服务端传输应用层数据。
HTTP/1.x
-
HTTP请求时间 = 1TCP连接时间 + 1HTTP连接时间 = 1.5RTT + 1RTT = 2.5RTT
-
HTTPS请求时间 = 1TCP连接时间 + 1TLS连接时间 + 1HTTP连接时间 = 1.5RTT + 2RTT + 1RTT = 4.5RTT
HTTP/2
-
HTTP请求时间
- 第一次请求时间 = 1TCP连接时间 + 1HTTP连接时间 = 1.5RTT + 1RTT = 2.5RTT
- 之后的请求时间 = 1HTTP连接时间 = 1RTT
-
HTTPS请求时间
- 第一次请求时间 = 1TCP连接时间 + 1TLS连接时间 + 1HTTP连接时间 = 1.5RTT + 2RTT + 1RTT = 4.5RTT
- 之后的请求时间 = 1HTTP连接时间 = 1RTT