| # FlatBuffers messages and RPC | |
| [中文版](../cn/flatbuffers.md) | |
| bRPC provides optional IOBuf-backed FlatBuffers messages, builders, service | |
| descriptors, and the `fb_rpc` transport. The implementation builds on | |
| [apache/brpc#3196](https://github.com/apache/brpc/pull/3196) and | |
| [apache/brpc#3197](https://github.com/apache/brpc/pull/3197), while preserving | |
| Protocol's existing protobuf callback signatures. | |
| ## Enable FlatBuffers | |
| FlatBuffers is **OFF by default**. Enable it when building bRPC, then build the | |
| client/server against that same library and generated configuration header. | |
| Adding `-DBRPC_WITH_FLATBUFFERS=1` to an application is not a substitute: the | |
| FlatBuffers APIs are compiled into the library. The option does not change the | |
| layout of Channel, Controller or Server, so protobuf-only code works with either | |
| build, and code that uses FlatBuffers APIs fails to link against a library | |
| built without them. | |
| | Build system | Enable option | Exported runtime prefix | | |
| | --- | --- | --- | | |
| | CMake | `-DWITH_FLATBUFFERS=ON` | `cmake --install` prefix | | |
| | Make | `config_brpc.sh --with-flatbuffers` | `<checkout>/output` | | |
| | Bazel | `--define=BRPC_WITH_FLATBUFFERS=true` on build/test commands | Bazel outputs, not an install prefix for the standalone example | | |
| ### Dependencies and versions | |
| Prepare the normal bRPC dependencies described in [Getting started](getting_started.md): | |
| a C++ toolchain, Protobuf compiler/development libraries, gflags, LevelDB, | |
| OpenSSL and zlib. FlatBuffers RPC does **not** remove the Protobuf dependency. | |
| FlatBuffers support requires **C++17 or later**, for the library and for every | |
| translation unit that includes the FlatBuffers or generated headers. CMake and | |
| `config_brpc.sh --with-flatbuffers` select C++17 automatically, and the headers | |
| stop with `#error` below C++17. This keeps over-aligned objects on the same | |
| aligned `new` everywhere instead of mixing C++14 and C++17 allocation rules. | |
| Protobuf-only builds keep their current standard. | |
| | Component | Additional requirement | | |
| | --- | --- | | |
| | bRPC message/RPC runtime | FlatBuffers headers; no `libflatbuffers` linkage | | |
| | Official schema generation | `flatc` matching the runtime headers | | |
| | bRPC service generation | `brpc_flatc`, built with matching official headers and `libflatbuffers` | | |
| | Example smoke | Python 3; no GoogleTest requirement | | |
| | Library unit tests | GoogleTest and the project's test dependencies | | |
| The repository's Bazel/ON gate pins FlatBuffers **25.2.10**. Use a complete, | |
| matching installation to reproduce it; never remove the generated header's | |
| version assertions. CMake runtime tests use `FLATBUFFERS_FLATC_EXECUTABLE`, | |
| whereas generator acceptance and the example use `FLATC_EXECUTABLE`. | |
| `BRPC_FLATC_EXECUTABLE` always means the bRPC generator, not official `flatc`. | |
| Use the same Protobuf installation across all builds. With `Protobuf_VERSION > | |
| 4.21`, Abseil is also required, and the generator and example builds need | |
| Protobuf's CMake config package. CMake 3.16+ is enough to build; the CTest | |
| commands below use 3.17+ for `--no-tests=error` (with 3.16, run `smoke.py` | |
| directly). Use a single-configuration generator such as Unix Makefiles or Ninja. | |
| The runtime depends on FlatBuffers builder internals and supports only | |
| 25.2.10; other versions fail at compile time. Regenerate incompatible headers | |
| rather than removing or weakening upstream version assertions. Bzlmod and | |
| WORKSPACE use the same checksum-pinned archive; this avoids the gRPC, other | |
| language tools and conflicting BoringSSL dependencies that `bazel_dep` would add. | |
| To use another FlatBuffers version, update the version checks in the runtime, | |
| the generator and the codegen tests, then run `tools/flatbuffers/verify.sh` | |
| against that version. See the generator | |
| [README](../../tools/flatbuffers/README.md#using-another-flatbuffers-version) | |
| for the steps, using 23.5.26 as an example. They apply to CMake builds only. | |
| ### CMake runtime build | |
| Run from a checkout, with a working compiler selected through `CC`/`CXX` if | |
| necessary. The CMake build keeps generated files in its build directory, and the | |
| example bindings and binaries stay in `WORK`. Install the runtime into a prefix: | |
| the build tree alone does not contain the public headers or `config.h` that the | |
| standalone example needs. | |
| Replace the prefixes below with your installations (`include/`, `lib/` or | |
| `lib64/`); one prefix may serve several dependencies. | |
| ```sh | |
| REPO="$PWD" | |
| DEPS=/absolute/path/to/dependency-prefix | |
| FB=/absolute/path/to/flatbuffers-prefix | |
| OPENSSL=/absolute/path/to/openssl-prefix | |
| WORK="$(mktemp -d "${TMPDIR:-/tmp}/brpc-benchmark-fb.XXXXXX")" | |
| JOBS=2 | |
| printf 'WORK=%s\n' "$WORK" | |
| ``` | |
| If FlatBuffers is not installed, build a matching official source checkout first | |
| (skip this block when `FB` already contains the required headers, compiler and | |
| library). `FB` must be a writable installation prefix, not the source directory: | |
| ```sh | |
| FB_SOURCE=/absolute/path/to/flatbuffers-25.2.10-source | |
| cmake -S "$FB_SOURCE" -B "$WORK/flatbuffers" \ | |
| -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ | |
| -DCMAKE_INSTALL_PREFIX="$FB" -DCMAKE_INSTALL_LIBDIR=lib \ | |
| -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATC=ON \ | |
| -DFLATBUFFERS_BUILD_FLATLIB=ON -DFLATBUFFERS_BUILD_SHAREDLIB=OFF \ | |
| -DFLATBUFFERS_INSTALL=ON -DFLATBUFFERS_LIBCXX_WITH_CLANG=OFF | |
| cmake --build "$WORK/flatbuffers" --parallel "$JOBS" | |
| cmake --install "$WORK/flatbuffers" | |
| "$FB/bin/flatc" --version | |
| ``` | |
| Build the runtime without the unit-test dependencies: | |
| ```sh | |
| cmake -S "$REPO" -B "$WORK/runtime" \ | |
| -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ | |
| -DCMAKE_PREFIX_PATH="$DEPS;$FB;$OPENSSL" \ | |
| -DOPENSSL_ROOT_DIR="$OPENSSL" \ | |
| -DCMAKE_INSTALL_PREFIX="$WORK/prefix" \ | |
| -DWITH_FLATBUFFERS=ON -DBUILD_SHARED_LIBS=OFF \ | |
| -DFLATBUFFERS_INCLUDE_DIR="$FB/include" \ | |
| -DBUILD_UNIT_TESTS=OFF -DDOWNLOAD_GTEST=OFF -DBUILD_BRPC_TOOLS=OFF | |
| cmake --build "$WORK/runtime" --parallel "$JOBS" | |
| cmake --install "$WORK/runtime" | |
| grep -E '^#define BRPC_WITH_FLATBUFFERS +1$' "$WORK/prefix/include/butil/config.h" | |
| ``` | |
| The final check must print `#define BRPC_WITH_FLATBUFFERS 1`. Public headers live | |
| in `brpc/flatbuffers/`: `message.h` for messages/builders and `service.h` for | |
| services/descriptors. The configuration macro is always 0 or 1; use `#if`, not | |
| `#ifdef`. The policy argument above is an optional compatibility setting for | |
| older dependencies under CMake 4, not a FlatBuffers switch or a replacement for | |
| required dependency versions. | |
| ### Make and Bazel alternatives | |
| In a separate writable checkout, using the same dependency prefixes: | |
| ```sh | |
| sh config_brpc.sh --with-flatbuffers \ | |
| --headers="$FB/include $DEPS/include $OPENSSL/include" \ | |
| --libs="$DEPS/lib $OPENSSL/lib" --cc="${CC:-cc}" --cxx="${CXX:-c++}" | |
| make -j"$JOBS" | |
| ``` | |
| Use `lib64` or the platform's library directory where appropriate. The resulting | |
| `output/` can replace `WORK/prefix` in the example command below. Make | |
| unit tests take `FLATC="$FB/bin/flatc"` and require installed GoogleTest libraries | |
| and gperftools, not just GoogleTest sources; their `test/libbrpc.dbg.*` must also | |
| be loadable. The ON runner below builds GoogleTest, sets the test library path, | |
| and validates reports; system test dependencies such as gperftools must already | |
| be installed. | |
| Bazel supplies its pinned dependencies; pass the feature flag to both commands: | |
| ```sh | |
| bazel build --define=BRPC_WITH_FLATBUFFERS=true //:brpc | |
| bazel test --define=BRPC_WITH_FLATBUFFERS=true --cache_test_results=no \ | |
| //test:brpc_flatbuffers_unittest //test:brpc_flatbuffers_protocol_unittest | |
| ``` | |
| These Bazel targets verify the library, not the standalone example. Do not use a | |
| raw `bazel-bin` directory as `BRPC_ROOT`; the example requires the include/lib | |
| layout of a CMake install prefix or a Make `output/` directory. | |
| ## Verify with the client/server example | |
| [example/benchmark_fb](../../example/benchmark_fb/README.md) runs a **bounded | |
| functional check** by default and has an opt-in timed mode that compares `fb_rpc` | |
| with an equivalent `baidu_std` service. Its [schema](../../example/benchmark_fb/echo.fbs) | |
| uses `BenchmarkService.Echo` with explicit wire ID 7. The | |
| [server](../../example/benchmark_fb/server.cpp) calls `AddFlatBuffersService`; | |
| the [client](../../example/benchmark_fb/client.cpp) uses the generated | |
| `BenchmarkService::Stub` and `fb_rpc` channel. | |
| ### Generate, build and smoke-test | |
| Continue in the same shell with the variables and runtime from above. An | |
| existing compatible FB ON runtime may be used instead by changing `BRPC_ROOT`. | |
| Build the bRPC generator, then the example: | |
| ```sh | |
| cmake -S "$REPO/tools/flatbuffers" -B "$WORK/codegen" \ | |
| -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ | |
| -DBUILD_TESTING=OFF \ | |
| -DCMAKE_PREFIX_PATH="$FB;$DEPS" \ | |
| -DFLATBUFFERS_INCLUDE_DIR="$FB/include" | |
| cmake --build "$WORK/codegen" --parallel "$JOBS" | |
| cmake -S "$REPO/example/benchmark_fb" -B "$WORK/example" \ | |
| -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ | |
| -DBUILD_TESTING=ON \ | |
| -DCMAKE_PREFIX_PATH="$DEPS;$FB;$OPENSSL" \ | |
| -DOPENSSL_ROOT_DIR="$OPENSSL" \ | |
| -DBRPC_ROOT="$WORK/prefix" \ | |
| -DFLATBUFFERS_INCLUDE_DIR="$FB/include" \ | |
| -DFLATC_EXECUTABLE="$FB/bin/flatc" \ | |
| -DBRPC_FLATC_EXECUTABLE="$WORK/codegen/brpc_flatc" | |
| cmake --build "$WORK/example" --parallel "$JOBS" | |
| (cd "$WORK/example" && ctest -V --no-tests=error --output-on-failure -R '^benchmark_fb_smoke$') | |
| ``` | |
| The example build runs **both** generators. `flatc` produces `echo_generated.h`; | |
| `brpc_flatc` produces `echo.brpc.fb.h/.cpp`, all under `WORK/example/generated/`. | |
| Do not commit them or reuse stale generated headers after changing versions. | |
| If library discovery is ambiguous, pass `FLATBUFFERS_LIBRARY` explicitly when | |
| configuring `brpc_flatc`. See the [generator guide](../../tools/flatbuffers/README.md) | |
| for included schemas, explicit IDs and generator acceptance tests. | |
| Success means **one named CTest passed**, exit status 0, and this output: | |
| ```text | |
| benchmark_fb smoke passed: 13 verified replies, 2 schema rejections, clean shutdown | |
| ``` | |
| That is 15 RPCs, not 15 CTests. `No tests were found` is not a pass. What the | |
| smoke test checks, its deadlines and how to run it without CTest are in the | |
| [example README](../../example/benchmark_fb/README.md#smoke-test). | |
| The example links `libbrpc.a` by default. For `LINK_SO=ON`, build and install the | |
| runtime with `BUILD_SHARED_LIBS=ON` and the `brpc-shared` target first; `LINK_SO` | |
| alone cannot create a shared runtime. | |
| ### Run the programs separately | |
| The [example README](../../example/benchmark_fb/README.md#run-separately) lists the | |
| manual client commands, their expected results and the bounded client/server | |
| options. | |
| ## Additional tests and the ON gate | |
| For library unit tests, configure with `BUILD_UNIT_TESTS=ON`, | |
| `FLATBUFFERS_FLATC_EXECUTABLE` pointing to the matching official compiler, and | |
| `BRPC_SYSTEM_GTEST_SOURCE_DIR` pointing to GoogleTest sources when | |
| `DOWNLOAD_GTEST=OFF`. Build and run `brpc_flatbuffers_unittest` and | |
| `brpc_flatbuffers_protocol_unittest`; enabling the library alone does not run them. | |
| For the complete CMake path (both library suites, two codegen tests, and the | |
| example smoke), the shared [ON runner](../../.github/scripts/flatbuffers-on.py) | |
| can use the prefixes above. This full CMake gate requires **CMake/CTest 3.21+** | |
| for JUnit XML output (`--output-junit`). **Its work directory must not already | |
| exist**: | |
| ```sh | |
| python3 "$REPO/.github/scripts/flatbuffers-on.py" \ | |
| --build-system cmake --source "$REPO" --work "$WORK/on-gate" --jobs "$JOBS" \ | |
| --flatbuffers-prefix "$FB" \ | |
| --dependency-prefix "$DEPS" --dependency-prefix "$OPENSSL" | |
| ``` | |
| This gate requires FlatBuffers 25.2.10. Omit `--flatbuffers-prefix` to let it | |
| download/checksum/build that version; GoogleTest defaults to a checksum-pinned | |
| 1.14.0 download, or can be supplied with `--gtest-source`. Normal platform | |
| dependencies must already be installed. Make/Bazel modes validate the two | |
| library suites; only CMake mode also builds the generator and example. Inspect | |
| `WORK/on-gate/evidence/summary.json` for `status: passed`, all required test names, | |
| nonzero executed counts and zero failed/skipped cases. Commands, logs and XML | |
| reports are retained even on failure. Empty/filtered/skipped runs are rejected. | |
| The [workflow](../../.github/workflows/flatbuffers-on.yml) runs Linux CMake/Make | |
| with GCC and Clang, Linux Bazel with GCC, and macOS CMake. A local gate pass does | |
| not imply the hosted GitHub matrix or a different dependency combination passed. | |
| ## Troubleshooting | |
| | Symptom | Check / action | | |
| | --- | --- | | |
| | `BRPC_ROOT is not FlatBuffers-enabled` or missing FB symbols | Rebuild bRPC with the enable option, then rebuild all consumers. Check the installed prefix's `include/butil/config.h`; do not force the macro or mix an ON header with an OFF library. | | |
| | Missing `flatbuffers/idl.h` or `libflatbuffers` | The service generator needs the full official development installation, not only the runtime headers. Set `FLATBUFFERS_INCLUDE_DIR` and, if needed, `FLATBUFFERS_LIBRARY`. | | |
| | Header/compiler version mismatch | Check `flatc --version`, select matching headers/compiler/library, and regenerate bindings in a fresh build directory. Do not delete upstream version checks. | | |
| | Missing Protobuf/Abseil headers or link symbols | Use one compatible Protobuf installation throughout and expose its CMake config and Abseil prefixes. Do not mix system and private headers/libraries. | | |
| | OpenSSL not found on macOS | Set `OPENSSL_ROOT_DIR` and include the actual installed prefix in `CMAKE_PREFIX_PATH`; check compiler/SDK/architecture consistency. | | |
| | Cannot write `src/butil/config.h.tmp` | Only `config_brpc.sh` (Make) writes this file into the checkout, so it needs a writable source tree. Use a private copy; CMake keeps `config.h` in its build directory. | | |
| | Old dependency policy error with CMake 4 | Try the appropriate `CMAKE_POLICY_VERSION_MINIMUM` compatibility setting for that dependency, or update it; this does not change the required C++ or dependency versions. | | |
| | `No tests were found` | Use the example build directory, configure `BUILD_TESTING=ON`, build the executables, then run the named test or `smoke.py` directly. | | |
| | `LINK_SO=ON` cannot find a library or the loader fails | Build `brpc-shared` with runtime `BUILD_SHARED_LIBS=ON` first. Check the shared library's dependencies and runtime search paths. | | |
| | Connection refused/timeout | Wait for the readiness line, use its current port on the same host/container, and check the server's finite lifetime. These are not successful schema rejections. | | |
| Flatc 2.0.x emits unqualified `flatbuffers::` names. Keep business schemas outside | |
| the `brpc` namespace (for example `myapp.rpc`); do not depend on include order to | |
| avoid shadowing. | |
| ## Message construction and ownership | |
| Generate `*_generated.h` with upstream `flatc --cpp`. Pass a | |
| `brpc::flatbuffers::MessageBuilder` to the generated `Create...` functions, | |
| then call `Finish(root)` and `ReleaseMessage()`. | |
| * For large messages, pass the expected size to the constructor, for example | |
| `MessageBuilder builder(payload_size + 256);`. The default initial size is | |
| 1 KB, and each growth allocates a new buffer and copies the existing bytes. | |
| In our benchmark, building a 1 MB reply without a reserved size doubled | |
| server CPU, mostly from repeated allocation and page faults. | |
| * `ReleaseMessage()` returns a move-only Message without copying payload bytes. | |
| Its IOBuf block reference survives builder reuse or destruction. | |
| * Moves leave the source Message or builder reusable. Moving a shared-string | |
| builder clears its deduplication cache but preserves existing offsets. | |
| * `Message::CopyFrom` and `MergeFrom` share a ref-counted IOBuf block without | |
| copying payload or metadata. Changes through one alias affect all others; | |
| concurrent reads and writes require external synchronization. | |
| * Importing a regular `::flatbuffers::FlatBufferBuilder` copies payload and | |
| scratch, preserving unfinished tables. The original allocator frees the old | |
| storage and is destroyed if owned by the source builder. Import neither | |
| guesses between `free` and `delete[]` nor requires a payload prefix. | |
| * Use only MessageBuilder's own move, swap, and release operations. Base-class | |
| transfers and inherited raw-buffer releases can leave a detached buffer | |
| pointing to the member allocator. | |
| * Released payloads have a 64-byte zeroed prefix. `reduce_meta_size_and_get_buf` | |
| can shrink it without changing the payload address or bytes. Attempts to grow | |
| it fail without changing the message. | |
| * Serializing a const Message shares its storage with the output IOBuf; it is | |
| not copy-on-write. Do not modify payload or metadata while readers or | |
| serialized buffers still use it. | |
| * Sizes are checked before conversion to SingleIOBuf's uint32_t length. | |
| Allocation failure in SlabAllocator or a builder terminates the process even | |
| in release builds, regardless of `crash_on_fatal_log`: FlatBuffers' | |
| `vector_downward` cannot continue after a null allocation. Allocation failure | |
| when copying during parsing returns false and leaves the Message unchanged. | |
| `ParseFbFromIOBUF` checks lengths and framing and retains a storage reference; | |
| it does not limit received message sizes. Bound untrusted `msg_size` with your | |
| max-message-size policy before parsing: fragmented or unaligned input is copied | |
| to new storage before schema validation. | |
| Parsing shares contiguous input when its payload is 64-byte aligned. Builder | |
| allocations have this alignment, but finished payloads need only meet their | |
| schema's alignment, so local messages may still require a copy. Alignment | |
| requirements above 64 bytes are unsupported. | |
| **Framing is not schema verification.** Before reading untrusted data, call | |
| `msg.Verify<YourRoot>()` and use `GetRoot<YourRoot>()` or | |
| `GetMutableRoot<YourRoot>()` only if it succeeds. Optional strings/vectors can | |
| still be null in valid messages. Failed framing checks leave the Message intact. | |
| ## Service IDs and generation | |
| `BrpcDescriptorTable` holds a namespace, service name, whitespace-separated | |
| method names, and unique nonnegative int32 IDs. Handwritten descriptors may | |
| use an empty ID list to assign IDs in declaration order; generated services | |
| require explicit IDs: | |
| ```fbs | |
| rpc_service BenchmarkService { | |
| First(Request):Response (id: 2); | |
| Second(Request):Response (id: 5); | |
| } | |
| ``` | |
| * `descriptor.method(position)` returns methods in declaration order. | |
| * `method.index()` is the stable wire ID, not an array index. | |
| * Look up sparse IDs with `descriptor.FindMethodByIndex(id)`, not by indexing | |
| a dense array with a wire ID. | |
| * Do not reuse removed method IDs or change existing IDs when reordering | |
| methods. | |
| * Namespaces `a.b` and `a.b.` normalize to the same service name; an empty | |
| namespace means global scope. Method full names include the service name. | |
| Service hashes use the normalized full name and MurmurHash3 seed 1. Keep | |
| service names stable when persisting or transmitting IDs. | |
| * Descriptors own methods through RAII and cannot be reinitialized after | |
| success. | |
| Generated accessors use thread-safe function-local static initialization. | |
| The companion generator in `tools/flatbuffers/` uses the upstream parser to | |
| produce service bindings. It is independently built; only that optional tool | |
| needs `libflatbuffers`. See its [README](../../tools/flatbuffers/README.md) for | |
| commands and limitations. Generated dispatch verifies requests, rejects | |
| unknown/foreign methods, and runs non-null completion callbacks on failure, | |
| including unimplemented methods. Successful implementations own completion and | |
| must run their callback exactly once. | |
| ## Network RPC | |
| The class layout of Channel, Controller and Server is the same with the option ON | |
| or OFF; the ON validation checks this. Register generated services with | |
| `server.AddFlatBuffersService(&service, SERVER_DOESNT_OWN_SERVICE)`. Use | |
| `ChannelOptions::protocol = "fb_rpc"` and pass that `brpc::Channel` to a | |
| generated stub (`Echo::Stub stub(&channel);`). The stub wraps the channel in a | |
| library adapter that calls `Channel::FBCallMethod`; | |
| `Controller::flatbuffers_method()` returns the typed descriptor, while the | |
| protobuf `Controller::method()` remains null. Manually supplied descriptors | |
| must outlive their calls, including retries and backup requests. | |
| Service registration is separate from protobuf's AddService and ListServices | |
| APIs. Add/remove/clear require a stopped (READY) server, not a server still | |
| STOPPING; management operations must be externally serialized. Ownership | |
| transfers only after successful registration. `RemoveFlatBuffersService` | |
| deletes an owned service, while Stop/Join keep registrations for restart. | |
| `GetFlatBuffersServiceCount()` and `ListFlatBuffersServices()` report this | |
| separate registry; `ListServices()` and `/list` stay protobuf-only, while | |
| `ServerStatistics::user_service_count` counts both kinds. Duplicate service | |
| IDs (including hash collisions) and conflicting full protobuf/FlatBuffers method | |
| names are rejected. FlatBuffers methods use the same per-method properties as | |
| protobuf methods, so `MaxConcurrencyOf()`, `IgnoreEovercrowdedOf()`, the | |
| server-wide and default method concurrency limits, method bvars and `/status` | |
| all cover them. Other protocols cannot call a FlatBuffers method by name. | |
| The transport supports synchronous/asynchronous calls, retries, backup requests, | |
| single/pooled/short connections and request/response attachments. It allocates a | |
| small independent header for each send and shares payload storage; it never | |
| rewrites a const request's metadata prefix. Thus retries and concurrent calls | |
| can safely share an immutable request. The application must still keep each | |
| response and Controller alive until completion. | |
| Framing validates lengths, not application schemas. Generated services verify | |
| requests before dispatch. Handwritten services must do the same. Callers must | |
| verify received response schemas before using root accessors; an RPC succeeding | |
| does not replace `response.Verify<Response>()`. | |
| Authentication, compression, checksums and streaming are not supported and are | |
| rejected rather than silently ignored. FlatBuffers services cannot be accessed | |
| through the internal, builtin-only port. SelectiveChannel/ParallelChannel, | |
| HTTP/JSON mapping and RPC-dump replay are not provided by this transport. | |
| Log IDs, user fields and distributed-tracing metadata are not transmitted. | |
| For a complete generated client/server, follow | |
| [Verify with the client/server example](#verify-with-the-clientserver-example) | |
| above. The example demonstrates these APIs; its optional timed mode compares | |
| `fb_rpc` with an equivalent `baidu_std` service. | |
| ### FRPC framing and compatibility | |
| A frame is `[12-byte header][metadata][message][attachment]`. The header contains | |
| `FRPC`, a uint32 body size and a uint32 metadata size; body size excludes the | |
| 12-byte header but includes all three following sections. Both header | |
| integers are big-endian (network byte order), as in the `baidu_std` header. | |
| The metadata is a FlatBuffers table defined in | |
| [flatbuffers_rpc_meta.fbs](../../src/brpc/policy/flatbuffers_rpc_meta.fbs): | |
| * `RequestMeta`: service ID, method ID, message size, attachment size and | |
| correlation ID. | |
| * `ResponseMeta`: error code, message size, attachment size and correlation ID. | |
| The checked-in `flatbuffers_rpc_meta_generated.h` is generated by `flatc` | |
| 25.2.10; after editing the schema, regenerate it with | |
| `tools/flatbuffers/gen_rpc_meta.sh`. The ON gate fails if the header is stale. | |
| New fields must be appended to a table; do not reorder, renumber, retype or | |
| remove existing fields. Readers verify the table and ignore fields they do not | |
| know, so a peer with a newer schema stays compatible. Metadata that fails | |
| verification closes the connection. Sizes above `INT32_MAX`, an inconsistent | |
| payload length or an excessive body are rejected. Error replies have a nonzero | |
| error code and no payload. Method IDs are sparse wire IDs, never | |
| array positions: adding, deleting or reordering declarations preserves surviving | |
| IDs only when explicit IDs are retained. This does not make legacy ordinal-ID | |
| schemas compatible, and removed IDs must never be reused. | |
| The magic is `FRPC`, not `BRPC`; like `PRPC` for `baidu_std`, it lets the server | |
| detect the protocol on a port shared with other protocols. New connections try | |
| `fb_rpc` right after `baidu_std` rather than in ID order (its ID is 30). This format does not | |
| promise compatibility with earlier experimental FRPC variants, which used | |
| different magic, service hashes or byte orders. The library's global Protocol hook signatures remain | |
| unchanged, so existing protocol callback implementations need no adaptation. | |
| Private numeric protocol IDs must not overlap newly assigned builtin IDs; | |
| `PROTOCOL_FLATBUFFERS_RPC` uses ID 30. |