Linux应用开发实验班——JSON-RPC

目录

前言

1.是什么JSON-RPC

2.常用的JSON函数

1.创建JSON

2.根据名字获取JSON

3.获取JSON的值

4.删除JSON

3.如何进行远程调用

服务器

客户端

4.基于JSON-RPC进行硬件操作

课程链接


前言

学习的课程是百问网韦东山老师的课程,对更详细步骤感兴趣的同学,可以去学习视频课程。代码里的led和dht11的驱动都是学习韦老师的课程写的。

1.是什么JSON-RPC

JSON(JavaScript Object Notation,JavaScript 对象表示法)是基于 ECMAScript的
一个子集设计的,是一种开放标准的文件格式和数据交换格式,它易于人阅读和编写,同
时也易于机器解析和生成。JSON独立于语言设计,很多编程语言都支持JSON格式的数据交
换。JSON 是一种常用的数据格式,在电子数据交换中有多种用途,包括与服务器之间的
Web 应用程序的数据交换。其简洁和清晰的层次结构有效地提升了网络传输效率,使其成
为理想的数据交换语言。其文件通常使用扩展名.json。 

1.它的关键成员是“name:value”,value有多种形式。

{ "name": "John", "age": 30, "isStudent": false , "ptr": null }

2.上述例子中,有3种取值:"John"是字符串,30是整数,false是bool类型,null是 空值。 值的类型也可以是数组,比如:

{ "fruits": ["apple","banana", "cherry"] }

3.值的类型,还可以是一个JSON对象,比如:

{

"title":"JSON Example",

"author": { "name":"John Doe", "age": 35, "isVerified":true }, "tags":["json", "syntax", "example"],

"rating": 4.5, "isPublished":false,

"comments": null

}

2.常用的JSON函数

1.创建JSON

使用字符串创建一个cJSON结构体:

cJSON *json = cJSON_Parse(const char *value);
参数:
const char *value:这是唯一的参数,是一个指向要解析的 JSON 字符串的指针。
该字符串需要以 null 结尾。
返回值:
如果解析成功,函数会返回一个指向 cJSON 结构体的指针。
这个结构体表示了解析后的 JSON 数据,可以通过其他 cJSON 库提供的函数
(如 cJSON_GetObjectItem 等)来访问和操作其中的具体元素。
如果解析失败,函数会返回 NULL。导致解析失败的原因可能是 JSON 字符串的格式不正确、
存在非法字符或其他不符合 JSON 规范的情况。
注意事项:使用 cJSON_Parse 函数时,在调用之后一定要检查返回值是否为 NULL,
以确保解析成功。并且在使用完解析后的 cJSON 结构体后,
需要调用 cJSON_Delete 函数来释放内存,以避免内存泄漏。

2.根据名字获取JSON

cJSON *value = cJSON_GetObjectItem(const cJSON * const object, const char * const string);
参数:
const cJSON * const object:这是一个指向 cJSON结构体的常量指针,
代表待查找的 JSON 对象。该参数指定了在哪个 JSON 对象中进行成员查找。
const char * const string:这是一个指向字符串的常量指针,
代表要查找的成员的名称。该名称应与 JSON 对象中成员的键相对应。
返回值:
如果在给定的 JSON对象中找到了指定名称的成员,则返回一个指向该成员的 cJSON结构体的指针。
通过这个返回的指针,可以进一步访问该成员的具体信息,如值的类型、字符串值、数值等。
如果没有找到指定名称的成员,则返回 NULL。所以在使用该函数后,
通常需要检查返回值是否为 NULL,以确保能够正确地处理查找结果。

3.获取JSON的值

cJSON 结构体里存有值:valuestring、valueint、valuedouble,直接使用即可: 

示例:

4.删除JSON

cJSON_public(void) cJSON_Delete(cJSON *item);
参数:
cJSON *item:这是一个指向要释放的 cJSON 结构体的指针。
该指针指向的 cJSON 结构体可以是由 cJSON_Parse 函数解析 JSON 字符串后得到的根节点,
也可以是通过其他 cJSON 函数获取的子节点。
返回值:该函数没有明确的特定返回值类型定义,其主要作用是释放内存。
在调用该函数后,传入的 cJSON 结构体指针 item 及其所有相关的子结构体所占用的内存都会被释放。

3.如何进行远程调用

服务器

服务器的编写json-rpc为我们提供了初始化的API接口,直接调用就可以进行初始化。

1.初始化

函数原型:
int jrpc_server_init(struct jrpc_server *server, int port_number)。
参数:
struct jrpc_server *server:这是一个指向jrpc_server结构体的指针,
用于传递服务器的配置信息和状态。通过这个参数,函数可以对服务器进行初始化设置。
int port_number:指定服务器要监听的端口号。
返回值:
返回一个整数。具体的返回值含义可能取决于函数的具体实现逻辑。
通常情况下,可能返回一些状态码,比如成功初始化时返回 0,
出现错误时返回非零值以表示不同类型的错误情况。

2.在服务器上注册新的过程 

函数原型:
int jrpc_register_procedure(struct jrpc_server *server, jrpc_function function_pointer, char *name, void *data)。
参数:
struct jrpc_server *server:指向 JSON-RPC 服务器结构体的指针,
用于在该服务器上注册新的过程。
jrpc_function function_pointer:一个函数指针,指向要注册的过程所对应的函数。
char *name:要注册的过程的名称。
void *data:一个通用指针,可以传递与注册的过程相关的额外数据。
返回值:
返回一个整数。如果注册成功,返回 0;如果出现错误,
比如内存分配失败或字符串复制失败,返回 -1。

3.启动 JSON-RPC 服务器

函数原型:
void jrpc_server_run(struct jrpc_server *server)。
参数:
struct jrpc_server *server:指向 JSON-RPC 服务器结构体的指针。
这个结构体中包含了与服务器运行相关的信息,特别是其中的事件循环(通过server->loop访问)。
返回值:
无返回值(void)。

服务器会监听设置的端口,根据客户端发送来的消息选择要执行的过程,将数据以cjson结构体返回 

4.在服务器不再使用时进行清理和资源释放操作

函数原型:
void jrpc_server_destroy(struct jrpc_server *server)。
参数:
struct jrpc_server *server:指向 JSON-RPC 服务器结构体的指针。
这个结构体包含了服务器运行时的各种状态和资源信息。
返回值:
无返回值(void)。

客户端

客户端的编写,初始化和之前网络编程中的客户端编写是相同的。

初始化

这里我就直接放代码了,不懂可以查看直接网络编程那一篇的文章

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;}return iSocketClient;    
}

客户端选择要远程调用的过程

1.将消息构造成json类型的字符串,发送给给服务器

 sprintf(buf, "{\"method\": \"add\", \"params\": [%d,%d], \"id\": \"2\" }", a, b);iLen = send(iSocketClient, buf, strlen(buf), 0);

2.服务器会返回一个cjson结构体的结果,解析cjson结构体获取结果

iLen = read(iSocketClient, buf, sizeof(buf));
cJSON *root = cJSON_Parse(buf);
cJSON *result = cJSON_GetObjectItem(root, "result");
*sum = result->valueint;
cJSON_Delete(root);

4.基于JSON-RPC进行硬件操作

服务器端:
 

#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;
}

客户端:

#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"int rpc_led_control(int iSocketClient, int on)
{char buf[100];int iLen;int ret = -1;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(int iSocketClient, char *humi, char *temp)
{char buf[300];int iLen;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;}return iSocketClient;    
}static void print_usage(char *exec)
{printf("Usage:\n");printf("%s led <0|1>\n", exec);printf("%s dht11\n", exec);
}int main(int argc, char **argv)
{if (argc < 2){print_usage(argv[0]);return -1;}{        int sum;int fd = RPC_Client_Init();if (fd < 0){printf("RPC_Client_Init err : %d\n", fd);return -1;}if (argc == 3 && !strcmp(argv[1], "led")){int on = (int)strtoul(argv[2], NULL, 0);int err = rpc_led_control(fd, on);if (!err){printf("set led ok\n");}else{printf("rpc err : %d\n", err);}}else if (argc == 2 && !strcmp(argv[1], "dht11")){            char humi, temp;int err = rpc_dht11_read(fd, &humi, &temp);if (err){printf("rpc err : %d\n", err);}else{printf("dht11 humi = %d, temp = %d\n", humi, temp);}}            }return 0;
}

课程链接

Linux应用入门实验班icon-default.png?t=O83Ahttps://video.100ask.net/p/t_pc/course_pc_detail/video/v_66e049f8e4b023c061203dd5?product_id=p_66e0497de4b023c06c8ea08d&content_app_id=&type=6

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

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

相关文章

89个H5小游戏源码

下载地址&#xff1a;https://download.csdn.net/download/w2sft/89791650 亲测可用&#xff0c;代码完整&#xff0c;都是htmljs&#xff0c;保存到本地即可。 游戏截图&#xff1a;

3519嵌入式如何通过ssh 或者telnet连接嵌入式设备

需求 PC电脑连接嵌入式设备&#xff0c;已经能够连接串口&#xff0c;想要额外连接嵌入式设备&#xff0c;查看终端信息。 尝试了两种方法&#xff1a;1.通过SSH登录(失败) 2.通过telnet登录(成功) 问题描述 1.SSH登录 3519通过网线和串口线连接PC windows&#xff0c;并在…

JVM(HotSpot):虚拟机栈(JVM Stacks)之线程问题排查方法

文章目录 前言一、CPU占用过大二、程序运行很长时间没有结果三、总结 前言 本篇讲的排查都是基于Linux环境的。 一、CPU占用过大 这个一般是出现了死循环导致的。 1、先用top命令查看占用CPU的进程ID top2、再用ps命令查看对应的线程 就看一查看到对应的线程id ps H -eo …

hexo github部署,通过域名访问你的博客

hexo github部署&#xff0c;通过域名访问你的博客 hexo 常用命令hexo github 部署 在部署之前&#xff0c;了解一下hexo的常用命令 hexo 常用命令 hexo new "My New Post" # 新建文章 hexo n "My New Post"hexo generate # 生成静态文件 hexo ghexo serv…

2024必备中英互译利器全知道

现在英语目前还是学习最广泛的第二语言&#xff0c;所以很多资料都有英文的版本。如果外语不好&#xff0c;那中英互译翻译工具就能帮我们解决这个问题。今天我们一起来探讨下有哪些好用的翻译工具。 1.福昕在线翻译 链接直达>>https://fanyi.pdf365.cn/doc 这个工具…

无人机的避障的航迹规划详解!!!

一、无人机避障技术 视觉避障系统&#xff1a;通过安装在无人机上的摄像头捕捉周围环境的图像&#xff0c;利用计算机视觉技术对图像进行处理和分析&#xff0c;提取出障碍物的信息。这种方法直观、信息丰富&#xff0c;但在光线不足或变化多的情况下可能影响识别效果&#xf…

解决启动docker desktop报The network name cannot be found的问题

现象 deploying WSL2 distributions ensuring main distro is deployed: checking if main distro is up to date: checking main distro bootstrap version: getting main distro bootstrap version: open \wsl$\docker-desktop\etc\wsl_bootstrap_version: The network name…

【网络通信基础与实践番外一】多图预警之图解UDP和TCP前置知识

参考大佬的文章https://www.cnblogs.com/cxuanBlog/p/14059379.html 一、宏观架构中的传输层 在计算机中&#xff0c;任何一个可以交换信息的介质都可以称为端系统。计算机网络的运输层则负责把报文从一端运输到另一端&#xff0c;运输层实现了让两个互不相关的主机进行了逻辑…

【后端开发】JavaEE初阶—Theard类及常见方法—线程的操作(超详解)

前言&#xff1a; &#x1f31f;&#x1f31f;本期讲解多线程的知识哟~~~&#xff0c;希望能帮到屏幕前的你。 &#x1f308;上期博客在这里&#xff1a;【后端开发】JavaEE初阶—线程的理解和编程实现-CSDN博客 &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondl…

Android OpenGLES2.0开发(三):绘制一个三角形

我们总是对陌生人太客气&#xff0c;而对亲密的人太苛刻 上一篇文章中&#xff0c;我们已经将OpenGL ES环境搭建完成。接下来我们就可以开始我们的绘图之旅了。该篇我们讲解最基本图形三角形的绘制&#xff0c;这是一切绘制的基础。在OpenGL ES的世界里一切图形都可以由三角形拼…

OrangePi 烧录镜像步骤

理解&#xff1a;第一步&#xff1a;烧录镜像。第二步&#xff1a;建立编译环境&#xff08;一般是PC端的Linux虚拟机&#xff09;和板卡端的文件连接。因为要传文件&#xff0c;一般用挂载的方法。第三步&#xff1a;软件程序的编译与部署。 第一步&#xff1a;烧录镜像步骤 …

数据分析:Python语言网络图绘制

文章目录 介绍加载R包类别导入数据下载数据画图介绍 网络图是一种图形表示法,用于展示实体之间的关系。在不同的领域中,网络图有着不同的含义和用途:在生物学中,网络图可以用来表示生物分子之间的相互作用,如蛋白质相互作用网络。 加载R包 import pandas as pd import …

Xcode 16 上传AppStore遇到第三方库 bitcode 的问题

Xcode 16 上传AppStore遇到第三方库 bitcode 的问题 最近两天更新了Xcode 16&#xff0c;然后正好要发布新版本的App&#xff0c;打包Adhoc没问题&#xff0c;但是上传AppStoreConnect或者TestFlight就不行解决方案参考资料 最近两天更新了Xcode 16&#xff0c;然后正好要发布新…

PyQT开发总结

用PyQT开发了一个界面小程序&#xff0c;记录一下。 pyuic和pyrcc pyuic &#xff08;PYthon User Interface Compiler&#xff09;是一个命令行工具&#xff0c;用于将 Qt Designer 生成的 .ui 文件转换成 Python 代码。pyrcc 用于处理 Qt 资源文件&#xff08;如图片&#…

HTML+CSS学习笔记

目录 HTML 1.开发环境 2.创建HTML文件 3.HTML元素 3.1HTML文件结构 3.2HTML标签 3.3HTML属性​编辑​编辑 3.4HTML区块 3.4.1块元素 3.4.2行内元素 3.5HTML表单 CSS 1.CSS简介 2.CSS语法​编辑 3.CSS三种导入方式 内联样式 内部样式 外部样式 4.选择器​ 5.C…

低代码中实现数据映射的必要性与方案

在数字化转型的浪潮中&#xff0c;低代码平台因其快速开发和灵活性而受到越来越多企业的青睐。然而&#xff0c;随着业务需求的复杂化&#xff0c;单纯依赖低代码工具往往难以满足企业在数据处理和业务逻辑上的要求。数据映射作为连接不同数据源和业务逻辑的桥梁&#xff0c;显…

sheng的学习笔记-AI-时序差分学习

AI目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 强化学习&#xff1a;sheng的学习笔记-AI-强化学习&#xff08;Reinforcement Learning, RL&#xff09;-CSDN博客 蒙特卡罗强化学习&#xff1a; sheng的学习笔记-AI-蒙特卡罗强化学习-CSDN博客 什么是时序差分学习 时序…

解锁HTML的力量:从基础标签到完整网页构建

在整个学习编程技能的过程中&#xff0c;我们会始终基于编程的本质&#xff1a;输入-》函数处理-》输出 和编程语言的本质&#xff1a;语法糖、变量、基础函数&#xff0c;去理解各种编程技术和学习相关的技能。 今天开始学习编程的第一个技能点&#xff1a;HTML。正如编程的本…

国内可用ChatGPT-4中文镜像网站整理汇总【持续更新】

一、GPT中文镜像网站 ① yixiaai.com 支持GPT4、4o以及o1&#xff0c;支持MJ绘画 ② chat.lify.vip 支持通用全模型&#xff0c;支持文件读取、插件、绘画、AIPPT ③ AI Chat 支持GPT3.5/4&#xff0c;4o以及MJ绘画 二、模型知识 o1/o1-mini&#xff1a;最新的版本模型&am…

汇量科技大数据面试题及参考答案

如何在 SQL 中处理三个字段完全一样的去重?在 Scala 中又该如何实现? 在 SQL 中,可以使用多种方法来处理三个字段完全一样的去重。一种常见的方法是使用 DISTINCT 关键字结合多个字段来实现。例如,假设有表 table_name,包含字段 field1、field2 和 field3,可以使用以下 S…