菏泽网站制作,哪些网站可以做ppi,网站首页图片代码,自做购物网站多少钱protobuf、protobuf-c、protobuf-c-rpc在Linux#xff08;Ubuntu18.04#xff09;编译安装及交叉编译arm\aarch64版本 文章目录 protobuf、protobuf-c、protobuf-c-rpc在Linux#xff08;Ubuntu18.04#xff09;编译安装及交叉编译arm\aarch64版本一、前言二、protobuf、rp…protobuf、protobuf-c、protobuf-c-rpc在LinuxUbuntu18.04编译安装及交叉编译arm\aarch64版本 文章目录 protobuf、protobuf-c、protobuf-c-rpc在LinuxUbuntu18.04编译安装及交叉编译arm\aarch64版本一、前言二、protobuf、rpc、protobuf-c、protobuf-c-rpc介绍1、protobuf2、protobuf-c3、protobuf-c-rpc 三、Ubuntu18.04下编译安装及交叉编译1、前置准备-升级cmake2、protobuf编译安装及交叉编译2.1、正常编译、安装及错误解决方法2.2、交叉编译arm、aarch64版本及错误解决方法 3、protobuf-c编译安装及交叉编译3.1、正常编译安装3.2、交叉编译arm、aarch64版本 4、protobuf-c-rpc编译安装4.1、正常编译安装4.2、交叉编译arm、aarch64版本 四、接口调用示例及演示**1、创建proto文件test.proto****2、使用protoc-c编译proto文件生成服务和客户端代码文件****3、完成rpc客户端和服务端程序****4、编译并测试**5、关键点重要 五、最后 一、前言
如下介绍c语言的protobufrpc的开源库protobuf-c和protobuf-c-rpc其适合于嵌入式分布式场景利用protobuf协议的可扩展性比较方便进行协议兼容升级利用rpc接口的网络易用性不需要再从头到尾实现一遍socket通信、通信接口设计只需要实现C函数接口设计和开发以及利用proto设计好交互协议即可并且具备一定的跨编程语言交互特性每个具备联网能力的嵌入式设备都可作为rpc客户端和服务端可以快速进行嵌入式设备业务组网开发此外还有一些适合于stm32的protobuf库这里的库个人感觉更适合Linux和嵌入式Linux。
二、protobuf、rpc、protobuf-c、protobuf-c-rpc介绍
1、protobuf
Protocol Buffers简称ProtoBuf是一种开源跨平台的序列化数据结构的协议。其对于存储资料或在网络上进行通信的程序是很有用的。这个方法包含一个接口描述语言描述一些数据结构并提供程序工具根据这些描述产生代码这些代码将用来生成或解析代表这些数据结构的字节流。 起初接触protobuf是在go语言上当时go的grpc框架对我影响很大分布式场景的快速组网开发使得设备之间的交互扩展性极强增加新功能只需要简单修改protobuf交互协议文档新的服务就可以快速生成并开发高低版本的交互协议也很容易兼容其相较于xml和json使用简单更接近于代码层面的数据类型以及高效的性能和兼容性在分布式场景下应用越来越广。
2、protobuf-c
这是Google Protocol Buffers数据序列化格式的 C 实现。它包括一个实现 protobuf 编码和解码的纯 C 库以及一个基于原始 .protobuf 文件将 Protocol Buffer 文件转换为 C 描述符代码的代码生成器。之前是包含rpc实现的后面单独拆分出来了更将强调了 protobuf和rpc的单独性虽然protobuf和rpc以及grpc一起使用但protobuf可以像json、xml等序列化协议一样可以单独去使用。
3、protobuf-c-rpc
用于将protobuf和rpc结合使用的C语言实现库以此类推也有将json和rpc结合使用的库等等。
三、Ubuntu18.04下编译安装及交叉编译
1、前置准备-升级cmake
#卸载老版本
sudo apt-get autoremove cmake
#直接下载对应运行包https://cmake.org/files/
wget https://cmake.org/files/v3.20/cmake-3.20.0-linux-x86_64.tar.gz
#解压
tar zxvf cmake-3.20.0-linux-x86_64.tar.gz
#移动到常用安装目录
mv cmake-3.20.0-linux-x86_64 /opt/cmake-3.20.0
#创建软链接
ln -sf /opt/cmake-3.20.0/bin/cmake /usr/bin/cmake
#查看版本
cmake --version2、protobuf编译安装及交叉编译
GitHub仓库及下载地址 https://github.com/google/protobuf/releases https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.6.0.tar.gz
2.1、正常编译、安装及错误解决方法
该过程可以写入简单shell脚本一键执行
#下载源码
wget https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.6.0.tar.gz
#解压
tar zxvf v3.6.0.tar.gz
cd protobuf-3.6.0/
#安装autogen、autoconf、libtool、m4
apt-get install autogen
apt-get install autoconf
apt-get install libtool
apt-get install m4
#configure编译并设置安装路径
./autogen.sh
apt-get install g
./configure --prefix/usr/local/protobuf
#make编译时间稍微长一些
make
make install
#bin目录可以加入/etc/profile中之后就可以执行protoc命令将.proto文件生成代码了
export PATH/usr/local/protobuf/bin/:$PATH
source /etc/profile
#查看版本安装成功的话可以看到类似libprotoc 3.6.0
protoc --version
#PKG_CONFIG_PATH最好不要添加交叉编译时路径需要修改所以每次编译前执行一下该命令即可如果不需要交叉编译则可以添加避免找不到库
export PKG_CONFIG_PATH/usr/local/protobuf/lib/pkgconfig/错误1
# ./autogen.sh autoreconf -f -i -Wall,no-obsolete
./autogen.sh: 32: ./autogen.sh: autoreconf: not found解决安装autogen、autoconf
错误2
# ./autogen.sh autoreconf -f -i -Wall,no-obsolete
configure.ac:104: error: possibly undefined macro: AC_PROG_LIBTOOLIf this token and others are legitimate, please use m4_pattern_allow.See the Autoconf documentation.
autoreconf: /usr/bin/autoconf failed with exit status: 1解决安装libtool、m4
错误3
configure: error: in /home/plc/protobuf-3.6.0:
configure: error: C preprocessor /lib/cpp fails sanity check
See config.log for more details解决安装g
2.2、交叉编译arm、aarch64版本及错误解决方法
首先需要确认你自己的交叉编译工具链这主要取决于你的开发板这里以linaro的gnu工具链为例。 下载地址https://www.linaro.org/downloads/#gnu_and_llvm https://snapshots.linaro.org/gnu-toolchain/ 这里以目前最新的的14版本为例下载x86_64的arm和aarch的arm交叉编译工具链这取决于你的PC机的芯片。 这里注意不要下载版本太高的交叉编译工具链否则其依赖的libc版本太高的话会导致无法使用。
#wget直接下载会比较慢建议使用其它方法下载好传到虚拟机上
wget https://snapshots.linaro.org/gnu-toolchain/11.3-2022.06-1/aarch64-linux-gnu/gcc-linaro-11.3.1-2022.06-x86_64_aarch64-linux-gnu.tar.xz
wget https://snapshots.linaro.org/gnu-toolchain/11.3-2022.06-1/arm-linux-gnueabihf/gcc-linaro-11.3.1-2022.06-x86_64_arm-linux-gnueabihf.tar.xz
#解压
tar -xvf gcc-linaro-11.3.1-2022.06-x86_64_arm-linux-gnueabihf.tar.xz
tar -xvf gcc-linaro-11.3.1-2022.06-x86_64_aarch64-linux-gnu.tar.xz
#移动到常用位置
mv gcc-linaro-11.3.1-2022.06-x86_64_arm-linux-gnueabihf/ /usr/local/
mv gcc-linaro-11.3.1-2022.06-x86_64_aarch64-linux-gnu/ /usr/local/
#进行配置、编译、安装
CC/usr/local/gcc-linaro-11.3.1-2022.06-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc CXX/usr/local/gcc-linaro-11.3.1-2022.06-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g ./configure --prefix/usr/local/protobuf/arm --hostarm-linux
make clean make make install#aarch版本
CC/usr/local/gcc-linaro-11.3.1-2022.06-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc CXX/usr/local/gcc-linaro-11.3.1-2022.06-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g ./configure --prefix/usr/local/protobuf/aarch64 --hostaarch64-linux
make clean make make install错误1
#configure报错
checking for arm-linux-gcc... /usr/local/gcc-linaro-14.0.0-2023.06-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
checking whether the C compiler works... no#然后使用/usr/local/gcc-linaro-14.0.0-2023.06-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc发现libc版本不够
/lib/x86_64-linux-gnu/libc.so.6: version GLIBC_2.34 not found (required by /usr/local/gcc-linaro-14.0.0-2023.06-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
strings /lib/x86_64-linux-gnu/libc.so.6 |grep GLIBC_
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_2.13
GLIBC_2.14
GLIBC_2.15
GLIBC_2.16
GLIBC_2.17
GLIBC_2.18
GLIBC_2.22
GLIBC_2.23
GLIBC_2.24
GLIBC_2.25
GLIBC_2.26
GLIBC_2.27
GLIBC_PRIVATE解决方法下载低版本的交叉编译工具链或者升级glibc升级glibc会导致一系列系统问题不太建议。
3、protobuf-c编译安装及交叉编译
https://github.com/protobuf-c/protobuf-c https://github.com/protobuf-c/protobuf-c/releases/download/v1.4.1/protobuf-c-1.4.1.tar.gz 目前安装的1.4.1protobuf-c和protobuf-c-rpc已经分离成两个项目了。 这里注意正常编译时不需要配置disable-protoc用于生成bin、lib等内容而交叉编译时则可以不需要
3.1、正常编译安装
wget https://github.com/protobuf-c/protobuf-c/releases/download/v1.4.1/protobuf-c-1.4.1.tar.gz
tar zxvf protobuf-c-1.4.1.tar.gz
cd protobuf-c-1.4.1/
apt-get install pkg-config
#注意设置PKG_CONFIG_PATH否则会找不到protobuf的头文件等
export PKG_CONFIG_PATH/usr/local/protobuf/lib/pkgconfig/
./configure --prefix/usr/local/protobuf-c CFLAGS-fPIC
make clean make make install
export PATH/usr/local/protobuf-c/bin/:$PATH错误1
checking pkg-config is at least version 0.9.0... ./configure: line 12928: /usr/local/protobuf/lib/pkgconfig/: Is a directory
no
configure: error: pkg-config is required!解决方法安装pkg-config 如果确认你安装了pkg-config但还是一直报类似错误
configure: error: in /home/plc/protobuf-c-1.4.1:
configure: error: The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.Alternatively, you may set the environment variables protobuf_CFLAGS
and protobuf_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.To get pkg-config, see http://pkg-config.freedesktop.org/.
See config.log for more details那么可能是环境变量污染导致的export看一下PKG_CONFIG是不是被设置了如果是应该就是这个问题reboot重启一下设备就好了。
3.2、交叉编译arm、aarch64版本
#交叉编译时使用的bin下的程序还是Linux正常编译安装的只改变PKG_CONFIG_PATH链接对应的库和头文件
export PKG_CONFIG_PATH/usr/local/protobuf/arm/lib/pkgconfig/
#增加--disable-protoc只生成库和头文件
CC/usr/local/gcc-linaro-11.3.1-2022.06-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc ./configure --prefix/usr/local/protobuf-c/arm --hostarm-linux --disable-protoc CFLAGS-fPIC
make clean make make install#aarch64版本
CC/usr/local/gcc-linaro-11.3.1-2022.06-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc ./configure --prefix/usr/local/protobuf-c/aarch64 --hostaarch64-linux --disable-protoc CFLAGS-fPIC
make clean make make install错误1
/bin/bash: /usr/local/protobuf/arm/bin/protoc: cannot execute binary file: Exec format error
Makefile:2707: recipe for target protobuf-c/protobuf-c.pb.cc failed
make: *** [protobuf-c/protobuf-c.pb.cc] Error 126protoc该程序只是用于编译proto文件可以不需要交叉编译的protoc程序当然如果交叉编译环境要使用该程序则修改环境变量让其使用上面我们交叉编译protobuf时生成的protoc即可我这里直接disable方便一些。
4、protobuf-c-rpc编译安装
https://github.com/protobuf-c/protobuf-c-rpc
4.1、正常编译安装
git clone https://github.com/protobuf-c/protobuf-c-rpc.git
cd protobuf-c-rpc/
export PKG_CONFIG_PATH/usr/local/protobuf-c/lib/pkgconfig/
./autogen.sh
./configure --prefix/usr/local/protobuf-c-rpc CFLAGS-fPIC
export C_INCLUDE_PATH/usr/local/protobuf-c/include/
make clean make make install错误1
In file included from protobuf-c-rpc/protobuf-c-rpc-data-buffer.c:37:0:
protobuf-c-rpc/protobuf-c-rpc.h:32:10: fatal error: protobuf-c/protobuf-c.h: No such file or directory#include protobuf-c/protobuf-c.h^~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
Makefile:853: recipe for target protobuf-c-rpc/protobuf-c-rpc-data-buffer.lo failed解决方法设置环境变量C_INCLUDE_PATH指定头文件位置即可export C_INCLUDE_PATH/usr/local/protobuf-c/include/交叉编译时也是如此。
4.2、交叉编译arm、aarch64版本
#交叉编译时使用的bin下的程序还是Linux正常编译安装的只改变PKG_CONFIG_PATH链接对应的库和头文件
export PKG_CONFIG_PATH/usr/local/protobuf-c/arm/lib/pkgconfig/
CC/usr/local/gcc-linaro-11.3.1-2022.06-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc ./configure --prefix/usr/local/protobuf-c-rpc/arm --hostarm-linux CFLAGS-fPIC
export C_INCLUDE_PATH/usr/local/protobuf-c/arm/include
make clean make make install#aarch64版本
export PKG_CONFIG_PATH/usr/local/protobuf-c/arm/lib/pkgconfig/
CC/usr/local/gcc-linaro-11.3.1-2022.06-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc ./configure --prefix/usr/local/protobuf-c-rpc/aarch64 --hostaarch64-linux CFLAGS-fPIC
export C_INCLUDE_PATH/usr/local/protobuf-c/aarch64/include/
make clean make make install四、接口调用示例及演示
protobuf-c-rpc示例主要参考这里https://github.com/protobuf-c/protobuf-c-rpc/blob/master/t/test-rpc.c
域socket方式指定socket文件的路径即可比如“./socket”tcp方式服务端指定端口即可传递的name是字符串类型的端口如“8888”而客户端需要指定ip和端口如“127.0.0.1:8888”
这里以获取一个版本号为例写一个简单的rpc客户端服务端示例客户端去调用rpc接口获取版本信息
1、创建proto文件test.proto
syntax proto3;service Test {rpc GetVersion(VersionReq) returns (VersionRes) {}
}message VersionReq {string dev 1; //请求版本的设备标识
}message VersionRes {int32 err_code 1; //错误码为0是正常非0错误string message 2; //回复错误信息string version 3; //版本信息
}2、使用protoc-c编译proto文件生成服务和客户端代码文件
/usr/local/protobuf-c/bin/protoc-c --c_out. test.proto之后会生成test.pb-c.c和test.pb-c.h每次更新.proto文件重新生成一下即可。
3、完成rpc客户端和服务端程序
//server.c
#include stdio.h
#include pthread.h
#include unistd.h
#include string.h
#include stdlib.h
#include signal.h
#include protobuf-c/protobuf-c.h
#include protobuf-c/protobuf-c-rpc.h
#include test.pb-c.hstatic int g_run_flag 1;void signal_handler(int signum) {printf(Interrupt signal:%d received.\n, signum);g_run_flag 0;exit(signum);
}void this__get_version(Test_Service *service,const VersionReq *input,VersionRes_Closure closure,void *closure_data) {VersionRes result VERSION_RES__INIT;printf(ser get version\n);(void) service;if (input-dev NULL || !strlen(input-dev)){result.err_code -1;result.message dev info is null;closure(result, closure_data);return;}printf(req dev info:%s\n, input-dev);result.err_code 0;result.version 1;result.message success;closure (result, closure_data);
}static Test_Service test_service TEST__INIT(this__);void *pthread_rpc_server(void *arg) {ProtobufC_RPC_Server *rpc_server;ProtobufCService *local_service (ProtobufCService *)test_service;//域socket方式
// protobuf_c_rpc_server_new(PROTOBUF_C_RPC_ADDRESS_LOCAL, test.socket,
// local_service, NULL);//tcp方式protobuf_c_rpc_server_new(PROTOBUF_C_RPC_ADDRESS_TCP, 12345,local_service, NULL);while (g_run_flag) {protobuf_c_rpc_dispatch_run(protobuf_c_rpc_dispatch_default());sleep(1);}return NULL;
}int main(int argc, char *argv[]) {pthread_t pid_rpc_server;signal(SIGINT, signal_handler);printf(fun rpc run.\n);pthread_create(pid_rpc_server, NULL, (void *(*)(void *)) pthread_rpc_server, NULL);while (g_run_flag) {}
}
//client.c
#include stdio.h
#include pthread.h
#include unistd.h
#include string.h
#include stdlib.h
#include signal.h
#include protobuf-c/protobuf-c-rpc.h
#include test.pb-c.hstatic int g_run_flag 1;void signal_handler(int signum) {printf(Interrupt signal:%d received.\n, signum);g_run_flag 0;exit(signum);
}static void
handle_query_response(const VersionRes *result,void *closure_data) {if (result NULL)printf(Error processing request.\n);else if (result-message NULL)printf(Not found.\n);else {printf(resp message:%s\n, result-message);printf(resp ver:%s\n, result-version);}*(protobuf_c_boolean *) closure_data 1;
}static void
do_nothing (ProtobufCRPCDispatch *dispatch, void *unused)
{
}
static void
run_main_loop_without_blocking (ProtobufCRPCDispatch *dispatch)
{protobuf_c_rpc_dispatch_add_idle (dispatch, do_nothing, NULL);protobuf_c_rpc_dispatch_run (dispatch);
}int main(int argc, char *argv[]) {ProtobufCService *service;ProtobufC_RPC_Client *client;VersionRes resp VERSION_RES__INIT;signal(SIGINT, signal_handler);//域socket方式
// service protobuf_c_rpc_client_new(PROTOBUF_C_RPC_ADDRESS_LOCAL, test.socket, test__descriptor, NULL);//tcp方式service protobuf_c_rpc_client_new(PROTOBUF_C_RPC_ADDRESS_TCP, 127.0.0.1:12345, test__descriptor, NULL);if (service NULL) {printf(error creating client\n);exit(-1);}client (ProtobufC_RPC_Client *) service;//设置自动重连时间protobuf_c_rpc_client_set_autoreconnect_period(client, 3000);while (!protobuf_c_rpc_client_is_connected(client))protobuf_c_rpc_dispatch_run(protobuf_c_rpc_dispatch_default());fprintf(stderr, done.\n);while (g_run_flag) {protobuf_c_boolean is_done 0;VersionReq req VERSION_REQ__INIT;req.dev 12345678;run_main_loop_without_blocking (protobuf_c_rpc_dispatch_default ());test__get_version(service, req, handle_query_response, is_done);while (!is_done)protobuf_c_rpc_dispatch_run (protobuf_c_rpc_dispatch_default ());printf(req get version:\n);sleep(1);}
}
4、编译并测试
gcc server.c test.pb-c.c -o server -L /usr/local/protobuf-c/lib -L /usr/local/prtobuf-c-rpc/lib -lprotobuf-c-rpc -lprotobuf-c -lpthread
gcc client.c test.pb-c.c -o client -L /usr/local/protobuf-c/lib -L /usr/local/protobuf-c-rpc/lib -lprotobuf-c-rpc -lprotobuf-c -lpthread# ./server
fun rpc run.
ser get version
req dev info:12345678
ser get version
req dev info:12345678
ser get version
req dev info:12345678
ser get version
req dev info:12345678
ser get version
req dev info:12345678
ser get version
req dev info:12345678
...# ./client
done.
resp message:success
resp ver:1
req get version:
resp message:success
resp ver:1
req get version:
resp message:success
resp ver:1
req get version:
resp message:success
resp ver:1
req get version:
resp message:success
resp ver:1
req get version:
^CInterrupt signal:2 received.5、关键点重要
TCP方式时服务端protobuf_c_rpc_server_new的name只需要设置端口不需要绑定ip但是客户端这里的name为ip:port形式域socket方式时需要创建为name的文件用来做域socket通信客户端要调用的接口方法是固定的但是服务端需要重写函数指针对应的函数并且函数名是初始化service时传入的前缀名称加上方法名称
//比如这里初始化时设置前缀为this__那么这里重写的回调函数名称就是this_get_version这个函数指针被注册到服务之中了等到客户端请求时就会调用该注册的函数
static Test_Service test_service TEST__INIT(this__);
void this__get_version(Test_Service *service,const VersionReq *input,VersionRes_Closure closure,void *closure_data) {
...
}五、最后
protobuf这种序列化方式的数据交互方式虽然相较json等上手门槛稍微高一些但是相较于json、xml还是有不少优势的比较推荐。