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

ARM Linux Qt使用JSON-RPC实现前后台分离

文章目录

  • 1、前言
  • 2、解决方案
    • 2.1、JSON-RPC
    • 2.2、Qt中应用JSON-RPC的框架图
    • 2.3、优点
    • 2.4、JSON-RPC 1.0 协议规范
  • 3、程序示例
    • 3.1、Linux C(只例举RPC Server相关程序)
    • 3.2、Qt程序(只例举RPC Client相关程序)
  • 4、编译程序
    • 4.1、交叉编译库文件
      • 4.1.1、编译libev库
      • 4.1.2、编译jsonrpc库
    • 4.2、编译应用程序
      • 4.2.1、编译RPC Server应用程序
      • 4.2.2、编译RPC Client应用程序
  • 5、测试
  • 6、总结

1、前言

在个人以往的嵌入式Linux Qt开发中,尽管想着将硬件操作和上层应用解耦,但所有的程序实现还是堆在了一个Qt项目工程里,没有实现真正的分离。例举几个痛点:

1、在获取bmp280温湿度传感器的数据时,一般需要open()设备节点,再获取数据。但类似open()等初始化的操作,没必要在Qt程序中实现。

2、在Qt程序中容易留有C语言的味道。

2、解决方案

2.1、JSON-RPC

使用JSON-RPC。JSON-RPC(JavaScript Object Notation Remote Procedure Call)是一种远程过程调用(RPC)协议,它使用JSON(JavaScript Object Notation)作为数据格式,并通过HTTP或其他传输协议(如TCP)在网络上发送请求和接收响应。

2.2、Qt中应用JSON-RPC的框架图

画板

使用Linux C部署RPC服务器,同时实现硬件HAL,提供接口函数。

Qt则作为RPC客户端,同时实现具体业务和UI。

RPC客户端与RPC服务器之间使用特定格式的JSON字符串作为数据进行传输。

2.3、优点

使用JSON-RPC后的优点:

1、无需在Qt程序中实现硬件HAL,尽最大可能解耦,毕竟Qt只是一个GUI框架。

2、开发过程中,可以在RPC Server创建伪数据,供Qt程序测试应用功能。

2.4、JSON-RPC 1.0 协议规范

客户端发送一个请求对象至服务端代表一个rpc调用, 一个请求对象包含下列成员:

{ "method" : "add", "params": [1, 2],"id": 1
}
  • <font style="background-color:#F4F5F5;">method</font>:指定了要调用的远程过程或方法的名称。
  • <font style="background-color:#F4F5F5;">params</font>:是一个数组,包含了调用方法时所需的参数。
  • <font style="background-color:#F4F5F5;">id</font>:是一个可选字段,用于标识请求。

当客户端发起一个rpc调用时,除通知之外,服务端都必须回复响应:

{ "result" : 3,  "error": null,    "id": 1
}
  • <font style="background-color:#F4F5F5;">result</font>:返回结果。
  • <font style="background-color:#F4F5F5;">error</font>:错误,没有错误返回null。
  • <font style="background-color:#F4F5F5;">id</font>:调用标识符,与传入时的一致。

如果是 JSON-RPC 2.0,请求和响应数据必须添加jsonrpc字段:

# 请求
{ "jsonrpc" : "2.0","method" : "add", "params": [1, 2],"id": 1
}# 响应
{ "jsonrpc" : "2.0","result" : 3,  "error": null,    "id": 1
}

3、程序示例

Linux C实现RPC Server。Qt程序实现RPC Client,同时向RPC Server发起远程调用,实现LED控制和dht11数据获取。

3.1、Linux C(只例举RPC Server相关程序)

/* rpc_server.c */#include <jsonrpc-c.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "rpc.h"
#include "led.h"
#include "dht11.h"static struct jrpc_server my_server;/* 参数: {"params" : [0|1]} */
cJSON * server_led_control(jrpc_context * ctx, cJSON * params, cJSON *id) {cJSON * status = cJSON_GetArrayItem(params,0);led_control(status->valueint);	return cJSON_CreateNumber(0);
}/* 参数: {"params" : null} */
cJSON * server_dht11_read(jrpc_context * ctx, cJSON * params, cJSON *id) {int array[2];array[0] = array[1] = 0;while (0 != dht11_read((char *)&array[0], (char *)&array[1]));return cJSON_CreateIntArray(array, 2);
}int RPC_Server_Init(void) 
{int err;err = jrpc_server_init(&my_server, PORT);if (err){printf("jrpc_server_init err : %d\n", err);}jrpc_register_procedure(&my_server, server_led_control, "led_control", NULL );jrpc_register_procedure(&my_server, server_dht11_read, "dht11_read", NULL );jrpc_server_run(&my_server);jrpc_server_destroy(&my_server);return 0;
}int main(int argc, char **argv)
{led_init();dht11_init();RPC_Server_Init();   return 0;
}

3.2、Qt程序(只例举RPC Client相关程序)

/* rpc_client.cpp */#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "cJSON.h"
#include "rpc.h"static int g_iSocketClient;int rpc_led_control(int on)
{char buf[100];int iLen;int ret = -1;int iSocketClient = g_iSocketClient;sprintf(buf, "{\"method\": \"led_control\", \"params\": [%d], \"id\": \"2\" }", on);iLen = send(iSocketClient, buf, strlen(buf), 0);if (iLen ==  strlen(buf)){while (1) {iLen = read(iSocketClient, buf, sizeof(buf));buf[iLen] = 0;if (iLen == 1 && (buf[0] == '\r' || buf[0] == '\n'))continue;elsebreak;} if (iLen > 0){cJSON *root = cJSON_Parse(buf);cJSON *result = cJSON_GetObjectItem(root, "result");ret = result->valueint;cJSON_Delete(root);return ret;}else{printf("read rpc reply err : %d\n", iLen);return -1;}}else{printf("send rpc request err : %d, %s\n", iLen, strerror(errno));return -1;}
}int rpc_dht11_read(char *humi, char *temp)
{char buf[300];int iLen;int iSocketClient = g_iSocketClient;sprintf(buf, "{\"method\": \"dht11_read\"," \"\"params\": [0], \"id\": \"2\" }");        iLen = send(iSocketClient, buf, strlen(buf), 0);if (iLen ==  strlen(buf)){while (1) {iLen = read(iSocketClient, buf, sizeof(buf));buf[iLen] = 0;if (iLen == 1 && (buf[0] == '\r' || buf[0] == '\n'))continue;elsebreak;} if (iLen > 0){cJSON *root = cJSON_Parse(buf);cJSON *result = cJSON_GetObjectItem(root, "result");if (result){cJSON * a = cJSON_GetArrayItem(result,0);cJSON * b = cJSON_GetArrayItem(result,1);*humi = a->valueint;*temp = b->valueint;cJSON_Delete(root);return 0;}else{cJSON_Delete(root);return -1;}}else{printf("read rpc reply err : %d\n", iLen);return -1;}}else{printf("send rpc request err : %d, %s\n", iLen, strerror(errno));return -1;}
}/* 连接RPC Server* 返回值: (>0)socket, (-1)失败*/
int RPC_Client_Init(void) 
{int iSocketClient;struct sockaddr_in tSocketServerAddr;int iRet;iSocketClient = socket(AF_INET, SOCK_STREAM, 0);tSocketServerAddr.sin_family      = AF_INET;tSocketServerAddr.sin_port        = htons(PORT);  /* host to net, short *///tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;inet_aton("127.0.0.1", &tSocketServerAddr.sin_addr);memset(tSocketServerAddr.sin_zero, 0, 8);iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));	if (-1 == iRet){printf("connect error!\n");return -1;}g_iSocketClient = iSocketClient;return iSocketClient;    
}

4、编译程序

4.1、交叉编译库文件

在RPC Server应用程序中,会引用一个头文件jsonrpc-c.h,使用该头文件需要提前交叉编译jsonrpc-c库。而jsonrpc-c库还依赖libev库。

4.1.1、编译libev库

# 1、解压库文件
tar xjf libev.tar.bz2
cd libev/# 2、配置
./configure --host=arm-buildroot-linux-gnueabihf --prefix=$PWD/tmp# 3、编译
make -j 16# 4、安装
make install# 5、查看安装后的目录
ls tmp/

4.1.2、编译jsonrpc库

# 1、安装编译jsonrpc库时需要用到的工具
sudo apt install libtool# 2、解压库文件
tar xjf jsonrpc-c.tar.bz2
cd jsonrpc-c/# 3、配置
autoreconf -i
./configure --host=arm-buildroot-linux-gnueabihf --prefix=$PWD/tmp CFLAGS="-I$PWD/../libev/tmp/include" LDFLAGS="-L$PWD/../libev/tmp/lib"# 4、编译
make -j 16# 5、安装
make install# 6、查看安装后的目录
ls tmp/

4.2、编译应用程序

4.2.1、编译RPC Server应用程序

Makefile参考:

TARGET=rpc_server
CC=arm-buildroot-linux-gnueabihf-gccTOP_DIR=$(shell pwd)/../
LIBEV_DIR=${TOP_DIR}/libev/tmp/
JSONRPC_DIR=${TOP_DIR}/jsonrpc-c/tmp/CFLAGS=-I${LIBEV_DIR}/include -I${JSONRPC_DIR}/include
LDFLAGS=${JSONRPC_DIR}/lib/libjsonrpcc.a  ${LIBEV_DIR}/lib/libev.a -lm -lpthreadc_files = cJSON.c rpc_server.c led.c dht11.c all:${CC} ${CFLAGS} -o ${TARGET} ${c_files} ${LDFLAGS}clean:rm -f *.o ${TARGET}

4.2.2、编译RPC Client应用程序

在Qt creator中正常编译。

5、测试

将编译出来的rpc_server和qt可执行程序拷贝到单板中,先运行rpc_server,等待约5s后,运行qt程序。

6、总结

韦东山视频教程:5-1_把程序拆分为前后台_哔哩哔哩_bilibili

相关文章:

ARM Linux Qt使用JSON-RPC实现前后台分离

文章目录 1、前言2、解决方案2.1、JSON-RPC2.2、Qt中应用JSON-RPC的框架图2.3、优点2.4、JSON-RPC 1.0 协议规范 3、程序示例3.1、Linux C&#xff08;只例举RPC Server相关程序&#xff09;3.2、Qt程序&#xff08;只例举RPC Client相关程序&#xff09; 4、编译程序4.1、交叉…...

【C++篇】C++11新特性总结1

目录 1&#xff0c;C11的发展历史 2&#xff0c;列表初始化 2.1C98传统的{} 2.2&#xff0c;C11中的{} 2.3&#xff0c;C11中的std::initializer_list 3&#xff0c;右值引用和移动语义 3.1&#xff0c;左值和右值 3.2&#xff0c;左值引用和右值引用 3.3&#xff0c;…...

【Nginx + Keepalived 实现高可用的负载均衡架构】

使用 Nginx Keepalived 可以实现高可用的负载均衡架构&#xff0c;确保在某个 Nginx 节点故障时&#xff0c;自动将流量转移到备用节点。以下是详细的实现步骤&#xff1a; 1. 架构概述 Nginx&#xff1a;作为负载均衡器&#xff0c;将流量分发到后端服务器。Keepalived&…...

使用外骨骼灵活远程控制协作机器人案例

外骨骼控制器采用可调节结构&#xff0c;简化了机器人编程&#xff0c;使协作机器人 FR3 的远程控制变得容易。 一、引言 在开发机器人手臂或双臂系统的应用程序时&#xff0c;经常会遇到以下挑战&#xff1a; 1. 使用拖动和示教进行定位的困难&#xff1a;拖动和示教功能通常…...

Centos Stream 10 根目录下的文件夹结构

/ ├── bin -> usr/bin ├── boot ├── dev ├── etc ├── home ├── lib -> usr/lib ├── lib64 -> usr/lib64 ├── lostfound ├── media ├── mnt ├── opt ├── proc ├── root ├── run ├── sbin -> usr/sbin ├── srv ├─…...

python连点器

要实现一个用于抖音点赞的鼠标连点工具&#xff0c;可以通过编程或现有软件实现。以下是两种常见方法&#xff08;但请注意&#xff1a;频繁自动化操作可能违反平台规则&#xff0c;需谨慎使用&#xff09;&#xff1a; 方法 1&#xff1a;使用现成工具&#xff08;如 AutoClic…...

STM32G474--Whetstone程序移植(单精度)笔记

1 准备基本工程代码 参考这篇笔记从我的仓库中选择合适的基本工程&#xff0c;进行程序移植。这里我用的是stm32g474的基本工程。 使用git clone一个指定文件或者目录 2 移植程序 2.1 修改Whetstone.c 主要修改原本变量定义的类型&#xff0c;以及函数接口全部更换为单精度…...

Spring Boot 3.4 中 MockMvcTester 的新特性解析

引言 在 Spring Boot 3.4 版本中&#xff0c;引入了一个全新的 MockMvcTester 类&#xff0c;使 MockMvc 测试可以直接支持 AssertJ 断言。本文将深入探讨这一新特性&#xff0c;分析它如何优化 MockMvc 测试并提升测试的可读性。 Spring MVC 示例 为了演示 MockMvcTester 的…...

java 读取sq3所有表数据到objectNode

1.实现效果&#xff1a;将sq3中所有表的所有字段读到objectNode 对象中&#xff0c;兼容后期表字段增删情况&#xff0c;数据组织形式如下图所示&#xff1a; 代码截图&#xff1a; 代码如下&#xff1a; package com.xxx.check.util;import java.sql.*; import java.util.Arr…...

网络计算机的五个组成部分

单个计算机是无法进行通信的。所以需要借助网络。 下面介绍一些在网络里常见的设备。 一、服务器 服务器是在网络环境中提供计算能力并运行软件应用程序的特定IT设备 它在网络中为其他客户机&#xff08;如个人计算机、智能手机、ATM机等终端设备&#xff09;提供计算或者应用…...

jakarta EE学习笔记-个人笔记

WebServlet注解&#xff1a;声明一个类为Servlet Target({ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) Documented public interface WebServlet {// 指定Servlet的影子String name() default ""; // 匹配地址映射(URL)String[] value() default {};// …...

vue3-响应式 toRefs

在Vue 3中&#xff0c;toRefs是一个非常有用的组合式API&#xff08;Composition API&#xff09;函数&#xff0c;它主要用于将响应式对象&#xff08;通常是由reactive创建的对象&#xff09;转换为单独的响应式引用对象。这样做的好处是可以将这些响应式引用解构出来&#x…...

学习threejs,使用Lensflare模拟镜头眩光

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.Lensflare 二、&…...

redis高级数据结构布隆过滤器

文章目录 背景什么是布隆过滤器Redis 中的布隆过滤器布隆过滤器使用注意事项实现原理空间占用估计 背景 我们在使用新闻客户端看新闻时&#xff0c;它会给我们不停地推荐新的内容&#xff0c;它每次推荐时要去重&#xff0c;去掉那些已经看过的内容。问题来了&#xff0c;新闻…...

mysql 5.7安装

基础环境&#xff1a;centos7.9 创建日志存放目录 mkdir -p /opt/supervisor/log安装相关工具 yum install -y perl net-tools numactl gcc python-devel配置yum源 sudo vim /etc/yum.repos.d/mysql-community.repo [mysql-connectors-community] nameMySQL Connectors Com…...

Golang:精通sync/atomic 包的Atomic 操作

在本指南中&#xff0c;我们将探索sync/atomic包的细节&#xff0c;展示如何编写更安全、更高效的并发代码。无论你是经验丰富的Gopher还是刚刚起步&#xff0c;你都会发现有价值的见解来提升Go编程技能。让我们一起开启原子运算的力量吧&#xff01; 理解Go中的原子操作 在快…...

微信小程序如何使用decimal计算金额

第三方库地址&#xff1a;GitHub - MikeMcl/decimal.js: An arbitrary-precision Decimal type for JavaScript 之前都是api接口走后端计算&#xff0c;偶尔发现这个库也不错&#xff0c;计算简单&#xff0c;目前发现比较准确 上代码 导入js import Decimal from ../../uti…...

最新Modular公司之MAX和Mojo作者 克里斯·拉特纳简介

Chris Lattner&#xff08;克里斯拉特纳&#xff09; 是一位著名的计算机科学家和软件工程师&#xff0c;以其在编程语言、编译器技术和软件开发工具领域的贡献而闻名。以下是关于他的详细介绍&#xff1a; 1. 主要成就 &#xff08;1&#xff09;LLVM 项目的创始人 Chris La…...

Redis数据库篇 -- Pipeline

一. 什么是Pipeline 在传统的请求-响应模式中&#xff0c;客户端与服务器之间的通信流程如下&#xff1a; 客户端发送一个命令到服务器。服务器接收命令并执行。服务器将执行结果返回给客户端。客户端接收结果后&#xff0c;发送下一个命令 在这种传统的模式下&#xff0c;…...

爬虫自动化(DrissionPage)

目录 ?一.介绍: 下载DrissionPage,还是我们熟悉的pip&#xff1a; 环境准备&#xff1a; ?二.基本代码&#xff1a; 它对于的导包和类使用&#xff1a; 窗口的设置&#xff1a; 和获取的页面的滑动&#xff1a; 3.进一步认识DrissionPage&#xff1a; 浏览器可以多开…...

常见string库中的函数(C语言超详细)

文章目录 strcspnstrcpystrncpystrcatstrncatstrcmpstrncmpstrchrstrrchrstrstrstrtokstrlenstrnlen strcspn 原型: size_t strcspn(const char *str1, const char *str2);功能&#xff1a; strcspn 会扫描 str1&#xff0c;并返回一个整数&#xff0c;表示 str1 中第一个匹配…...

单例模式几种实现

静态内部类holder实现&#xff08;推荐&#xff09; public class UniqueIdGenerator {public static final UniqueIdGenerator INSTANCE Holder.INSTANCE;// Private holder class for lazy initializationprivate static class Holder {static final UniqueIdGenerator INS…...

android中关于CheckBox自定义选中图片选中无效问题

在android xml 布局中&#xff0c;使用CheckBox控件设置选中背景图代码如下 <CheckBoxandroid:layout_width"wrap_content"android:layout_height"wrap_content"android:button"drawable/dfrd_common_selecotr_check"android:paddingStart&q…...

虚拟局域网之详解(Detailed Explanation of Virtual Local Area Network)

虚拟局域网之详解 VLAN (virtual localArea network)是一种虚拟局域网技术&#xff0c;它可以将一个物理局域网划分为多个逻辑上的虚拟局域网。 基于交换式以太网的虚拟局域网在交换式以太网中&#xff0c;利用VLAN技术&#xff0c;可以将由交换机连接成的物理网络划分成多个…...

双亲委派(JVM)

1.双亲委派 在 Java 中&#xff0c;双薪委派通常是指双亲委派模型&#xff0c;它是 Java 类加载器的一种工作模式&#xff0c;用于确保类加载的安全性和一致性。以下是其相关介绍&#xff1a; 定义与作用 定义&#xff1a;双亲委派模型要求除了顶层的启动类加载器外&#xf…...

第二十一章:考研的艰难抉择与放弃入学的转折

深秋时节&#xff0c;校园宛如被大自然精心雕琢的艺术殿堂。金黄的银杏叶在阳光的轻抚下&#xff0c;闪烁着细碎的光芒&#xff0c;微风拂过&#xff0c;叶片相互摩挲&#xff0c;发出沙沙的轻响&#xff0c;仿佛在低声诉说着岁月的故事。一片片银杏叶悠悠然飘落&#xff0c;宛…...

webpack配置之---output.chunkLoading

output.chunkLoading webpack.output.chunkLoading 配置项用于指定 Webpack 如何加载异步 chunk&#xff08;即按需加载的代码块&#xff09;。在现代 Webpack 版本中&#xff0c;异步代码分割成为了非常常见的功能&#xff0c;chunkLoading 配置项就用于控制 Webpack 加载这些…...

升级RAG应用程序与Redis向量库

Redis Vector Library (RedisVL) 简化AI应用开发 几个月前&#xff0c;Redis推出了Redis向量库&#xff08;RedisVL&#xff09;&#xff0c;以简化人工智能&#xff08;AI&#xff09;应用的开发。自那时起&#xff0c;我们引入了强大的新功能&#xff0c;支持大规模的语言模…...

【starrocks学习】之将starrocks表同步到hive

目录 方法 1&#xff1a;通过HDFS导出数据 1. 将StarRocks表数据导出到HDFS 2. 在Hive中创建外部表 3. 验证数据 方法 2&#xff1a;使用Apache Spark同步 1. 添加StarRocks和Hive的依赖 2. 使用Spark读取StarRocks数据并写入Hive 3. 验证数据 方法 3&#xff1a;通过…...

HTML应用指南:利用GET请求获取全国盒马门店位置信息

随着新零售业态的发展,门店位置信息的获取变得至关重要。作为新零售领域的先锋,盒马鲜生不仅在商业模式创新上持续领先,还积极构建广泛的门店网络,以支持其不断增长的用户群体。本篇文章,我们将继续探究GET请求的实际应用,我们使用Python的requests库通过GET请求,从盒马…...