免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Apache Thrift C++ 库完全指南:构建、链接、SSL 加密与 TUuid 实践

Apache Thrift C++ 库完全指南:构建、链接、SSL 加密与 TUuid 实践 Apache Thrift C 库完全指南构建、链接、SSL 加密与 TUuid 实践【免费下载链接】thriftApache Thrift项目地址: https://gitcode.com/GitHub_Trending/thr/thrift导读本文以 Apache Thrift 仓库中 lib/cpp/README.md 为骨架系统讲解 Thrift C 运行库的构建安装、动态/静态链接、跨平台Linux 与 Windows配置、SSL 安全通信、UUID 类型支持以及版本演进中的破坏性变更。读完本文你将掌握libthrift与libthriftnb两个核心库的依赖关系与使用场景能够独立配置 C 项目的构建与链接并基于TSSLSocketFactory/AccessManager为 RPC 服务叠加 TLS 加密与证书校验同时了解 Thrift 从 C03 到 C11 迁移过程中的关键 API 变化。一、Thrift C 库的构建与安装1.1 基于 GNU 工具链的构建流程Thrift C 库使用 GNU 工具链autoconf/automake构建。顶层仓库的 README.md 提供了完整说明核心命令序列如下./bootstrap.sh ./configure (--with-boost/usr/local) make sudo make installbootstrap.sh生成 configure 脚本及相关构建文件./configure检测系统依赖并生成 Makefile可通过--with-boost指定 Boost 安装前缀Boost 仅用于单元测试见下文依赖一节make编译全部库与工具sudo make install将头文件、静态库与动态库安装到系统目录默认前缀/usr/local。如果希望跳过单元测试只构建运行库可以使用./configure --disable-tests一类的选项具体选项以./configure --help输出为准。1.2 两个核心库libthrift 与 libthriftnbThrift C 分为两个库见 lib/cpp/Makefile.am 与 lib/cpp/CMakeLists.txt库名内容额外依赖libthrift核心 Thrift 代码协议、传输、服务框架、并发原语等openssl、pthreads、librtlibthriftnb非阻塞nonblocking服务器基于 libevent 事件循环libevent在 libthrift 依赖之上普通阻塞式 RPCTSimpleServer、TThreadedServer、TThreadPoolServer只需要libthrift只有使用非阻塞服务器TNonblockingServer时才需要链接libthriftnb与 libevent。二、链接与部署配置2.1 Linux 下的链接构建安装后库默认安装到/usr/local/lib。请确保该路径在动态链接器搜索路径LDPATH中在/etc/ld.so.conf中加入/usr/local/lib执行/sbin/ldconfig刷新动态链接器缓存。链接时根据静态/动态链接方式及构建环境可能需要显式追加librt和/或libpthread使用libthriftnb时还需要追加libevent。典型链接命令形如g my_client.cpp -lthrift -lpthread -lrt -o my_client g my_nb_server.cpp -lthriftnb -lthrift -levent -lpthread -lrt -o my_nb_server2.2 Windows 下的构建与链接Windows 上可以使用 autoconf 或 CMake 构建系统。两者都能自动探测多数系统配置若需要指定第三方库位置可设置以下环境变量环境变量用途示例BOOST_ROOTBoost 安装根目录D:\boost_1_55_0OPENSSL_ROOT_DIROpenSSL 安装根目录D:\OpenSSL-Win32LIBEVENT_ROOT_DIRLibevent 安装根目录仅 libthriftnb 需要D:\libevent-2.0.21-stable更多细节见仓库根目录的3rdparty.user文件即文档所指/3rdparty.user位于 lib/cpp/3rdparty.props 同目录的第三方配置体系。Windows 下链接规则与 Linux 一致使用libthrift需链接 openssl、pthreads、librt使用libthriftnb需再链接 libevent。在 Visual Studio 项目属性中还必须设置预处理宏HAVE_CONFIG_H强制包含配置头文件windows/config.h。2.3 Windows 版本兼容性Thrift 库面向 Windows 7 及以上版本。Windows XP 与 Vista 的支持在 0.12.0 之后终止1.0.0 正式移除见下文破坏性变更。2.4 通过 vcpkg 安装也可以使用 vcpkg 依赖管理器快速获取 Thrift 的 Windows 二进制包git clone https://github.com/Microsoft/vcpkg.git cd vcpkg ./bootstrap-vcpkg.sh ./vcpkg integrate install ./vcpkg install thriftvcpkg 中的 thrift port 由 Microsoft 团队成员和社区贡献者维护Apache Thrift 项目不负责该 port 的版本同步若版本滞后请在 vcpkg 仓库提交 issue 或 pull request。2.5 Named PipesWindows 本地 IPCNamed Pipe 传输由TPipe和TPipeServer两个类实现源码见 lib/cpp/src/thrift/transport/TPipe.h 与 lib/cpp/src/thrift/transport/TPipe.cpp目前仅支持 Windows。非 Windows 平台没有实现 Named Pipe 传输——对本地 IPC 而言Unix Domain Socket 是更优选择且 *NIX 上的 named pipe 只支持 1:1 的客户端-服务器连接。三、Thrift/SSL为 RPC 叠加 TLS 加密3.1 适用范围与架构Thrift 的 SSL 支持仅适用于阻塞式socket I/O可搭配TSimpleServer、TThreadedServer、TThreadPoolServer使用非阻塞服务器不能使用 SSL 传输。SSL 功能由两个核心类承担声明见 lib/cpp/src/thrift/transport/TSSLSocket.hTSSLSocketFactory负责创建和管理TSSLSocket实例加载证书、私钥、信任链配置密码套件与认证策略TSSLSocket实际的 SSL socket实例永远由TSSLSocketFactory创建不应直接构造。默认TSSLSocketFactory上下文使用 OpenSSL 的 version-flexible TLS 方法并将TLS 1.2 设为最低协商协议版本。需要不同协议范围的应用可以提供自定义SSLContextFactorystd::functionstd::shared_ptrSSLContext()见 TSSLSocket.h在创建 socket 前调整 OpenSSL 上下文选项。链接 OpenSSL 兼容 TLS 库的应用还可以在外部创建并配置SSL_CTX用SSLContext包装后通过工厂传入——这适用于默认工厂方法无法表达的协议特定或双证书配置。工厂的关键配置接口包括factory-loadCertificate(path, PEM); // 加载服务器证书 factory-loadPrivateKey(path, PEM); // 加载私钥 factory-loadTrustedCertificates(path, capath); // 加载受信任 CA factory-ciphers(ALL:!ADH:!LOW:!EXP:!MD5:STRENGTH); // 密码套件 factory-authenticate(true); // 是否要求对端出示有效证书 factory-server(true); // 服务器模式 factory-access(manager); // 设置证书校验回调randomize()是虚方法默认实现只在 OpenSSL 库首次初始化时调用 OpenSSL 的RAND_poll()。PRNG 种子是应用安全的关键如果默认实现强度不够应覆写此方法。TSSLSocketFactory的生命周期必须长于它创建的每一个TSSLSocket。如果工厂先于 socket 析构OpenSSL 会被过早清理导致未定义行为旧版本会静默回退到不安全的 OpenSSL 多线程行为0.11.0 起改为断言或直接崩溃以暴露问题。只有当通过setManualOpenSSLInitialization()将 OpenSSL 的初始化和清理交给消费应用负责时这一要求才不再必要。3.2 AccessManager证书校验回调AccessManager见 TSSLSocket.h定义了一个回调接口用于在 SSL 握手完成后让应用决定是否继续与远端通信。它包含三个verify方法(a) Decision verify(const sockaddr_storage sa); (b) Decision verify(const string host, const char* name, int size); (c) Decision verify(const sockaddr_storage sa, const char* data, int size);这三个方法在验证流程的不同节点被调用。返回值Decision是枚举取值与语义如下源码注释见 TSSLSocket.h取值值语义ALLOW1允许继续通信验证流程立即停止DENY-1拒绝并断开连接验证流程立即停止SKIP0基于当前输入无法做出决定继续后续验证完整验证流程如下握手完成后首先调用(a)参数sa为远端对等方的 IP 地址加载远端对等方证书提取 SubjectAltName 扩展并逐项回调提取到DNS类型的 subjectAltName 时调用(b)提取到IP类型的 subjectAltName 时调用(c)若任一verify返回ALLOW或DENY验证流程停止若全部返回SKIP所有决策被忽略验证继续直到最后一项被检查完毕若最终仍无决策连接被终止。关于(b)中host的取值客户端侧 socket 取TSocket::getHost()服务器侧取TSocket::getPeerHost()。原因是客户端 socket 主动发起连接getHost()即远端主机名服务器侧远端主机名未知需通过getPeerHost()获取。无论哪种情况host都应当是远端主机名。注意若TSocket::getPeerHost()失败会以数字格式返回远端主机名。Common NameCN校验规则仅当证书完全没有 DNS subjectAltName 扩展时才检查 CN 字段。一旦存在 DNS subjectAltName它就代表证书身份依据 RFC 6125 6.4.4 与 RFC 9525 6.3未匹配的 DNS subjectAltName 是明确回答而非缺失——(b)返回SKIP不会把问题转交给 CN。而没有任何 DNS subjectAltName或只含 IP 条目的证书仍会走到 CN 检查通过(b)传给应用其中host为远端主机名data为 CN 值size为其长度。线程安全如果 AccessManager 被多个 SSL socket 共享它不应保存状态信息。3.3 SIGPIPE 信号处理通过网络连接运行 OpenSSL 的应用可能因 SIGPIPE 未忽略而崩溃当收到对端连接重置connection reset by peer异常时可能触发 SIGPIPE 信号若未处理该信号会直接杀死应用。因此在启用 SSL 的应用中应忽略 SIGPIPE。3.4 SSL 模式测试运行指南SSL 模式下的测试客户端与服务器需要test/目录下的三个证书文件文件名在源码中硬编码keys/server.crtkeys/server.keykeys/CA.pem上述文件在仓库 test/keys 目录中已存在含server.crt、server.key、CA.pem及客户端证书/密钥。运行测试前需确保keys/server.crt至少包含以下之一subjectAltName, DNS localhostsubjectAltName, IP 127.0.0.1common name, localhost在test/目录下执行./cpp/TestServer --ssl ./cpp/TestClient --ssl若客户端使用-h host指定主机则上述证书中的localhost必须替换为该主机名。真实使用示例可参考 test/cpp/src/TestServer.cpp其中展示了构造TSSLSocketFactory、调用loadCertificate/loadPrivateKey/ciphers(ALL:!ADH:!LOW:!EXP:!MD5:STRENGTH)以及将工厂包装进TSSLServerSocket的完整流程。客户端侧证书校验示例参见 test/cpp/src/TestClient.cpp。四、Thrift UUIDTUuid 类型4.1 TUuid 类设计uuid基础类型在 C 中由apache::thrift::TUuid类实现见 lib/cpp/src/thrift/TUuid.h。它是对内部16 字节缓冲区的强封装类data_为uint8_t data_[16]从字符串赋值时按网络字节序存储。TUuid支持从多种 UUID 字符串表示构造TUuid.hhhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh {hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh} hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh {hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh}如果字符串非法对象会被置为 nil空UUID可通过is_nil()判断。类还提供begin()/end()/size()/data()迭代器接口、operator/!、swap()以及自由函数to_string()与operator输出格式为标准的带连字符小写形式。4.2 与 boost::uuids::uuid 互操作TUuid内部基于boost::uuids::uuid实现底层数据结构一致因此可以与 boost UUID 类型无缝互操作。当项目已经使用 boost 时可定义预处理宏THRIFT_TUUID_SUPPORT_BOOST_UUID在包含 thrift 库的项目侧设置即可thrift 库本身无需重新编译定义该宏后启用从boost::uuids::uuid构造TUuid的构造函数该构造函数默认是隐式的定义THRIFT_TUUID_BOOST_CONSTRUCTOR_EXPLICIT可将其改为显式。相关单元测试位于 lib/cpp/test/TUuidTestBoost.cpp 与 lib/cpp/test/TUuidTestBoostNoDirective.cpp并在 lib/cpp/test/CMakeLists.txt 中登记。五、弃用与破坏性变更版本演进指南5.1 0.12.0 的弃用弃用对 C03/C98 的支持弃用对 Boost 作为运行时依赖的支持。5.2 1.0.0 的破坏性变更THRIFT-4720Monitor与TimerManager的 timeout 参数改为std::chrono::milliseconds涉及THRIFT_TIMESPEC与timeval的方法和函数被移除。平台支持放弃 Windows XP/Vista放弃 C03/C98如需该语言级别请使用 0.12.0。Boost 依赖变化Boost 不再作为运行时库依赖但仍是构建运行库与运行单元测试所需头文件thrift/stdcxx.h被移除相关代码直接使用 C11 概念。THRIFT-4730移除BoostThreadFactory、PosixThreadFactory、StdThreadFactory、PlatformThreadFactory统一使用基于 C11 的ThreadFactory原StdThreadFactory更名。THRIFT-4732CMake 选项WITH_SHARED_LIBS/WITH_STATIC_LIBS弃用不再并行构建静态与共享库通过标准 CMake 选项BUILD_SHARED_LIBS选择构建共享库或静态库。THRIFT-4735移除 Qt4 支持。THRIFT-4762TTransport::getOrigin()增加const限定符函数签名改变建议派生自TTransport的实现补充override说明符。5.3 0.11.0 的变更优先使用 C11 的memory类旧版本依赖boost/smart_ptr.hpp可通过定义宏FORCE_BOOST_SMART_PTR强制使用 boost 内存类THRIFT-2221。pthread 互斥锁实现的竞争剖析contention profiling代码默认关闭THRIFT-4151。TSSLSocketFactory生命周期短于其创建的TSSLSocket时行为由静默回退为断言/崩溃THRIFT-4164详见上文 SSL 章节。5.4 0.25.0 的破坏性变更HTTP 传输与 SSL 授权收紧HTTP 头名必须完整匹配HTTP 传输现在将冒号前的整个 token 作为头名读取。旧实现只比较对端已发送的字符数导致任何已知头名的前缀都会被接受如C: 5设置 content-length、T: chunked开启 chunked 解码、X: 1.2.3.4设置 originWebSocket 服务器端U:、C:、S:即可满足握手。依赖这些缩写的行为现在必须发送完整头名——其他 HTTP 实现本就要求如此。Content-Length 严格解析按 RFC 9110 8.6 的1*DIGIT解析。旧的atoi()无法报告负数、超出字段范围的数值或非数字文本例如Content-length: -1过去会变成 4294967295这三种情况现在都会抛出TTransportException。HTTP 消息体大小受限消息体受TConfiguration::maxMessageSize约束默认 100 MBchunked 体按各 chunk 之和计数。旧版本消息体大小不受限制声明长度或 chunk 数量由对端决定。需要交换更大消息体的客户端/服务器应像其他传输一样调高该配置。SSL 授权收紧CN 回退逻辑变更TSSLSocket::authorize()仅在证书没有 DNS subjectAltName 扩展时才检查 CN。旧版本只要没有 subjectAltName 条目返回 ALLOW 就回退检查 CN导致 subjectAltName 指向其他主机的证书还能凭匹配的 CN 获得第二次机会DefaultClientAccessManager::verify对不匹配的名字返回 SKIP使指向其他主机与不指向任何主机落入同一回退状态。影响与迁移现在对等方证书 subjectAltName 未覆盖目标主机、但 CN 覆盖、且此前被接受的场景会被拒绝并报authorize: cannot authorize peer。应重新签发证书把主机加入 subjectAltName——机器上其他 TLS 客户端早已如此要求。自定义 AccessManager 不受影响它仍通过(b)/(c)依次接收 subjectAltName 条目直到某项给出回答变化的只是其后是否还会被询问 CN。六、参考资源速查资源仓库相对路径C 库说明文档本文主体lib/cpp/README.mdSSL socket 实现与接口声明lib/cpp/src/thrift/transport/TSSLSocket.h、lib/cpp/src/thrift/transport/TSSLSocket.cppTUuid 实现lib/cpp/src/thrift/TUuid.hNamed Pipe 实现lib/cpp/src/thrift/transport/TPipe.h构建配置lib/cpp/Makefile.am、lib/cpp/CMakeLists.txtSSL 测试服务端/客户端test/cpp/src/TestServer.cpp、test/cpp/src/TestClient.cpp测试证书server.crt / server.key / CA.pemtest/keysTUuid 单元测试lib/cpp/test/TUuidTestBoost.cpp【免费下载链接】thriftApache Thrift项目地址: https://gitcode.com/GitHub_Trending/thr/thrift创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表