Netty http2 写Data Frame

我们知道,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)