美文网首页
Netty http2 写Data Frame

Netty http2 写Data Frame

作者: 绝尘驹 | 来源:发表于2019-01-06 14:55 被阅读0次

    我们知道,HTTP2.0使用header桢表达HTTP header+request line,data frame表达Body。header桢和data桢使用相同的stream id组成一个完整的HTTP请求/响应包。这里的stream描述了一次请求和响应,相当于完成了一次HTTP/1.x的短连接请求和响应。

    Http1.x 的http request 在完成对请求头编码后,接下了就时对请求体编码为Data Frame了,如果时get请求,没有请求体,那就不需要发送data frame,所以我们可以知道,只有post请求才会发data frame。

    在把请求体编码成data frame时,一个重要的flag就时end_stream,需要告诉服务端这是不是该stream上的最后一个frame,因为在header frame 发送时,介绍了,
    有data frame,header frame 的end_stream 肯定为false,所以大部分在发送请求体即data frame时,end_stream为true,除非有trailers header,因为发完数据,还要发trailers header,那就时最后一个header frame,而且end_stream为true。

    编码pipeline

    HttpToHttp2ConnectionHandler->DefaultHttp2ConnectionEncoder->DefaultHttp2FrameWriter

    发送data frame时,需要判断end stream 是否为true,如果分

        //endStream 如果为ture,就不需要发data frame了。
        if (!endStream && msg instanceof HttpContent) {
                boolean isLastContent = false;
                HttpHeaders trailers = EmptyHttpHeaders.INSTANCE;
                Http2Headers http2Trailers = EmptyHttp2Headers.INSTANCE;
                if (msg instanceof LastHttpContent) {
                    isLastContent = true;
    
                    // Convert any trailing headers.
                    final LastHttpContent lastContent = (LastHttpContent) msg;
                    trailers = lastContent.trailingHeaders();
                    http2Trailers = HttpConversionUtil.toHttp2Headers(trailers, validateHeaders);
                }
    
                // Write the data
                final ByteBuf content = ((HttpContent) msg).content();
                endStream = isLastContent && trailers.isEmpty();
                release = false;
                encoder.writeData(ctx, currentStreamId, content, 0, endStream, promiseAggregator.newPromise());
    
                if (!trailers.isEmpty()) {
                    // Write trailing headers.
                    writeHeaders(ctx, encoder, currentStreamId, trailers, http2Trailers, true, promiseAggregator);
                }
            }
    

    encoder data frame 时,直接添加到stream对应的流控队列,代码如下:

    @Override
    public ChannelFuture writeData(final ChannelHandlerContext ctx, final int streamId, ByteBuf data, int padding,
            final boolean endOfStream, ChannelPromise promise) {
        final Http2Stream stream;
        try {
            stream = requireStream(streamId);
    
            // Verify that the stream is in the appropriate state for sending DATA frames.
            switch (stream.state()) {
                case OPEN:
                case HALF_CLOSED_REMOTE:
                    // Allowed sending DATA frames in these states.
                    break;
                default:
                    throw new IllegalStateException("Stream " + stream.id() + " in unexpected state " + stream.state());
            }
        } catch (Throwable e) {
            data.release();
            return promise.setFailure(e);
        }
    
        // Hand control of the frame to the flow controller.
        flowController().addFlowControlled(stream,
                new FlowControlledData(stream, data, padding, endOfStream, promise));
        return promise;
    }
    

    添加到队列后,代表write操作就结束咯,后面在flush时先把流控队列里的数据写到netty的循环队列,后面的 ctx.flush(); 会从循环队列写到os的写缓冲区。

    @Override
    public void flush(ChannelHandlerContext ctx) {
        try {
            // Trigger pending writes in the remote flow controller.
            //这里时流控机制,需要选择哪些frame可以发送,通过后面的流控来具体分析
            encoder.flowController().writePendingBytes();
            ctx.flush();
        } catch (Http2Exception e) {
            onError(ctx, true, e);
        } catch (Throwable cause) {
            onError(ctx, true, connectionError(INTERNAL_ERROR, cause, "Error flushing"));
        }
    }
    

    相关文章

      网友评论

          本文标题:Netty http2 写Data Frame

          本文链接:https://www.haomeiwen.com/subject/pnrzmftx.html