基本概念 基本数据结构

【最佳答案】百科知识网:struct ngx_http_v2_connection_s {//HTTP/2连接数据结构ngx_connection_t*connectio基本数据结构1struct ngx_http_v2_connection_s {//HTTP/2连接数据结构ngx_connection_t*connection;ngx_http_connection_t*http_connection;ngx_uint_tprocessing;size_tsend_window;//发送窗口size_trecv_window;//接收窗口size_tinit_window;//初始化窗口大小 用于初始化stream recv_window以及发送给客户端SETTING帧中的SETTINGS_INITIAL_WINDOW_SIZEsize_tframe_size;ngx_queue_twaiting;ngx_http_v2_state_tstate;ngx_http_v2_hpack_thpack;ngx_pool_t*pool;ngx_http_v2_out_frame_t*free_frames;ngx_connection_t*free_fake_connections;ngx_http_v2_node_t**streams_index;ngx_http_v2_out_frame_t*last_out;ngx_queue_tdependencies;ngx_queue_tclosed;ngx_uint_tlast_sid;unsignedclosed_nodes:8;unsignedsettings_ack:1;unsignedblocked:1;unsignedgoaway:1;};
基本概念2流量控制窗口 (Flow Control Window)
HTTP/2中流量控制是通过每个流上每个发送端,保持一个窗口来实现的 。流量控制窗口是一个简单的整数值,指示发送端被允许传输的字节数;因此,它的大小是接收端的缓存能力的衡量 。
流量控制窗口对流和连接的流量控制窗口都适用 。发送端绝对不能发送超出接收端广播的流量控制窗口大小的可用空间长度的受流量控制影响的帧 。在各个流量控制窗口中没有可用空间时,可以发送带有END_STREAM标记的长度为0的帧(例如,空数据帧) 。WINDOW_UPDATE帧HTTP/2定义的帧类型的一种,用途是通知对端增加窗口值,WINDOW_UPDATE会指定增加的大小

算法描述:
发送端保有一个流量控制窗口(window)初始值 。初始值的设定请参考SETTING 帧的 SETTINGS_INITIAL_WINDOW_SIZE发送端每发送一个DATA帧,就把window递减,递减量为这个帧的大小 。如果当前window小于帧大小,那么这个帧就必须被拆分到不大于window,如果window等于0,就不能发送任何帧接收端可以发送 WINDOW_UPDATE帧给发送端,发送端以帧内指定的Window Size Increment作为增量,加到window上
我们来看看nginx 1.10.3中相关的源码
看看在各种情况下流量控制窗口值的变化 。
nginx定义了一个recv_window用来控制发送window_update帧的时机
nginx相关配置3指令:http2_body_preread_size
默认:http2_body_preread_size 65535
上下文:http server
用来定义 Nginx 在客户端收到 SETTINGS 帧之前可以接受多大的 DATA 帧,默认为 64KB 。
这个值设置为0,可能会导致一个POST bug 。详情见: https://imququ.com/post/nginx-http2-post-bug.html
请求处理部分4建立连接(connection)初始阶段NGINX 会设置整个连接的接收窗口和发送窗口的初始大小
h2c->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;// 默认65535 。这个就是协议中说到的流量控制窗口h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW;// 值为2^31-1接收窗口是nginx衡量自身接收能力定义出来的,并没有在协议中出现 。h2c->init_window = NGX_HTTP_V2_DEFAULT_WINDOW;// 65535
发送SETTING帧
在h2连接建立的初始阶段,nginx会发送一个SETTING帧,
SETTINGS_INITIAL_WINDOW_SIZE
值为h2scf->preread_size默认值是65535不能大于2%31-1
表明发送方的流级别的流量控制的初始窗口大小(以字节为单位) 。初始值是2^16-1(65535)字节 。这个设置影响所有流的窗口大小 。超过65535的窗口大小必选被视为类型是FLOW_CONTROL_ERROR的连接错误 。
发送WINDOW_UPDATE帧
2^31-65536Window Size Increment的大小为

建立流(stream)初始阶段建立连接之后,收到HEADERS帧时,就会创建一个流(stream)
接收到HEADER帧
stream->send_window = h2c->init_window;// 默认65535stream->recv_window = h2scf->preread_size;// 默认65535可配置流的发送窗口和接收窗口在初始化的时候,设置的值默认比较小,只有65535.
一般情况下,流建立后,客户端会给服务端发送一个SETTING帧,重新设置发送窗口大小
收发数据阶段接收到DATA帧h2c->recv_window -= h2c->state.lengthif (h2c->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) {//连接的接收窗口大小降到窗口最大值1/4时,即发送window_update帧if (ngx_http_v2_send_window_update(h2c, 0, NGX_HTTP_V2_MAX_WINDOW- h2c->recv_window)== NGX_ERROR){return ngx_http_v2_connection_error(h2c,NGX_HTTP_V2_INTERNAL_ERROR);}h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW;//发送完毕后,连接的接收窗口恢复到最大值 2^31-1}stream->recv_window -= h2c->state.length;if (stream->no_flow_control// 默认是0&& stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) //当前流的接收窗口大小降到窗口最大值1/4时,即发送window_update帧{if (ngx_http_v2_send_window_update(h2c, node->id,NGX_HTTP_V2_MAX_WINDOW- stream->recv_window)== NGX_ERROR){return ngx_http_v2_connection_error(h2c,NGX_HTTP_V2_INTERNAL_ERROR);}stream->recv_window = NGX_HTTP_V2_MAX_WINDOW;//发送完毕后,当前流的接收窗口恢复到最大值 2^31-1}