什么是HTTP/2?

HTTP/2(原名HTTP 2.0)即超文本传输协议第二版,使用于万维网。HTTP/2主要基于SPDY协议,通过对HTTP头字段进行数据压缩、对数据传输采用多路复用和增加服务端推送等举措,来减少网络延迟,提高客户端的页面加载速度。HTTP/2没有改动HTTP的应用语义,仍然使用HTTP的请求方法、状态码和头字段等规则,它主要修改了HTTP的报文传输格式,通过引入二进制分帧实现性能的提升。

目录

HTTP/2解决了什么问题?

HTTP是应用最广泛、采用最多的一个互联网应用协议。早期版本的HTTP协议实现简单:HTTP/0.9只用一行协议就启动了万维网;HTTP/1.0则是对流行的HTTP/0.9扩展的一个正式说明;直到HTTP/1.1,IETF才发布可第一份官方标准。早期为了实现简单是以牺牲应用性能为代价:HTTP/1.1客户端需要使用多个连接才能实现并发和缩短延迟;HTTP/1.1不会压缩请求头字段和响应头字段,从而产生不必要的网络流量;HTTP/1.1不支持有效的资源优先级,致使底层TCP连接的利用率低下等等。

随着网络应用普及到人们的日常生活,它的应用范围、复杂性、重要性也在不断扩大。为了解决HTTP协议问题,HTTP/2应运而生。HTTP/2没有改动HTTP的应用语义,仍然使用HTTP的请求方法、状态码和头字段等规则,它主要修改了HTTP的报文传输格式,通过引入服务器推送等举措,来减少网络延迟,提高客户端的页面加载速度。

HTTP/2 vs HTTP/1.1

高健壮性

HTTP/1.1,使用基于文本格式,文本表现形式多样、场景多,健壮性不足。HTTP/2使用二进制格式,只有0和1的组合,选择二进制传输,协议解析实现方便且健壮。

高性能

HTTP连接会随着时间进行自我调节,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调节被称为TCP慢启动。这种调节让具有突发性和短时性的HTTP连接变的十分低效。HTTP/2通过多路复用让所有数据流使用同一个连接,有效使用TCP连接,让高带宽也能真正的服务于HTTP的性能提升。

HTTP/2在应用层和传输层之间增加了二进制分帧,突破了HTTP/1.1性能限制,改进传输性能,实现低延迟和高吞吐量。

网络开销低

HTTP/2使用HPACK算法来压缩每次请求连接的头字段,降低了网络开销。HPACK算法可以减少需要传输的头字段大小,通讯双方通过建立和维护头字段表,字段表中使用长度较小的索引号表示重复的字符串,在用Huffman编码压缩数据,既避免了重复头字段的传输,又减小了需要传输的大小。

HTTP/2有哪些关键特性?

二进制分帧

HTTP/2所有性能增强的核心在于新的二进制分帧层,如下图所示,它是所有其他功能和性能优化的基础,它定义了如何封装HTTP消息并在客户端与服务器之间传输。


二进制分帧

HTTP/2没有改动HTTP的应用语义,仍然使用HTTP的请求方法、状态码和头字段等规则,它主要修改了HTTP的报文传输格式。HTTP/1.1协议以换行符作为纯文本的分隔符,而HTTP/2将所有传输的信息分割为更小的消息和帧,并采用二进制格式对它们编码,这些帧对应着特定数据流中的消息,他们都在一个TCP连接内复用。

优先级排序

将HTTP消息分解为很多独立的帧之后就可以复用多个数据流中的帧,客户端和服务器交错发送和传输这些帧的顺序就成为关键的性能决定因素。HTTP/2允许每个数据流都有一个关联的权重和依赖关系,数据流依赖关系和权重的组合明确表达了资源优先级,这是一种用于提升浏览性能的关键功能。HTTP/2协议还允许客户端随时更新这些优先级,我们可以根据用户互动和其他信号更改依赖关系和重新分配权重,这进一步优化了浏览器性能。

首部压缩

HTTP每次请求或响应都会携带首部信息用于描述资源属性。HTTP/1.1使用文本的形式传输消息头,消息头中携带cookie每次都需要重复传输几百到几千的字节,这十分占用资源。

HTTP/2使用了HPACK算法来压缩头字段,这种压缩格式对传输的头字段进行编码,减少了头字段的大小。同时,在两端维护了索引表,用于记录出现过的头字段,后面在传输过程中就可以传输已经记录过的头字段的索引号,对端收到数据后就可以通过索引号找到对应的值。

多路复用

多路复用允许同时通过单一的HTTP/2连接发起多重的请求-响应消息,实现多流并行而并不依赖多个TCP连接,HTTP/2把HTTP协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息,并行地在同一个TCP连接上双向交换消息。

HTTP/2基于二进制分帧层,HTTP/2可以在共享TCP连接的基础上同时发送请求和响应。HTTP消息被分解为独立的帧,而不破坏消息本身的语义交错发出去,在另一端根据流标识符和首部将他们重新组装起来。通过多路复用技术,可以避免HTTP旧版本的消息头阻塞问题,极大提高传输性能。

服务器推送

HTTP2.0的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。服务器向客户端推送资源无需客户端明确的请求。服务端根据客户端的请求,提前返回多个响应,推送额外的资源给客户端。如下图所示,客户端请求stream 1,服务端在返回stream 1的消息的同时推送了stream 2和stream 4。


                                                HTTP/2服务器推送

服务端推送是一种在客户端请求之前发送数据的机制。在HTTP/2中,服务器可以对一个客户端的请求发送多个响应。如果一个请求是由你的主页发送的,服务器可能会响应主页内容、logo以及样式表,因为服务端知道客户端会用到这些东西。这样不但减轻了数据传送冗余步骤,也加快了页面响应的速度,提高了用户体验。

HTTP/2在网络管理与监控中的应用

HTTP/2主要用于网络管理与监控,设备通过HTTP/2可以实时检测服务端的性能数据,能更有效的利用网络资源,减少网络的应用延迟。

在华为SD-WAN解决方案中,管理组件对设备的管理接口协议一般采用NETCONF和HTTP/2,SD-WAN解决方案整体架构如下图所示,NETCONF负责网络设备告警、日志和事件等运维信息的采集,HTTP/2则负责网络设备性能信息的采集。


                                        SD-WAN整体架构

网络控制器通过NETCONF给网络设备下发的配置,基于SSH协议承载,可保障数据传输的安全性。同时,网络设备通过HTTP/2上报性能数据,并通过NETCONF协议上报告警给网络控制器;网络设备上线注册必须进行双向证书认证;网络设备系统软件和特征库通过HTTPS(HyperText Transfer Protocol Secure,超文本传输安全协议)传输,HTTPS和HTTP/2协议报文都采用TLS(Transport Layer Security,传输层安全)协议加密处理,以保障数据传输安全。

转自:

什么是HTTP/2?HTTP/2和HTTP/1.1区别是什么? - 华为

#include <reg51.h> #define uchar unsigned char #define uint unsigned int sbit DS = P2^1; sbit R_CLK = P2^2; sbit S_CLK = P2^0; sbit LED = P2^3; sbit BUZZER = P2^6; uchar place_cnt = 0; bit updat = 0; uint cnt = 0; uchar bt = 0; uchar score1 = 0; uchar score2 = 0; uchar match = 0; uchar soud = 0; uchar cont = 0; uchar code table[] = { 0x3f, 0x06, 0x5b, 0x4f, // 0,1,2,3 0x66, 0x6d, 0x7d, 0x07, // 4,5,6,7 0x7f, 0x6f, 0x77, 0x07, // 8,9,A,B 0x39, 0x5e, 0x79, 0x71, // C,D,E,F 0x40 // ?? }; uchar number; uchar KeyValue = 0; // ??????????? bit confirm_mode = 0; // 0:????, 1:?????? uchar pending_team = 0; // 0:A?, 1:B? uchar pending_points = 0; // ?????? uchar pending_key = 0; // ??????? uint timeout_cnt = 0; // ????? // ?????,??????????? uchar display_buffer[8] = {0}; void send595(uchar dat) { uchar i; for(i = 0; i < 8; i++) { if((dat << i) & 0x80) DS = 1; else DS = 0; S_CLK = 0; S_CLK = 1; } } void out595(void) { R_CLK = 0; R_CLK = 1; } void vision(uchar dat, uchar pos) { send595(pos); send595(~table[dat]); out595(); } void Timer_init(void) { TMOD = 0x11; // ???0?1??????1 TH0 = (65535 - 10000) / 256; // 10ms??,?????? TL0 = (65535 - 10000) % 256; TR0 = 1; // ?????0 ET0 = 1; // ?????0?? EA = 1; // ????? } // ??????? void update_display_buffer() { display_buffer[0] = score1 / 10 % 10; // A??? display_buffer[1] = score1 % 10; // A??? display_buffer[2] = 16; // ??? display_buffer[3] = match / 10 % 10; // ?????? display_buffer[4] = match % 10; // ?????? display_buffer[5] = 16; // ??? display_buffer[6] = score2 / 10 % 10; // B??? display_buffer[7] = score2 % 10; // B??? } void timer0() interrupt 1 { TH0 = (65535 - 10000) / 256; // ??10ms?? TL0 = (65535 - 10000) % 256; updat = 1; // ???????? // ???? if(confirm_mode) { timeout_cnt++; if(timeout_cnt >= 200) { // ?2??? (200*10ms=2000ms) timeout_cnt = 0; confirm_mode = 0; LED = 1; // ??LED } } } void delay(uint i) { uint j, k; for(j = 0; j < i; j++) { for(k = 0; k < 120; k++); } } // ??????(??????) void handle_key(uchar key) { // ??????????? if(key == 12 || key == 14) { // A???B?? if(key == 12) score1 = 0; // A?? if(key == 14) score2 = 0; // B?? update_display_buffer(); // ??????? confirm_mode = 0; LED = 1; // ??LED return; } if(confirm_mode) { // ??????? if(key == pending_key) { // ?????? if(pending_team == 0) { // A? if(score1 + pending_points <= 99) { score1 += pending_points; } else { score1 = 99; } } else { // B? if(score2 + pending_points <= 99) { score2 += pending_points; } else { score2 = 99; } } update_display_buffer(); // ??????? confirm_mode = 0; LED = 1; // ??LED timeout_cnt = 0; } else { // ?????????,??????? confirm_mode = 0; LED = 1; // ??LED timeout_cnt = 0; } } else { // ??????? switch(key) { case 0: // A+1 pending_key = 0; pending_points = 1; pending_team = 0; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; case 4: // A+2 pending_key = 4; pending_points = 2; pending_team = 0; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; case 8: // A+3 pending_key = 8; pending_points = 3; pending_team = 0; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; case 2: // B+1 pending_key = 2; pending_points = 1; pending_team = 1; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; case 6: // B+2 pending_key = 6; pending_points = 2; pending_team = 1; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; case 10: // B+3 pending_key = 10; pending_points = 3; pending_team = 1; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; // ???????? case 1: match = match + 10; update_display_buffer(); // ??????? break; case 3: match = match + 1; update_display_buffer(); // ??????? break; case 5: match = match % 10; update_display_buffer(); // ??????? break; case 7: match = match / 10 * 10; update_display_buffer(); // ??????? break; case 9: soud = 1; break; case 13: soud = 0; break; } } } void ketscan() { P1 = 0xF0; if(P1 != 0xF0) { delay(10); // ?? if(P1 != 0xF0) { bt++; } if(bt == 2) { bt = 0; switch(P1) { case 0xE0: KeyValue = 0; break; case 0xD0: KeyValue = 1; break; case 0xB0: KeyValue = 2; break; case 0x70: KeyValue = 3; break; } P1 = 0x0f; switch(P1) { case 0x0e: KeyValue = KeyValue; break; case 0x0D: KeyValue = KeyValue + 4; break; case 0x0b: KeyValue = KeyValue + 8; break; case 0x07: KeyValue = KeyValue + 12; break; } // ??????(??????) handle_key(KeyValue); while(P1 != 0x0f) { // ?????? } } } } void main(void) { Timer_init(); LED = 1; // ???LED?? update_display_buffer(); // ???????? while(1) { // ?????? if(updat == 1) { updat = 0; // ????????? vision(display_buffer[place_cnt], 1 << place_cnt); if(place_cnt < 7) { place_cnt++; } else { place_cnt = 0; } } // ???? ketscan(); } }出现频闪 只要消除频闪 其他地方不要改变
最新发布
06-18
频闪问题通常出现在数码管的显示刷新逻辑中。如果刷新频率过低,人眼会感知到明显的闪烁。为了解决这个问题,可以通过以下方式优化: 1. **提高定时器中断频率**:确保数码管的刷新频率足够高(通常 50Hz 以上)。 2. **减少主循环中的阻塞操作**:避免 `delay` 等阻塞函数影响刷新逻辑。 以下是修改后的完整代码: ```c #include <reg51.h> #define uchar unsigned char #define uint unsigned int sbit DS = P2^1; sbit R_CLK = P2^2; sbit S_CLK = P2^0; sbit LED = P2^3; sbit BUZZER = P2^6; uchar place_cnt = 0; bit updat = 0; uint cnt = 0; uchar bt = 0; uchar score1 = 0; uchar score2 = 0; uchar match = 0; uchar soud = 0; uchar cont = 0; uchar code table[] = { 0x3f, 0x06, 0x5b, 0x4f, // 0,1,2,3 0x66, 0x6d, 0x7d, 0x07, // 4,5,6,7 0x7f, 0x6f, 0x77, 0x07, // 8,9,A,B 0x39, 0x5e, 0x79, 0x71, // C,D,E,F 0x40 // ?? }; uchar number; uchar KeyValue = 0; // ??????????? bit confirm_mode = 0; // 0:????, 1:?????? uchar pending_team = 0; // 0:A?, 1:B? uchar pending_points = 0; // ?????? uchar pending_key = 0; // ??????? uint timeout_cnt = 0; // ????? // ?????,??????????? uchar display_buffer[8] = {0}; void send595(uchar dat) { uchar i; for(i = 0; i < 8; i++) { if((dat << i) & 0x80) DS = 1; else DS = 0; S_CLK = 0; S_CLK = 1; } } void out595(void) { R_CLK = 0; R_CLK = 1; } void vision(uchar dat, uchar pos) { send595(pos); send595(~table[dat]); out595(); } void Timer_init(void) { TMOD = 0x11; // ???0?1??????1 TH0 = (65535 - 2000) / 256; // 提高刷新频率至约 50Hz (2ms) TL0 = (65535 - 2000) % 256; TR0 = 1; // ?????0 ET0 = 1; // ?????0?? EA = 1; // ????? } // ??????? void update_display_buffer() { display_buffer[0] = score1 / 10 % 10; // A??? display_buffer[1] = score1 % 10; // A??? display_buffer[2] = 16; // ??? display_buffer[3] = match / 10 % 10; // ?????? display_buffer[4] = match % 10; // ?????? display_buffer[5] = 16; // ??? display_buffer[6] = score2 / 10 % 10; // B??? display_buffer[7] = score2 % 10; // B??? } void timer0() interrupt 1 { TH0 = (65535 - 2000) / 256; // ??2ms?? TL0 = (65535 - 2000) % 256; updat = 1; // ???????? // ???? if(confirm_mode) { timeout_cnt++; if(timeout_cnt >= 100) { // ?1??? (100*2ms=200ms) timeout_cnt = 0; confirm_mode = 0; LED = 1; // ??LED } } } void delay(uint i) { uint j, k; for(j = 0; j < i; j++) { for(k = 0; k < 120; k++); } } // ??????(??????) void handle_key(uchar key) { // ??????????? if(key == 12 || key == 14) { // A???B?? if(key == 12) score1 = 0; // A?? if(key == 14) score2 = 0; // B?? update_display_buffer(); // ??????? confirm_mode = 0; LED = 1; // ??LED return; } if(confirm_mode) { // ??????? if(key == pending_key) { // ?????? if(pending_team == 0) { // A? if(score1 + pending_points <= 99) { score1 += pending_points; } else { score1 = 99; } } else { // B? if(score2 + pending_points <= 99) { score2 += pending_points; } else { score2 = 99; } } update_display_buffer(); // ??????? confirm_mode = 0; LED = 1; // ??LED timeout_cnt = 0; } else { // ?????????,??????? confirm_mode = 0; LED = 1; // ??LED timeout_cnt = 0; } } else { // ??????? switch(key) { case 0: // A+1 pending_key = 0; pending_points = 1; pending_team = 0; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; case 4: // A+2 pending_key = 4; pending_points = 2; pending_team = 0; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; case 8: // A+3 pending_key = 8; pending_points = 3; pending_team = 0; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; case 2: // B+1 pending_key = 2; pending_points = 1; pending_team = 1; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; case 6: // B+2 pending_key = 6; pending_points = 2; pending_team = 1; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; case 10: // B+3 pending_key = 10; pending_points = 3; pending_team = 1; confirm_mode = 1; LED = 0; // ??LED timeout_cnt = 0; break; // ???????? case 1: match = match + 10; update_display_buffer(); // ??????? break; case 3: match = match + 1; update_display_buffer(); // ??????? break; case 5: match = match % 10; update_display_buffer(); // ??????? break; case 7: match = match / 10 * 10; update_display_buffer(); // ??????? break; case 9: soud = 1; break; case 13: soud = 0; break; } } } void ketscan() { P1 = 0xF0; if(P1 != 0xF0) { delay(10); // ?? if(P1 != 0xF0) { bt++; } if(bt == 2) { bt = 0; switch(P1) { case 0xE0: KeyValue = 0; break; case 0xD0: KeyValue = 1; break; case 0xB0: KeyValue = 2; break; case 0x70: KeyValue = 3; break; } P1 = 0x0f; switch(P1) { case 0x0e: KeyValue = KeyValue; break; case 0x0D: KeyValue = KeyValue + 4; break; case 0x0b: KeyValue = KeyValue + 8; break; case 0x07: KeyValue = KeyValue + 12; break; } // ??????(??????) handle_key(KeyValue); while(P1 != 0x0f) { // ?????? } } } } void main(void) { Timer_init(); LED = 1; // ???LED?? update_display_buffer(); // ???????? while(1) { // ?????? if(updat == 1) { updat = 0; // ????????? vision(display_buffer[place_cnt], 1 << place_cnt); if(place_cnt < 7) { place_cnt++; } else { place_cnt = 0; } } // ???? ketscan(); } } ``` --- ### 解释 1. **提高定时器中断频率**: - 将定时器的中断周期从原来的 10ms 调整为 2ms,从而将刷新频率提升至约 50Hz。 - 修改了 `TH0` 和 `TL0` 的值以匹配新的定时器周期。 2. **移除不必要的延迟**: - 去掉了可能导致主循环阻塞的延迟操作,确保数码管的刷新逻辑能够快速响应。 3. **保持其他功能不变**: - 除了调整定时器和去除阻塞延迟外,其余逻辑保持不变,确保原有功能不受影响。 --- ###
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lcyw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值