写在前面
学习一个框架, 首先是要去安装, 跑通这个框架的基本测试用例, 这次尝试搞一下 echo 服务器, 以及并发版本的实现, 这些例子在 brpc 代码库的example/
目录下都有, 其实主要需要关注的就是echo_c++
, multithread-echo_c++
和streaming-echo_c++
这三个例子, 包括了主要的 brpc 使用场景, 下面分别分析一下.
前置知识
gflags
是一个 Google 开源的命令行参数解析库, 默认采用长格式, brpc 中主要的命令行参数解析任务都是通过这个库实现的.
这里先提几个概念, 在一个主要的命令行程序调用过程中, 有下面几个术语, 看这个例子: (参考了 gflags 的文档, 位于gflags/doc/index.html
)
fgrep -l -f /var/tmp/foo johannes brahms
- 命令command, 即
fgrep
- 选项option, 即-l 和-f, 其中-l 是不带参数的选项, -f 带有一个参数
- 参数 argument, 即-f 选项后面的值, 通过空格分割, 后面的johannes和brahms都是 fgrep 命令的参数
这里跑一下官方代码库中的实例, 即test/config/main.cc
文件, 这里我改动了一下, 方便熟悉功能.
#include <gflags/gflags.h>
#include <iostream>
// 通过宏定义的方式设置要解析的参数, 下面的例子中, message 为选项的名称, 源码文件中`FLAGS_message`为具体的值, 第三个参数为描述信息, 在之后的`--help`中提到了
DEFINE_string(message, "Hello World!", "The message to print");
static bool ValidateMessage(const char *flagname, const std::string &message) {
if (!message.empty()) {
return true;
}
printf("error, empty msg\n");
return false;
}
DEFINE_validator(message, ValidateMessage);
int main(int argc, char **argv) {
gflags::SetUsageMessage(
"Test CMake configuration of gflags library (gflags-config.cmake)");
gflags::SetVersionString("0.1");
gflags::ParseCommandLineFlags(&argc, &argv, true);
std::cout << FLAGS_message << std::endl;
gflags::ShutDownCommandLineFlags();
return 0;
}
结果发现直接用 cmake 竟然报错了, 发现 cmake 文件最后一行: target_link_libraries (foo gflags::gflags)
出了问题, 应该是: target_link_libraries (foo gflags)
.
构建一下:
mkdir build
cd build
cmake ..
make
测试一下:
==> ./foo
Hello World!
==> ./foo --message=hello
hello
==> ./foo --message world
world
==> ./foo --message
ERROR: flag '--message' is missing its argument; flag description: The message to print
==> ./foo --message ""
error, empty msg
ERROR: failed validation of new value '' for flag 'message'
用--help
可以打印全部参数信息: (但是不太准确, 一堆冗余信息)
==> ./foo --help
foo: Test CMake configuration of gflags library (gflags-config.cmake)
Flags from /Users/hep/code/c-cpp_Proj/gflags/test/config/main.cc:
-message (The message to print) type: string default: "Hello World!" # 这里显示了描述信息以及选项的默认值
Flags from /tmp/gflags-20211021-3963-1mi18ai/gflags-2.2.2/src/gflags.cc:
-flagfile (load flags from file) type: string default: ""
-fromenv (set flags from the environment [use 'export FLAGS_flag1=value'])
type: string default: ""
-tryfromenv (set flags from the environment if present) type: string
default: ""
-undefok (comma-separated list of flag names that it is okay to specify on
the command line even if the program does not define a flag with that
name. IMPORTANT: flags in this list that have arguments MUST use the
flag=value format) type: string default: ""
Flags from /tmp/gflags-20211021-3963-1mi18ai/gflags-2.2.2/src/gflags_completions.cc:
-tab_completion_columns (Number of columns to use in output for tab
completion) type: int32 default: 80
-tab_completion_word (If non-empty, HandleCommandLineCompletions() will
hijack the process and attempt to do bash-style command line flag
completion on this value.) type: string default: ""
Flags from /tmp/gflags-20211021-3963-1mi18ai/gflags-2.2.2/src/gflags_reporting.cc:
-help (show help on all flags [tip: all flags can have two dashes])
type: bool default: false currently: true
-helpfull (show help on all flags -- same as -help) type: bool
default: false
-helpmatch (show help on modules whose name contains the specified substr)
type: string default: ""
-helpon (show help on the modules named by this flag value) type: string
default: ""
-helppackage (show help on all modules in the main package) type: bool
default: false
-helpshort (show help on only the main module for this program) type: bool
default: false
-helpxml (produce an xml version of help) type: bool default: false
-version (show version and build info and exit) type: bool default: false
bthread
brpc 内置的线程库, 其实就是对 Pthread 的一个封装, 但是改变了 Pthread 中用户级线程和系统级(核心级)线程的一一对应, 改成了 M:N 的关系, 这样应该能让线程切换的效率提高, 具体这里就不深究了, 文档的brpc in Depth
部分有提到.
protobuf
版本就是构建 brpc 时候所用的版本, 即21.12. 目前最新版 24 brpc 并不支持
这个是 Google 的 grpc 库中数据交换的基本格式, 其实就是对 C 的基本数据类型的一层封装, 使得数据可以以规定好的二进制格式传输, 提高了空间利用率, 简单熟悉一下这个格式:
基本的 echo 服务器
其实跟传统的echo没啥太大区别