- Qt 6.12
- Qt GRPC
- C++ Classes
- QGrpcHttp2Channel
- Qt 6.12.0 Reference Documentation

# QGrpcHttp2Channel Class

The QGrpcHttp2Channel class provides a HTTP/2 transport layer for gRPC™ communication. More...

Header: | `#include <QGrpcHttp2Channel>`
CMake: | `find_package(Qt6 REQUIRED COMPONENTS Grpc)` `target_link_libraries(mytarget PRIVATE Qt6::Grpc)`
Since: | Qt 6.5
In QML: | GrpcHttp2Channel
Inherits: | QAbstractGrpcChannel

- List of all members, including inherited members

## Public Functions

| QGrpcHttp2Channel(const QUrl &hostUri)
| QGrpcHttp2Channel(const QUrl &hostUri, const QGrpcChannelOptions &options)
virtual | ~QGrpcHttp2Channel() override
QUrl | hostUri() const

## Detailed Description

The QGrpcHttp2Channel class implements QAbstractGrpcChannel, enabling gRPC™ communication carried over HTTP/2 framing.

HTTP/2 introduces several advantages over its predecessor, HTTP/1.1, making QGrpcHttp2Channel well-suited for high-performance, real-time applications that require efficient communication, without sacrificing security or reliability, by using multiplexed TCP connections.

The channel can be customized with SSL support, a custom serializationFormat, or other options by constructing it with a QGrpcChannelOptions containing the required customizations.

Note: QGrpcChannelOptions::filterServerMetadata is enabled by default.

#### Transportation scheme

The QGrpcHttp2Channel implementation prefers different transportation methods based on the provided `hostUri`, scheme and options. The following criteria applies:

Scheme | Description | Default Port | Requirements | Example
--- | --- | --- | --- | ---
`http` | Unencrypted HTTP/2 over TCP | 80 | None | `http://localhost`
`https` | TLS-encrypted HTTP/2 over TCP | 443 | QSslSocket support AND (scheme OR sslConfiguration) | `https://localhost`
`unix` | Unix domain socket in filesystem path | ✗ | QLocalSocket support AND scheme | `unix:///tmp/grpc.socket`
`unix-abstract` | Unix domain socket in abstract namespace | ✗ | QLocalSocket support AND AbstractNamespace support AND scheme | `unix-abstract:app_grpc_channel`

#### Content-Type

The content-type in gRPC over HTTP/2 determines the message serialization format. It must start with `application/grpc` and can include a suffix. The format follows this scheme:

     "content-type": "application/grpc" [("+proto" / "+json" / {custom})]

For example:

- `application/grpc+proto` specifies Protobuf encoding.
- `application/grpc+json` specifies JSON encoding.

The serialization format can be configured either by specifying the `content-type` inside the metadata or by setting the serializationFormat directly. By default, the `application/grpc` content-type is used.

To configure QGrpcHttp2Channel with the JSON serialization format using `content-type` metadata:

     auto jsonChannel = std::make_shared<QGrpcHttp2Channel>(
         QUrl("http://localhost:50051"_L1),
         QGrpcChannelOptions().setMetadata({
             { "content-type"_ba, "application/grpc+json"_ba },
         })
     );

For a custom serializer and `content-type`, you can directly set the serialization format:

     class DummySerializer : public QAbstractProtobufSerializer
     {
         ...
     };
     QGrpcSerializationFormat dummyFormat("dummy", std::make_shared<DummySerializer>());

     auto dummyChannel = std::make_shared<QGrpcHttp2Channel>(
         QUrl("http://localhost:50051"_L1),
         QGrpcChannelOptions().setSerializationFormat(dummyFormat)
     );

This uses `DummySerializer` for encoding and decoding messages with the `dummy` suffix. For HTTP/2 transportation this results in the `application/grpc+dummy` content-type.

Note: Custom serializers require server support for the specified format.

#### Reserved metadata keys

Metadata is transmitted as HTTP/2 headers: keys are case-insensitive ASCII strings, values may be ASCII strings or binary data. The following keys are reserved by HTTP/2 or the gRPC protocol and are dropped from user metadata when the request is built:

- HTTP/2 pseudo-headers (any key starting with `:`).
- Any key with the `grpc-` or `qtgrpc-` prefix.
- `te`, `content-type`, `user-agent`.

A user-provided `content-type` is still consulted at channel construction for serializer auto-detection (see Content-Type); it is not, however, forwarded as a Custom-Metadata entry.

For more information on HTTP/2 headers, see RFC 7540, Section 8.1.2.

#### Receive windows

HTTP/2 flow control limits how much data a sender may transmit before the receiver acknowledges it. The channel advertises two such limits to the server, the receive windows:

- The stream window caps the unacknowledged data of a single RPC.
- The connection window caps the combined unacknowledged data of all RPCs, which share one connection.

A window limits data in flight, not the size of a transfer. Because acknowledgements take one network round trip, it also caps throughput:

     maximum throughput = window / round-trip time

Both windows are configured in bytes through environment variables:

- `QT_GRPC_HTTP2_STREAM_RECEIVE_WINDOW_SIZE` for the stream windows; (defaults to `4 MiB`)
- `QT_GRPC_HTTP2_CONNECTION_RECEIVE_WINDOW_SIZE` for the connection window; (defaults to four times the stream window, `16 MiB`)

Setting only `QT_GRPC_HTTP2_STREAM_RECEIVE_WINDOW_SIZE` automatically scales the connection window to four times the stream window. Set `QT_GRPC_HTTP2_CONNECTION_RECEIVE_WINDOW_SIZE` explicitly to use a different ratio.

The defaults saturate local networks and most internet paths. They fall short on fast links with long round-trip times. For example, an application receives large messages from a distant server:

     link: 1 Gbit/s (125 MB/s), 100 ms round-trip time

The server sends one stream window of data, then waits one round trip for the acknowledgement. With the default window it delivers at most 4 MiB every 100 ms:

     4 MiB / 0.1 s = 42 MB/s, 34% of the 125 MB/s the link carries

To saturate the link, the window must hold everything the link delivers during one round trip, the link's bandwidth-delay product (BDP):

     BDP = 125 MB/s x 0.1 s = 12.5 MB

     QT_GRPC_HTTP2_STREAM_RECEIVE_WINDOW_SIZE=12500000
     12.5 MB / 0.1 s = 125 MB/s, the link is saturated

Concurrent RPCs share a single connection receive window. As long as every stream is continuously read, the total in-flight data remains bounded by the BDP. If a stream is not read, however, its buffered data consumes part of the shared connection window and may block other streams. A good rule of thumb is to size the connection window for the sum of all concurrently active stream windows. For eight parallel transfers on the link above:

     QT_GRPC_HTTP2_STREAM_RECEIVE_WINDOW_SIZE=12500000       (12.5 MB = BDP)
     QT_GRPC_HTTP2_CONNECTION_RECEIVE_WINDOW_SIZE=100000000  (8 x 12.5 MB)

Each RPC can use the full 125 MB/s when it is the only active transfer. With eight concurrent RPCs, they share the link at roughly 15 MB/s each. In the worst case, if the application stops reading from every stream, the channel may buffer up to 100 MB of data.

Alternatively, size the stream windows so they collectively fit within a connection window equal to the BDP. This bounds the maximum buffered data, but limits every RPC to its allocated share, even when it transfers alone:

     QT_GRPC_HTTP2_STREAM_RECEIVE_WINDOW_SIZE=1562500        (12.5 MB / 8)
     QT_GRPC_HTTP2_CONNECTION_RECEIVE_WINDOW_SIZE=12500000   (= BDP)

Each RPC is limited to roughly 15 MB/s, whether it transfers alone or alongside seven others. The benefit is that the channel never buffers more than about 12.5 MB of unread data.

Use full-sized stream windows when minimizing transfer latency is more important than memory usage. Use smaller stream windows when bounding memory consumption is the priority. In either case, keep the connection window large enough to hold several stream windows; otherwise a single unread stream can exhaust the shared connection window and block all other RPCs.

Both windows accept values up to `2147483647` bytes. The stream window has a floor of `1024` bytes, which lets memory-constrained receivers bound per-stream buffering; the connection window has a floor of `65535` bytes, the protocol's initial window.

#### Environment variable fallbacks

Some channel settings can be configured through environment variables. They are evaluated when each channel is constructed. If an environment variable is not set, the built-in default is used.

Environment Variable | Option | Default fallback
--- | --- | ---
`QT_GRPC_MAXIMUM_RECEIVE_MESSAGE_SIZE` | maximumReceiveMessageSize | 4 MiB (4'194'304 Bytes)
`QT_GRPC_MAXIMUM_METADATA_SIZE` | None | 16 KiB (16'384 Bytes)
`QT_GRPC_INITIAL_RECONNECT_BACKOFF_MS` | None | 1s (1'000ms)
`QT_GRPC_MAXIMUM_RECONNECT_BACKOFF_MS` | None | 120s (120'000ms)
`QT_GRPC_CONNECT_TIMEOUT_MS` | None | 20s (20'000ms)
`QT_GRPC_HTTP2_STREAM_RECEIVE_WINDOW_SIZE` | None | 4 MiB (4'194'304 Bytes)
`QT_GRPC_HTTP2_CONNECTION_RECEIVE_WINDOW_SIZE` | None | 16 MiB (16'777'216 Bytes)

See also QAbstractGrpcChannel, QGrpcChannelOptions, and QGrpcSerializationFormat.

## Member Function Documentation

### `[explicit]` QGrpcHttp2Channel::QGrpcHttp2Channel(const QUrl &hostUri)

Constructs QGrpcHttp2Channel with hostUri. Please see the Transportation scheme section for more information.

### `[explicit]` QGrpcHttp2Channel::QGrpcHttp2Channel(const QUrl &hostUri, const QGrpcChannelOptions &options)

Constructs QGrpcHttp2Channel with hostUri and options. Please see the Transportation scheme section for more information.

### `[override virtual noexcept]` QGrpcHttp2Channel::~QGrpcHttp2Channel()

Destroys the QGrpcHttp2Channel object.

### QUrl QGrpcHttp2Channel::hostUri() const

Returns the host URI for this channel.

The URI is normalized according to the Transportation scheme: the scheme may be adjusted and a default port may be filled in. Passing the returned URI back to QGrpcHttp2Channel will select the same transport configuration.