protobuf、protobuf-c、protobuf-c-rpc在Linux(Ubuntu18.04)编译安装及交叉编译arm\aarch64版本

protobuf、protobuf-c、protobuf-c-rpc在Linux(Ubuntu18.04)编译安装及交叉编译arm\aarch64版本

文章目录

  • protobuf、protobuf-c、protobuf-c-rpc在Linux(Ubuntu18.04)编译安装及交叉编译arm\aarch64版本
    • 一、前言
    • 二、protobuf、rpc、protobuf-c、protobuf-c-rpc介绍
      • 1、protobuf
      • 2、protobuf-c
      • 3、protobuf-c-rpc
    • 三、Ubuntu18.04下编译安装及交叉编译
      • 1、前置准备-升级cmake
      • 2、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语言的protobuf+rpc的开源库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 --version

2、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 --host=arm-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 --host=aarch64-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.1,protobuf-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 --host=arm-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 --host=aarch64-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 126

protoc该程序只是用于编译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 --host=arm-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 --host=aarch64-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.h"static 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.h"static 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还是有不少优势的,比较推荐。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/218835.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity 置顶OpenFileDialog文件选择框

置顶文件选择框 &#x1f32d;处理前&#x1f959;处理后 &#x1f32d;处理前 &#x1f959;处理后 解决方案

【TI毫米波雷达入门-10】TI毫米波速度检测思路

知识回顾 FMCW chirp 雷达收发流程 中频信号 傅里叶变换 多目标检测 距离分辨率 最大距离 公式总结 FMCW数据处理流程示例 两个维度看图表 从range维度&#xff0c;水平方向上&#xff0c;反映每个chirp 发出的FMCW被接收天线检测到&#xff0c;2个点的目标&#xff0c;对应两个…

滑动窗口如人生,回顾往事不复还———力扣刷题

第一题&#xff1a;长度最小的子数组 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 思路&#xff1a; 第一想法肯定时暴力枚举&#xff0c;枚举数组任何一个元素&#xff0c;把他当起始位置&#xff0c;然后从起始位置找最短区间&#xff0c;使得…

uniapp原生插件之安卓app添加到其他应用打开原生插件

插件介绍 安卓app添加到其他应用打开原生插件&#xff0c;接收分享的文本和文件&#xff0c;支持获取和清空剪切板内容 插件地址 安卓app添加到其他应用打开原生插件&#xff0c;支持获取剪切板内容 - DCloud 插件市场 超级福利 uniapp 插件购买超级福利 详细使用文档 u…

Nyquist Theorem(取样定理)

取样定理&#xff0c;又称为奈奎斯特定理&#xff08;Nyquist Theorem&#xff09;&#xff0c;是信号处理领域中一项至关重要的基本原理。它规定了对于连续时间信号&#xff0c;为了能够完全准确地还原出原始信号&#xff0c;即使是在离散时间下进行采样和再构建&#xff0c;都…

Mybatis-plus更新多张表,保证事务安全的情况下使用异步多线程实现(待验证)

Mybatis-plus更新多张表,保证事务安全的情况下使用异步多线程实现(待验证) 文章目录 Mybatis-plus更新多张表,保证事务安全的情况下使用异步多线程实现(待验证)方案一:方案二:方案三:使用mybatis-plus更新数据库的五张不同的表,开启五个线程&#xff0c;每个线程负责更新一张表…

【JUC】二十七、synchronized锁升级之无锁

文章目录 1、背景2、Monitor、Java对象、线程如何关联起来的&#xff1f;3、synchronized锁升级4、锁升级之无锁 关于synchronized同步&#xff0c;能用无锁结构就不要用锁&#xff1b;能锁块&#xff0c;就不要锁整个方法&#xff1b;能用对象锁&#xff0c;就不要用类锁。 用…

【Py/Java/C++三种语言OD2023C卷真题】20天拿下华为OD笔试【单调栈】2023C-找最小数【欧弟算法】全网注释最详细分类最全的华为OD真题题解

文章目录 题目描述与示例题目描述输入输出示例一输入输出说明 示例二输入输出 示例三输入输出 解题思路代码PythonJavaC时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 题目描述与示例 题目描述 给一个正整数 NUM1&#xff0c;计算出新正整数 NUM2。NUM2 为 NUM1 中移…

LDO和DCDC的区别

目录标题 前言什么是LDO&#xff1f;什么是DCDC&#xff1f;LDO和DCDC的主要区别 前言 对于初学者来说&#xff0c;最常见到的LDO就是最小系统板上自带的低压差线性稳压器&#xff0c;其用于将USB输入的5V电压转化为3.3V供给单片机。最长用到DCDC器件&#xff0c;就是在做小车…

python算法例18 滑动窗口的最大值

1. 问题描述 给定一个可能包含重复整数的数组和一个大小为k的滑动窗口&#xff0c;从左到右在数组中滑动这个窗口&#xff0c;找到数组中每个窗口内的最大值。 2. 问题示例 给出数组[1&#xff0c;2&#xff0c;7&#xff0c;7&#xff0c;8]&#xff0c;滑动窗口大小为k3&a…

Redis - 主从集群下的主从复制原理

主从复制过程 数据同步演变过程 sync 同步 Redis 2.8 版本之前&#xff0c;首次通信成功后&#xff0c; slave 会向 master 发送 sync 数据同步请求。然后 master 就会将其所有数据全部发送给 slave &#xff0c;由 slave 保存到其本地的持久化文件中。这个过 程…

推荐10款值得信赖的办公软件app,为你的工作提效!

在如今的工作环境中&#xff0c;人们需要经常使用各种办公软件来提高工作效率&#xff0c;同时也帮助我们更好地管理自己的工作和生活。以下是推荐10款值得信赖的办公软件app&#xff1a; 1、Evernote – Evernote是一款非常流行的笔记应用程序&#xff0c;适用于多个平台。它…

conda的安装及使用 以pycharm 为例

下载 https://docs.conda.io/en/latest/miniconda.html 下载 window版本 74M且下着吧。 安装 一路next或agree &#xff0c;不同意人家也不会按装 。重要的是安装目录 让andconda当老大 pycharm的使用 创建项目时如下图选择 成功后进入项目的Terminal则如下图表示成功

快速二维相位解包算法基于按照非连续路径进行可靠性排序

Miguel Arevallilo Herra ez, David R. Burton, Michael J. Lalor, and Munther A. Gdeisat 摘要&#xff1a; 据我们所知&#xff0c;我们描述了一种新的相位展开技术。已经提出了几种基于首先展开最可靠像素的算法。这些仅限于连续路径&#xff0c;并且在定义起始像素时会遇…

目前进度记录

目前已经把之前记录的方法都实现了&#xff0c;目前的主函数可以写的更简单比如 int main(int argc, char* argv[]) {KernelClass::create_kernel();MPI_Init(&argc, &argv);kernel().mpi_manager.init_mpi(argc, argv);//创建种群int group1 kernel().conn_manger.c…

山西教资面试---结构化真题125道

文章目录 第一章 教育教学类单元1&#xff1a;应急应变&#xff08;1-21&#xff09;单元2&#xff1a;日常管理&#xff08;22-54&#xff09;单元3&#xff1a;人际关系&#xff08;55-66&#xff09; 第二章 综合分析类单元4&#xff1a;社会现象&#xff08;66-112&#xf…

Python特征工程神器:Feature Engine库详解与实战

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 特征工程是机器学习中至关重要的一环&#xff0c;而Feature Engine库作为Python中的强大特征工程工具&#xff0c;提供了丰富的功能和灵活的操作。本文将深入探讨Feature Engine的各种特性&#xff0c;包括缺失值…

torch.bmm

在PyTorch中&#xff0c;torch.bmm函数用于执行批量矩阵相乘&#xff08;Batch Matrix Multiplication&#xff09;。它接受三维张量作为输入&#xff0c;并执行批量矩阵相乘的操作。 具体来说&#xff0c;假设我们有两个输入张量A和B&#xff0c;它们的维度分别为 &#xff…

单片机的低功耗模式介绍

文章目录 简介一、功耗来源说明1.1、芯片工作模式1.2、静态损耗1.3、I/O额外损耗1.4、动态损耗 二、功耗如何测量三、降低功耗有什么方法3.1、选取合适的芯片工作模式3.2、降低工作频率3.3、关闭不需要使用的外设3.4、 降低静态电流损耗3.5、 周期采集供电3.6、 设置IO口状态 四…

HNU数据库大作业-世界杯比赛系统

前言 之前做的那个版本bug较多&#xff0c;后进行了大量优化。 此项目是一个前后端分离的项目&#xff0c;前端主要使用htmlcssjs搭建&#xff0c;使用的是layui框架 后端使用php语言&#xff0c;仅实现了简单的查询数据库功能&#xff0c;无法实现多并发查询等复杂情况 数…