当前位置: 首页 > news >正文

使用 C++ 和 gRPC 的常见陷阱及解决方案

文章目录

    • 1. 环境配置的陷阱
      • 1.1 依赖版本冲突或混淆
      • 1.2 gRPC 工具缺失
    • 2. 编译和链接的陷阱
      • 2.1 运行时库不匹配(/MT vs /MD)
      • 2.2 未解析的外部符号
    • 3. Protobuf 文件生成的陷阱
      • 3.1 工具版本不匹配
      • 3.2 生成文件运行时库不一致
    • 4. 运行时的陷阱
      • 4.1 缺少 DLL 文件
      • 4.2 服务初始化失败
    • 5. 调试和排查的陷阱
      • 5.1 日志不足
      • 5.2 VS2022 配置复杂
    • 最佳实践总结
    • 结语

gRPC 是一个高性能、跨平台的 RPC 框架,结合 C++ 使用时可以构建高效的服务端和客户端。然而,在实际开发中,从环境配置到编译、链接,再到运行时调试,开发者往往会遇到不少“坑”。本文总结了使用 C++ 和 gRPC 的常见问题,结合 vcpkg、CMake 和 Visual Studio 2022 的实践经验,提供详细的解决方案,帮助开发者少走弯路。

1. 环境配置的陷阱

1.1 依赖版本冲突或混淆

在使用 vcpkg 管理 gRPC 和 Protobuf 等依赖时,可能会同时安装动态库(如 x64 - windows)和静态库(如 x64 - windows - static),导致 CMake 或链接器混淆。

  • 表现
    • 链接错误,比如运行时库不匹配(/MT vs /MD)。
    • CMake 配置时意外使用了错误的三元组(triplet)。
  • 解决方法
    • 明确指定三元组并清理多余版本:
vcpkg remove protobuf:x64 - windows grpc:x64 - windows
vcpkg install protobuf:x64 - windows - static grpc:x64 - windows - static
- 在 CMake 中指定:
cmake .. -DVCPKG_TARGET_TRIPLET=x64 - windows - static -DCMAKE_TOOLCHAIN_FILE=C:\vcpkg\scripts\buildsystems\vcpkg.cmake
  • 建议
    始终检查已安装的依赖:
vcpkg list | findstr "protobuf grpc"

1.2 gRPC 工具缺失

vcpkg 安装的 grpc:x64 - windows - static 有时不提供 grpc_cpp_plugin.exe,这会导致无法生成 gRPC 的 C++ 代码。

  • 表现
    运行 protoc 时提示“找不到插件”或生成失败。
  • 解决方法
    • 手动编译 gRPC 获取插件:
git clone --branch v1.60.0 https://github.com/grpc/grpc
cd grpc
mkdir build && cd build
cmake .. -G "Visual Studio 17 2022" -A x64 -DgRPC_BUILD_GRPC_CPP_PLUGIN=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_CXX_FLAGS="/MT" -DCMAKE_C_FLAGS="/MT" -DCMAKE_TOOLCHAIN_FILE=C:\vcpkg\scripts\buildsystems\vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64 - windows - static
cmake --build . --config Release --target grpc_cpp_plugin
- 将生成的插件复制到 vcpkg:
copy Release\grpc_cpp_plugin.exe C:\vcpkg\installed\x64 - windows - static\tools\grpc\
  • 建议
    将插件路径加入环境变量,便于复用。

2. 编译和链接的陷阱

2.1 运行时库不匹配(/MT vs /MD)

C++ 项目中运行时库的不一致是常见问题,尤其在使用 gRPC 和 Protobuf 时。

  • 表现
    链接器报错:
error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MD_DynamicRelease”
  • 解决方法
    • 统一运行时库:
      • 安装静态版本依赖:
vcpkg install protobuf:x64 - windows - static grpc:x64 - windows - static
    - CMake 配置中强制使用 /MT:
-DCMAKE_CXX_FLAGS="/MT" -DCMAKE_C_FLAGS="/MT"
- 验证:

使用 dumpbin 检查:

dumpbin /directives <obj_file>
  • 建议
    在 CMakeLists.txt 中添加全局检查:
if(MSVC)foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE)string(REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")endforeach()
endif()

2.2 未解析的外部符号

链接时可能遇到缺少符号定义,尤其是与 Abseil 或标准库相关。

  • 表现
error LNK2001: 无法解析的外部符号 "std::basic_ostream<char>::write"
  • 解决方法
    • 确保链接所有必要库,例如 Abseil 的 absl_log_internal.lib:
target_link_libraries(<target> PRIVATE absl::log_internal)
- 检查运行时库一致性,混合使用可能导致符号未解析。
  • 建议
    详细检查链接器输入,确保无遗漏。

3. Protobuf 文件生成的陷阱

3.1 工具版本不匹配

使用不匹配的 protoc 和 grpc_cpp_plugin 会导致生成代码不兼容。

  • 表现
    编译时出现未定义行为,或运行时崩溃。
  • 解决方法
    使用 vcpkg 提供的工具:
C:\vcpkg\installed\x64 - windows - static\tools\protobuf\protoc.exe --proto_path=<path> --cpp_out=<path> --grpc_out=<path> --plugin=protoc - gen - grpc=C:\vcpkg\installed\x64 - windows - static\tools\grpc\grpc_cpp_plugin.exe <proto_file>.proto
  • 建议
    将工具版本与库版本对齐,避免手动下载。

3.2 生成文件运行时库不一致

生成的 .pb.cc 文件可能使用了 /MD,与项目配置不符。

  • 表现
    链接错误,如 RuntimeLibrary 不匹配。
  • 解决方法
    使用静态版本的 protoc 和插件重新生成,确保一致性。

4. 运行时的陷阱

4.1 缺少 DLL 文件

意外链接了动态库,可能导致运行时缺少 DLL。

  • 表现
    程序启动失败,提示缺少 MSVCRT.dll。
  • 解决方法
    • 检查依赖:
dumpbin /dependents <your_exe>.exe
- 确保全静态链接。
  • 建议
    优先使用静态构建,避免 DLL 依赖。

4.2 服务初始化失败

gRPC 服务端或客户端未正确初始化。

  • 表现
    FAILED_PRECONDITION 或 UNAVAILABLE 错误。
  • 解决方法
    检查端口和地址配置:
ServerBuilder builder;
builder.AddListeningPort("0.0.0.0:50051", grpc::InsecureServerCredentials());

5. 调试和排查的陷阱

5.1 日志不足

gRPC 默认日志不够详细,难以定位问题。

  • 解决方法
    启用详细日志:
set GRPC_VERBOSITY=DEBUG
set GRPC_TRACE=all
  • 建议
    在开发阶段保持日志开启。

5.2 VS2022 配置复杂

手动配置路径容易出错。

  • 解决方法
    使用 vcpkg 集成:
vcpkg integrate install

最佳实践总结

  • 统一静态链接:推荐使用 x64 - windows - static 三元组,避免 DLL 依赖。
  • 版本一致性:确保 protoc、grpc_cpp_plugin 和库版本匹配。
  • 脚本化构建:维护一个 build.bat,记录完整流程,例如:
mkdir build
cd build
cmake .. -G "Visual Studio 17 2022" -A x64 -DCMAKE_TOOLCHAIN_FILE=C:\vcpkg\scripts\buildsystems\vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64 - windows - static -DCMAKE_CXX_FLAGS="/MT" -DCMAKE_C_FLAGS="/MT"
cmake --build . --config Release
  • 定期更新:保持 vcpkg 和依赖库最新。

结语

使用 C++ 和 gRPC 开发虽然强大,但细节繁多。通过本文总结的陷阱和解决方案,您可以更高效地搭建开发环境、编译项目并调试问题。如果遇到具体错误,欢迎留言,我会提供针对性帮助!希望这篇博客对您的 gRPC 之旅有所助益。

相关文章:

使用 C++ 和 gRPC 的常见陷阱及解决方案

文章目录 1. 环境配置的陷阱1.1 依赖版本冲突或混淆1.2 gRPC 工具缺失 2. 编译和链接的陷阱2.1 运行时库不匹配&#xff08;/MT vs /MD&#xff09;2.2 未解析的外部符号 3. Protobuf 文件生成的陷阱3.1 工具版本不匹配3.2 生成文件运行时库不一致 4. 运行时的陷阱4.1 缺少 DLL…...

《深度学习实战》第2集:卷积神经网络(CNN)与图像分类

《深度学习实战》第2集&#xff1a;卷积神经网络&#xff08;CNN&#xff09;与图像分类 引言 卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09;是深度学习在计算机视觉领域的核心工具。从早期的 LeNet 到现代的 ResNet 和 Vision Transformer&#xf…...

AD(Altium Designer)器件封装——立创商城导出原理图和PCB完成器件封装操作指南

目录 1、立创商城下载原理图和PCB图 1.1 打开立创商城 1.2 寻找所需器件 1.3 确定所需芯片 1.4 打开原理图和PCB图 1.5 导出原理图 1.6 确定导出为AD文件 1.7 下载成功 1.8 导出PCB 1.9 确定导出为AD文件 1.10 原理图PCB下载成功 2、原理图和PCB图预处理 2.1 复制…...

DeepSeek掘金——调用DeepSeek API接口 实现智能数据挖掘与分析

调用DeepSeek API接口:实现智能数据挖掘与分析 在当今数据驱动的时代,企业和开发者越来越依赖高效的数据挖掘与分析工具来获取有价值的洞察。DeepSeek作为一款先进的智能数据挖掘平台,提供了强大的API接口,帮助用户轻松集成其功能到自己的应用中。本文将详细介绍如何调用D…...

LangChain系列:精通LangChain的合并文档链

LangChain的合并链旨在解决语言模型处理长文本时的上下文限制问题&#xff0c;包含Stuff、MapReduce、Refine和Rerank四种策略。Stuff链通过简单拼接文档块实现快速处理&#xff0c;适用于短文本但受限于模型token容量&#xff1b;MapReduce链采用分治思想&#xff0c;先独立处…...

rtcwake - Linux下定时唤醒计算机

rtcwake 是一个用于通过实时时钟&#xff08;RTC&#xff09;唤醒计算机的工具。它常用于在 Linux 系统中设置计算机在指定时间自动唤醒或关闭。以下是对命令 rtcwake -m off -s ${sleep_time} 的详细解析&#xff1a; 命令解析 bash复制 rtcwake -m off -s ${sleep_time} 1…...

MATLAB在投资组合优化中的应用:从基础理论到实践

引言 投资组合优化是现代金融理论中的核心问题之一&#xff0c;旨在通过合理配置资产&#xff0c;实现风险与收益的最佳平衡。MATLAB凭借其强大的数学计算能力和丰富的金融工具箱&#xff0c;成为投资组合优化的理想工具。本文将详细介绍如何使用MATLAB进行投资组合优化&#…...

什么是“可迭代”

在 Python 中&#xff0c;“可迭代”&#xff08;Iterable&#xff09;是一个非常重要的概念&#xff0c;它指的是任何可以被逐个访问其元素的对象。换句话说&#xff0c;如果一个对象支持迭代操作&#xff08;比如可以通过 for 循环逐个访问其元素&#xff09;&#xff0c;那么…...

Python天梯赛10分题-念数字、求整数段和、比较大小、计算阶乘和

007-念数字 输入一个整数&#xff0c;输出每个数字对应的拼音。当整数为负数时&#xff0c;先输出fu字。十个数字对应的拼音如下&#xff1a; 0: ling 1: yi 2: er 3: san 4: si 5: wu 6: liu 7: qi 8: ba 9: jiu输入格式&#xff1a; 输入在一行中给出一个整数&#xff0c;如&…...

C#初级教程(6)——函数:从基础到实践

一、函数的核心价值&#xff1a;简化与复用代码 以游戏开发项目为例&#xff0c;在游戏中&#xff0c;角色的移动、攻击等行为并非只在单一场景中出现。设想一下&#xff0c;若每次需要角色执行这些行为时&#xff0c;都要重新编写对应的代码&#xff0c;那将是何等繁琐且易错的…...

【Bluedroid】AVRCP 连接源码分析(一)

一、AVRCP协议简介 AVRCP(Audio/Video Remote Control Profile)是蓝牙协议栈中的一个重要部分,它定义了蓝牙设备之间的音视频传输控制的流程和特点。AVRCP使得用户可以通过一个蓝牙设备(如手机)远程控制另一个蓝牙设备(如蓝牙耳机或音箱)上的音视频播放,如播放、暂停、…...

编程考古-忘掉它,Delphi 8 for the Microsoft .NET Framework

忘掉它吧&#xff0c;作一篇记录&#xff01; 【圣何塞&#xff0c;加利福尼亚 – 2003年11月3日】在今日的Borland开发者大会上&#xff0c;Borland正式推出了Delphi 8 for Microsoft .NET Framework。这款新版本旨在为Delphi开发者提供一个无缝迁移路径&#xff0c;将现有的…...

Linux-Ansible基础模块

文章目录 模块Command模块Shell模块Script模块 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Linux专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年02月22日19点21分 模块 Command模块 Command模块实践 ansible 192.168.1.100 -m com…...

正则表达式–断言

原文地址&#xff1a;正则表达式–断言 – 无敌牛 欢迎参观我的个人博客&#xff1a;正则表达式特殊字符 – 无敌牛 断言assertions 1、(?...)&#xff1a;正向预查&#xff08;positive lookahead&#xff09;&#xff0c;表示某个字符串后面应该跟着什么。但这个字符串本身…...

Swiper插件的运用和学习

Swiper中文网-轮播图幻灯片js插件,H5页面前端开发 Swiper 是目前最流行的免费开源轮播组件之一&#xff0c;它功能强大、高度可定制且兼容性好&#xff0c;支持移动端手势操作和丰富的交互动画。 下载Swiper压缩包 轮播图演示页面。可以看见各种不同切换效果的轮播图 然后解压…...

标准I/O与文件I/O

一、概念 标准IO&#xff1a;标准IO是指程序与标准输入&#xff08;stdin&#xff09;、标准输出&#xff08;stdout&#xff09;和标准错误&#xff08;stderr&#xff09;之间的输入输出操作。通常用于与用户交互或输出调试信息。文件IO&#xff1a;文件IO是指程序与文件系统…...

JavaScript函数-函数的参数

在JavaScript编程语言中&#xff0c;函数是组织代码和实现复杂逻辑的基本单元。而函数参数则是这些功能的重要组成部分&#xff0c;它们允许我们将数据传递给函数&#xff0c;从而使得函数更加通用和灵活。本文将深入探讨JavaScript函数参数的各种特性及其最佳实践。 参数基础…...

Android TabLayout 实现随意控制item之间的间距

效果 红色标注是不同的间距。 实现方式 1、xml中定义 <com.google.android.material.tabs.TabLayoutandroid:id"id/tab_layout"android:layout_width"wrap_content"app:tabIndicatorColor"color/color_FF00B2E3"app:tabBackground"a…...

STM32的“Unique device ID“能否修改?

STM32F1系列的"Unique device ID"寄存器的地址为0x1FFFF7E8。 这个寄存器是只读的。 "Unique device ID"寄存器位于“System memory”中。“System memory”地址范围为“0x1FFF F000- 0x1FFF F7FF”。 所有STM32 MCU上都存在系统引导加载程序。顾名思义&a…...

STM32-温湿度上传OneNET项目

一、项目需求 使用 ESP8266 连接 OneNET 云平台&#xff0c;并通过 MQTT 协议上传 DHT11 获取的温湿度值。 二、项目框图 三、DHT11工作原理 参考于良许嵌入式手把手教你玩转DHT11&#xff08;原理驱动&#xff09; | 良许嵌入式 3.1 正常工作验证 #​ 上电后&#xff…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...