长连接
HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接。
HTTP是基于TCP/IP协议的,创建一个TCP连接是需要经过三次握手的,有一定的开销,如果每次通讯都要重新建立连接的话,对性能有影响。因此最好能维持一个长连接,可以用个长连接来发多个请求。
节约带宽
HTTP 1.1支持只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务器,则返回100,否则返回401。客户端如果接受到100,才开始把请求body发送到服务器。
这样当服务器返回401的时候,客户端就可以不用发送请求body了,节约了带宽。
另外HTTP还支持传送内容的一部分。这样当客户端已经有一部分的资源后,只需要跟服务器请求另外的部分资源即可。这是支持文件断点续传的基础。
HOST域
现在可以web server例如tomat,设置虚拟站点是非常常见的,也即是说,web server上的多个虚拟站点可以共享同一个ip和端口。
HTTP1.0是没有host域的,HTTP1.1才支持这个参数。
HTTP1.1 HTTP 2.0主要区别
多路复用
HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。
当然HTTP1.1也可以多建立几个TCP连接,来支持处理更多并发的请求,但是创建TCP连接本身也是有开销的。
TCP连接有一个预热和保护的过程,先检查数据是否传送成功,一旦成功过,则慢慢加大传输速度。因此对应瞬时并发的连接,服务器的响应就会变慢。所以最好能使用一个建立好的连接,并且这个连接可以支持瞬时并发的请求。
关于多路复用,可以参看学习NIO 。
数据压缩
HTTP1.1不支持header数据的压缩,HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快。
服务器推送
意思是说,当我们对支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源。
服务器端推送的这些资源其实存在客户端的某处地方,客户端直接从本地加载这些资源就可以了,不用走网络,速度自然是快很多的。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1. http 1.0
1.1 链接无法复用,即不支持持久链接:
http 1.0 规定浏览器与服务器保持较短时间的链接,浏览器每次请求都和服务器经过三次握手和慢启动(基本思想是当TCP开始传输数据或发现数据丢失并开始重发时,首先慢慢的对网路实际容量进行试探,避免由于发送了过量的数据而导致阻塞)建立一个TCP链接,服务器完成请求处理后立即断开TCP链接,而且不跟踪每个浏览器的历史请求。
注意:由于http 1.0每次建立TCP链接对性能的影响实在是太大,http1.1实现持久化链接之后,又反向移植到http 1.0上,只是默认是没有开启持久链接的,通过http的header部分的 Connection: KeepAlive 来启用)
1.2 线头阻塞(Head of Line (HOL) Blocking)
请求队列的第一个请求因为服务器正忙(或请求格式问题等其他原因),导致后面的请求被阻塞。
2. http 1.1
2.1 支持持久链接(在request和response中的header中的connection是close或者Keep-Alive进行控制)
一个TCP链接可以传送多个http请求和相应,减少了TCP建立链接和关闭链接的消耗。另外http1.1允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能 够区分出每次请求的响应内容。
2.2 支持http管道
不使用管道的http请求,在使用持久链接时,必须严格满足先进先出的队列顺序(FIFO),即发送请求,等待响应完成,再发送客户端队列中的下一个请求。管道可以让我们把 FIFO 队列从客户端(请求队列)迁移到服务器(响应队列),即客户端可以并行,服务端串行。客户端可以不用等待前一个请求返回,发送请求,但服务器端必须顺序的返回客户端的请求响应结果。
缺点:
a. 一个请求响应阻塞,就会阻塞后续所有请求
b. 并行处理请求时,服务器必须缓冲管道中的响应,从而占用服务器资源,如果有个响应非常大,则很容易形成服务器的受攻击面;
c. 响应失败可能终止 TCP 连接,从页强迫客户端重新发送对所有后续资源的请求,导致重复处理;
d. 由于可能存在中间代理,因此检测管道兼容性,确保可靠性很重要;
e. 如果中间代理不支持管道,那它可能会中断连接,也可能会把所有请求串联起来。
2.3 使用多个TCP链接
http1.1 在客户端排队所有请求,让后通过一个TCP持久链接,一个接一个的发送请求(如果有http管道还必须顺序等待服务端的顺序返回结果)。但实际中,浏览器的开发时不会这么笨,浏览器允许我们打开N个TCP链接(大多说浏览器是6个TCP链接,这个数字越大,客户端和服务器的资源占用越多,这个数据也只是感觉安全的数字而已)。
带来的好处:
1. 客户端可以并行发送最多 N个请求;
2. 服务器可以并行处理最多 N个请求;
3. 第一次往返可以发送的累计分组数量(TCP cwnd)增长为原来的 N 倍。
代价:
1.更多的套接字会占用客户端、服务器以及代理的资源,包括内存缓冲区和 CPU时钟周期;
2.并行 TCP 流之间竞争共享的带宽;
3.由于处理多个套接字,实现复杂性更高;
4.即使并行 TCP 流,应用的并行能力也受限制。
因此使用多个TCP链接只是权宜之计,后续的http 2.0支持多路复用,很好的解决了上述问题。
2.4 http 1.1 增加了请求头和响应头来扩充功能
举例:
a. 支持Host请求:
b. Connection: 请求头的值为Connection时,客户端通知服务器返回本次请求结果后保持连接;Connection请求头的值为close 时,客户端通知服务器返回本次请求结果后关闭连接
c. 支持断点续传:
d.身份认证:
e.状态管理:
f. 缓存处理:
2.5 域名分区
域名分区是思想是将原来集中到一个服务器上的资源分布到多个服务器上,这样就可以突破浏览器的链接限制(一般是6个),提高并行能力。
代价:
1. 每多一台主机都要多一次的 DNS 查询,每多一个套接字都会多消耗两端的一些资源;
2.必须手工分离一台主机上的资源到多台;.
实际实践中,效果并不是很明显,反而导致被滥用。
2.6 http的header的优化
目前所有的header请求都是以没有经过压缩的纯文本的形式发送(通常会有600`1000字节),而通常使用的http请求body却很少(10~200字节),和header相比,显得很少,特别是在使用了cookie之后,这样的矛盾就更加突出,因此要减少header的数据。
2.7 减少连接次数
即将需要多次才能获取的文件或资源组合并成一个,通过一次网络请求获取。这样减少了协议的开销,间接地将服务器端的管道思维移植到了客户端。缺点:增加复杂性,更缓存带来负担,页面的分步显示,改成一次显示,在网络慢的时候影响用户体验。
2.8 嵌入小的文件
即将资源嵌入文档(通过URI嵌入图片,音频或PDF),可以减少请求次数。嵌入资源作为页面的返回一部分一次返回,即如果在多个页面中都嵌入同样的资源,那么这个资源将会随着每个页面的加载而被加载,从而增大每个页面的总体大小,如果嵌入资源被更新,客户端只能重新获取有效的资源。
实践:一般只考虑嵌入1~2KB一下的资源
参照建议:
1. 如果文件很小,而且只有个别页面使用,可以考虑嵌入;
2.如果文件很小,但需要在多个页面中重用,应该考虑集中打包;
3. 如果小文件经常需要更新,就不要嵌入了;
4. 通过减少 HTTP cookie 的大小将协议开销最小化。
3. http 2.0
HTTP 2.0把解决性能问题的方案内置在了传输层,通过多路复用来减少延迟,通过压缩 HTTP首部降低开销,同时增加请求优先级和服务器端推送的功能。
3.1 支持多路复用
多路复用允许同时通过单一的 HTTP 2.0 连接发起多重的请求-响应消息,即所有HTTP 2.0 连接都是持久化的,而且客户端与服务器之间也只需要一个连接即可,所有数据流共用同一个连接 ,减少了因http链接多而引起的网络拥塞(在 HTTP1.1 协议中,同一时间,浏览器会针对同一域名下的请求有一定数量限制),解决了慢启动针对突发性和短时性的http链接低效的问题。
3.2 将通信的基本单位缩小为帧
即应用层(HTTP)和传输层(TCP or UDP)之间增加一个二进制分帧层,因此在多向请求和响应时,客户端和服务器可以把HTTP消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把它们重新组合起来,解决了http 1.*的对手阻塞问题。
3.3 首部压缩
http 2.0支持DEFLATE和HPACK 算法的压缩。
3.4 服务端推送
指客户端请求之前发送数据的机制,在 HTTP 2.0 中,服务器可以对客户端的一个请求发送多个响应。
3.5 请求优先级
HTTP 2.0 使用一个31比特的优先值,0表示最高优先级, 2(31)-1表示最低优先级,服务器端就可以根据优先级,控制资源分配,优先处理和返回最高优先级的请求帧给客户端。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TCP 三次握手和四次挥手的流程,为什么断开连接要 4 次,如果握手只有两次,会出现什么。
第一次握手(SYN=1, seq=x):
客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里。
发送完毕后,客户端进入 SYN_SEND
状态。
第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):
服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。
发送完毕后,服务器端进入 SYN_RCVD
状态。
第三次握手(ACK=1,ACKnum=y+1)
客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1
发送完毕后,客户端进入 ESTABLISHED
状态,当服务器端接收到这个包时,也进入 ESTABLISHED
状态,TCP 握手结束。
第一次挥手(FIN=1,seq=x)
假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。
发送完毕后,客户端进入 FIN_WAIT_1 状态。
第二次挥手(ACK=1,ACKnum=x+1)
服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。
第三次挥手(FIN=1,seq=y)
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。
发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。
第四次挥手(ACK=1,ACKnum=y+1)
客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。
服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。
客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。
两次后会重传直到超时。如果多了会有大量半链接阻塞队列。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
为什么TCP建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dns解析–>端口分析–>tcp请求–>服务器处理请求–>服务器响应–>浏览器解析—>链接关闭
使用序号,对收到的TCP报文段进行排序以及检测重复的数据;使用校验和来检测报文段的错误;使用确认和计时器来检测和纠正丢包或延时。//TCP头部,总长度20字节
typedef struct _tcp_hdr
{
unsigned short src_port; //源端口号
unsigned short dst_port; //目的端口号
unsigned int seq_no; //序列号
unsigned int ack_no; //确认号
#if LITTLE_ENDIAN
unsigned char reserved_1:4; //保留6位中的4位首部长度
unsigned char thl:4; //tcp头部长度
unsigned char flag:6; //6位标志
unsigned char reseverd_2:2; //保留6位中的2位
#else
unsigned char thl:4; //tcp头部长度
unsigned char reserved_1:4; //保留6位中的4位首部长度
unsigned char reseverd_2:2; //保留6位中的2位
unsigned char flag:6; //6位标志
#endif
unsigned short wnd_size; //16位窗口大小
unsigned short chk_sum; //16位TCP检验和
unsigned short urgt_p; //16为紧急指针
}tcp_hdr;
https://zh.bywiki.com/zh-hans/传输控制协议
无法被浏览器缓存的请求:
HTTP信息头中包含Cache-Control:no-cache,pragma:no-cache,或Cache-Control:max-age=0等告诉浏览器不用缓存的请求
需要根据Cookie,认证信息等决定输入内容的动态请求是不能被缓存的
经过HTTPS安全加密的请求(有人也经过测试发现,ie其实在头部加入Cache-Control:max-age信息,firefox在头部加入Cache-Control:Public之后,能够对HTTPS的资源进行缓存,参考《HTTPS的七个误解》)
POST请求无法被缓存
HTTP响应头中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的请求无法被缓存
http://www.alloyteam.com/2012/03/web-cache-2-browser-cache/
参考上面
加密方式是tls/ssl,底层是通过对称算法,非对称,hash算法实现
客户端发起HTTPS请求 --》2. 服务端的配置 --》
3. 传送证书 —》4. 客户端解析证书 5. 传送加密信息 6. 服务段解密信息 7. 传输加密后的信息 8. 客户端解密信息
http://www.cnblogs.com/zhuqil/archive/2012/07/23/2604572.html
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
三次握手,而不是两次握手
谢希仁版《计算机网络》中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送ack包。(校注:此时因为client没有发起建立连接请求,所以client处于CLOSED状态,接受到任何包都会丢弃,谢希仁举的例子就是这种场景。但是如果服务器发送对这个延误的旧连接报文的确认的同时,客户端调用connect函数发起了连接,就会使客户端进入SYN_SEND状态,当服务器那个对延误旧连接报文的确认传到客户端时,因为客户端已经处于SYN_SEND状态,所以就会使客户端进入ESTABLISHED状态,此时服务器端反而丢弃了这个重复的通过connect函数发送的SYN包,见第三个图。而连接建立之后,发送包由于SEQ是以被丢弃的SYN包的序号为准,而服务器接收序号是以那个延误旧连接SYN报文序号为准,导致服务器丢弃后续发送的数据包)但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。
在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。在另一部经典的《计算机网络》(Andrew S.Tanenbaum著,第四版)一书中讲“三次握手”的目的是为了解决“网络中存在延迟的重复分组”的问题。这两种不同的表述其实阐明的是同一个问题